[Rails] 部署
不管是哪個服務,都需要存取本地端的
- mac 建立並查看 ssh-key
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub
linux 指令
在部署中,會有一些比較常見的相關指令,這邊紀錄常用的指令紀錄
- 複製資料夾
cp -r <路徑A> <路徑B>
- 刪除檔案
rm -r <檔案>
- 查看使用指令的歷史
history
history | grep rails # 找出關鍵字為rails的指令
- 回到家目錄
cd ~
- 查看檔案 + 行數
cat /etc/nginx/nginx.conf # 查看檔案
cat -n /etc/nginx/nginx.conf # 查看檔案+行數
- 左移或右移游標
Ctrl + 左箭頭
Ctrl + 右箭頭
- 如何找關鍵字
grep -in -A 5 redirect /etc/nginx/sites-available/tungrp
grep -in -B 5 redirect /etc/nginx/sites-available/tungrp
grep -win -B 5 redirect /etc/nginx/sites-available/tungrp
其中w
代表獨立文字、i
代表不管大小寫(本身)、n
代表行數、A 5
代表內容以下五行、B 5
代表內容以上五行。
- 在 rails 正式站環境執行 console
RAILS_ENV=production bundle exec rails c
如果想要使用預設環境為正式站的話,可以在~/.bashrc
將環境變數 RAILS_ENV=production
寫進去即可。
- 調整時區
- chown
要知道chown,就要知道 Linux dwrx-
各代表什麼意思
- 環境變數使用
nano 指令
- 剪下該行(可以當作刪除):Ctrl+k
- 貼上該行(可以當作取消刪除):Ctrl+U
- 游標瞬間移動往上:Ctrl + Y
- 游標瞬間移動往下:Ctrl + V
- 存檔:
Ctrl+X
/Y
/Enter
Rails
- 若取不到DATABASE_URL,則預設 localhost
default: &default
host: <%= ENV.fetch("DATABASE_URL") { 'localhost' } %>
GCP interface
- 釘選常用:我會將常用的選單釘選上去
Web Server
常見網頁伺服器一共2種,一種是nginx,另外一種是apache。目前我只操作過nginx,還沒有操作過nginx。
- nginx
- apache
App Server
- passenger
- puma
- WEBrick
Nginx
Nginx 是一個反向代理伺服器,就像PM,接收所有客戶的需求後,分配給工程師處理。這樣的好處可以保護後方的 Web Server 被攻擊。同時,還可以提供負載平衡 (Load Balance)、快取以及 HTTPS 憑證等功能。
使用 Nginx 可以隱藏伺服器真實 IP、均衡負載、提供安全保障等等
以及與 Nginx 相關的概念
- 反向代理 Reverse Proxy
- 負載平衡 Load Balance
GCP
GCP 一共有三種方式可以部署
- App Engine:類似 Heroku 將程式碼託管
- Compute Engine:使用虛擬機
- Google Kubernetes Engine (GKE):使用容器
Semaphore 這篇是我覺得很好的文章(Rails + Unicorn)。使用容器的好處是,同樣的安裝不用做兩次,除此之外不會因為環境的不同遇到不同的問題。不過實際上會遇到其他什麼問題還沒有經驗
IAM
每個專案都有個IAM,若要使用別人GCP(或AWS),只要使用對方的帳號並開啟IAM,即可在不知道對方帳密的情況下去以擁有者(owner)的身份進行部署
踏出第一步
點入虛擬機的編輯,加入SSH金鑰,並且在最後加入使用者名稱,通常部署時,虛擬機的使用者名稱為 deploy。
google 建立使用者的方式特別友善,其他服務可能會需要先建立一個 super user ,再透過 super user 建立使用者 deploy。
使用GCP,我們只有在電腦輸入以下指令後便可以取得對gcp的控制權
ssh-keygen -t rsacat ~/.ssh/id_rsa.pub
可以透過編輯加入 SSH 就不用使用密碼登入,安全性跟流程都會節省許多。
安裝必要
進入虛擬機後安裝必要套件
# Adding Node.js repositorycurl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -# Adding Yarn repositorycurl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.listsudo add-apt-repository ppa:chris-lea/redis-server# Refresh our packages list with the new repositoriessudo apt-get update# Install our dependencies for compiiling Ruby along with Node.js and Yarnsudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev dirmngr gnupg apt-transport-https ca-certificates redis-server redis-tools nodejs yarn
安裝 rbenv
git clone https://github.com/rbenv/rbenv.git ~/.rbenvecho 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrcecho 'eval "$(rbenv init -)"' >> ~/.bashrcgit clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-buildecho 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrcgit clone https://github.com/rbenv/rbenv-vars.git ~/.rbenv/plugins/rbenv-varsexec $SHELLrbenv install 3.0.0rbenv global 3.0.0ruby -v# ruby 3.0.0
安裝 rails 圖片處理
sudo apt-get install imagemagick
sudo apt-get install libmagickwand-dev
查看目前安裝套件
apt list --installed
Rails 部署結構
在var/www底下的樹狀結構,其中 release 為近期5次的部署,current 連到最近部署的超連結
Cloud SQL
設定內網進去,所以進去方式為使用 mysql 語法建立資料庫(取代rails db:create),db:migrate 的部分由部署的時候 capistrano 幫我們做
mysql -uroot -p<密碼> -h<內網>
Google Cloud Storage
剛開始不太知道在建立專案的時候所拿到的 json 檔案哪來的
這邊描述如何取得使用google cloud storage json 檔案。
設定IP
首先我們先進去vpc網路,新增一個 ip 位置
負載平衡 (Load Balance)
進入vpc網路,點選負載平衡
接著新增一個負載平衡器
點選 https 負載平衡器
啟動完設定會看到以下畫面
如果沒有後端服務,請先建立後端服務
不過我同事在這邊遇到問題,沒有辦法找到執行個體群組
可以在 compute engine 點進去執行個體群組設定使用者
若要將已存在的vm分派執行個體群組的話,先新增非代管執行個體群組後,選定正確的地址便可以選到vm
設定完長這樣
以下為目前設定過的專案設定值,分為後端設定、主機與路徑規則、前端設定
- 如何進去憑證:進入負載平衡頁面,點選
進階選單
後點選憑證
頁籤
在憑證頁籤內可以建立新的SSL憑證
建立初始,網域狀態會顯示每一個申請的網域,以及附上狀態圖標,而下面的灰、橘、綠各代表一種狀態,而除此之外還有紅色圖標的狀態為永久失敗,當遇上永久失敗就只能刪掉重新創建。
上圖的狀態 PROVISIONING
代表還在認證中,認證完後狀態顯示 ACTIVE
。
上面的連結講述了狀態及網域狀態,可以當作參考。
- 設定負載平衡:
使用 google 驗證流程非常簡單,然而當時遇到一個狀況是
Google Cloud Storage
進去 iam,進入服務項目以後
常遇錯誤
- 權限問題:
- 虛擬機沒有安裝 yarn:
➡️ 沒有裝yarn會造成建制專案上出現問題,而另外Ubuntu本身就有 yarn 套件,所以要先把 yarn 刪除,來安裝 node package yarn
- npm / node 版本過舊:
- 遇到的錯誤:Net::SSH::HostKeyMismatch
➡️ 首先先在本地電腦啟用產生公鑰/私鑰:ssh-keygen -t rsa
➡️ 再來跑指令產出公鑰:cat ~/.ssh/id_rsa.pub
➡️ 發現輸出 ~/.ssh/id_rsa
時
- 遇到錯誤:Error: Net::SSH::AuthenticationFailed
Net::SSH::AuthenticationFailed: Authentication failed for user Christopher@12.23.34.45
- 遇到錯誤:SSHKit::Runner::ExecuteError ➡️
ssh-add
- 設定固有 ip:只要實作下列兩個步驟即可
Rails 部署
Github
在 github 上面必須設定本地的 ssh 公鑰,部署時在本地端下cap <環境名稱> deploy
指令,指令會透過 ssh 的方式認證 github,將專案的程式碼拉下來跑部署流程。
cap <環境名稱> deploy
cap test deploy # 測試站部署
cap staging deploy # staging 部署
cap production deploy # 正式站部署
Fun Fact
- Rails 在預載入動作時編譯的css, javascript 利用 rsync 同步到正式站
- 測試站部署的時間,與正式站不同步的原因:部署要從測試站下指令。
其他
- 遠端電腦安裝rvm,將原本的rbenv刪除
- 免費設定 SSL
部署後
- 登入後遇到問題
HTTP Origin header (https://ec.tun-grp.com) didn't match request.base_url (http://ec.tun-grp.com)
網路上有提供在rails 強迫設定SSL的用法,但使用之後就壞掉了,所以加入config.force_ssl = true
方法不可行。
再來第二個方式是在 /etc/nginx/sites-enabled/[APP_NAME]
(本專案名為tungrp) 加入以下兩行,使得強迫使用 https 的防護
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
不過老闆 Kurt 說虛擬機理論上不該force ssl,這是在還沒設定load balance 的狀況下使用,所以這兩行可以不用加。
- 本地端重啟 puma
cap production puma:start
- 在虛擬機改程式碼後,虛擬機(伺服器)重啟puma
sudo systemctl restart puma.service
- 改動 nginx 設定
sudo nano /etc/nginx/nginx.conf
sudo service nginx restart # 改完重啟
- Rails log 使用 logrotate
實用範例
- 該篇介紹的部署方式為 Ubuntu 20.04 + Capistrano + Nginx + Puma + RVM為實作,與大部分的網頁部署方式不同(Ubuntu 20.04 + Capistrano + Nginx + Passenger + rbenv),為與本次專案最接近的部署方式。
2. 其他經常看範例
其他託管地
除了GCP,還有AWS,以及其他地方可供託管,像是亞洲地區較常用的linode,以及國外流行的 Digital Ocean。
其他
- cheatsheet
GCP 文章
錯誤
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
Could not find mysql2–0.5.3 in any of the sources (Bundler::GemNotFound)
Install node14
sudo npm cache clean -f
sudo npm install -g n
sudo n stablecurl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs
AccessDeniedException: 403 tungrp-gs-test@tungrp-ec-20200930.iam.gserviceaccount.com does not have storage.objects.create access to the Google Cloud Storage object.
health checker
在load balance環境裡面,我們會需要health checker,固定時間打health checker 確認 load balance