Rails 部署實踐 - 素材預先編譯
目前大多數的 Rails 專案都還是前端、後端一起開發的,因此我們還需要讓製作出來的容器鏡像能夠將網站運行所需的圖檔、JavaScript 等等製作出來加入到容器鏡像中。
目前我們還沒有搭配持續交付(Continuous Delivery)相關的設計,因此我們先以直接在容器鏡像製作階段製作素材(Assets)的方式。
利用多階段建置實現
目前 Rails 專案大多是以 Node.js 為基礎來編譯這些素材,然而我們的 Ruby 基礎鏡像並不會內建 Node.js,因此可以利用多階段部署來解決這個問題。
1# ...
2FROM node:16.14-alpine as node
3FROM ruby:3-alpine as assets
4
5COPY --from=node /usr/local/bin/node /usr/local/bin/node
6COPY --from=gem /usr/local/bundle/config /usr/local/bundle/config
7COPY --from=gem /usr/local/bundle /usr/local/bundle
8COPY --from=gem /src/vendor/bundle /src/vendor/bundle
9
10RUN mkdir -p /src
11
12COPY . /src
13WORKDIR /src
14
15ENV RAILS_ENV production
16
17RUN bundle exec rake assets:precompile
18
19FROM ruby:3-alpine
20
21# ...
22
23COPY --from=assets /${APP_ROOT}/public /${APP_ROOT}/public
24
25# ...
我可以直接下載 Node.js 的鏡像不做任何事情,因為 Node.js 的主程式只需要 /usr/local/bin/node
這單一一個檔案就能夠運行,因此我們可以直接將他複製到我們的容器鏡像中,讓我們可以呼叫 node
命令。
接下來將 Ruby Gem 也複製到這個建置階段,這樣也就不需要額外的安裝 Ruby Gem 的處理,剩下的就是將環境變數設定為 RAILS_ENV=production
來以正式環境的模式進行預先編譯。
當整個程序完成後,我們就可以將 /src/public
目錄下的 packs
以及 assets
兩個目錄複製到最終的鏡像中,來讓我們的 Rails 專案可以使用。
Rails Credentials
然而,在靜態素材預先編譯時,可能會遇到一些狀況。像是我們有一些密鑰會保存在 Rails 6 加入的 Credentials(憑證)機制中,在編譯過程中會需要使用。
此時我們就會需要提供 Master Key(主鑰匙)到建置的環境裡面,因此可以透過 ARG
命令來允許傳入額外的設定。
1FROM ruby:3-alpine as assets
2
3ARG RAILS_MASTER_KEY
4
5# ...
6ENV RAILS_ENV production
7ENV RAILS_MASTER_KEY $RAILS_MASTER_KEY
8
9RUN bundle exec rake assets:precompile
因為 Rails 是基於環境變數偵測的,因此在設定 ARG
命令後我們還需要利用 ENV
命令轉換為環境變數使用。
透過多階段建置,我們還額外獲得了 RAILS_MASTER_KEY
這類敏感資訊只會在建置階段中被保存,而不會被正式部署的鏡像紀錄,也提高了安全性。然而在建置的快取中仍會因為我們的 ENV
命令而被暫存到,因此在使用上還是需要多加注意。
如果你遇到了需要 Redis 或者資料庫的狀況,我會推薦你重新審視為什麼編譯靜態素材會需要連線 Redis 和資料庫,在大多數狀況下都是不太合理的情況。這有可能是專案的連線方式有問題,或者對靜態素材的定義實際上不太「靜態」
提供靜態素材
雖然我們已經具備了 public/packs
以及 public/assets
這兩個目錄,然而在 Rails 中正式環境(Production Mode,生產力模式)並不會處理這類靜態素材,因為這類檔案更適合由 Nginx 這類伺服器處理,吞吐量(Throughput)也會是讓 Rails 來處理高上數倍。
在這樣的情況,我們更適合搭配持續交付的工具來處理,如果是測試環境或者小型專案,我們可以透過設定來告訴 Rails 直接處理,而不是透過第三方的靜態檔案伺服器。
1FROM ruby:3-alpine as assets
2
3# ...
4
5FROM ruby:3-alpine
6
7# ...
8
9ENV RAILS_ENV=production
10ENV RAILS_SERVE_STATIC_FILES=yes
11
12# ...
自從 Ruby on Rails 5 開始,就陸陸續續加入許多 RAILS_
類型的環境變數,讓我們可以很輕鬆的針對這類常見的環境差異來進行設定。
在使用 config/environments/production.rb
這個檔案的狀況下,可以利用 RAILS_SERVE_STATIC_FILES=yes
的設定讓 Rails 來處理靜態素材,這樣我們建置出來的容器鏡像就能處理 JavaScript 這類檔案。
如果想在第一時間收到更新,歡迎訂閱弦而時習之在這系列文章更新時收到通知,如果有希望了解的知識,可以利用Rails 部署實踐回饋表單告訴我。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- Rails 部署實踐 - 補上 Rails 教學缺少的一塊
- Rails 部署實踐 - 以容器部署 Rails 的方案
- Rails 部署實踐 - 部署前置準備
- Rails 部署實踐 - 容器化 Rails 專案概述
- Rails 部署實踐 - 上傳容器鏡像
- Rails 部署實踐 - 伺服器搭建
- Rails 部署實踐 - 撰寫 Docker Compose
- Rails 部署實踐 - 使用 HTTPS 協定加密連線
- Rails 部署實踐 - 健康檢查
- Rails 部署實踐 - 滾動更新
- Rails 實踐部署 - 使用 Alpine 製作容器鏡像
- Rails 部署實踐 - 容器化的 Bundler 最佳設定
- Rails 部署實踐 - 多階段建置
- Rails 部署實踐 - 素材預先編譯
- Rails 部署實踐 - 容器進入點
- Rails 部署實踐 - 容器相關工具
- Rails 部署實踐 - 持續部署
- Rails 部署實踐 - 使用 GitLab CI 自動化建置
- Rails 部署實踐 - 使用 GitHub Actions 自動化建置
- Rails 部署實踐 - 使用 Watchtower 自動更新
- Rails 部署實踐 - Docker Swarm 與 Docker Compose
- Rails 部署實踐 - Docker Swarm 安裝與設定
- Rails 部署實踐 - 部署到 Docker Swarm
- Rails 部署實踐 - 整合 GitLab CI 自動部署
- Rails 部署實踐 - 使用 GitLab 的 Review Apps 機制
- Rails 部署實踐 - 部署不是終點