MRSKとCloud Native BuildpacksでサクッとRailsをコンテナ化してデプロイした話
こんにちは、みてねコールドクターでエンジニアマネージャーをしている遠藤です。
今回は、MRSKとCloud Native Buildpacksを使用して、サクッとRailsをコンテナ化してデプロイした話を紹介します。
背景
弊社のサービスは、元々Herokuでホスティングを行っていましたが、様々な事情によりAWSへと移行することになりました。
移行の準備期間が短かったため、ほぼHerokuのビルドシステムと同等の機能を持つCloud Native Buildpacksを使用することにしました。
さらにデプロイメントや運用を簡単に行うために、MRSKも併用することを決定しました。
Cloud Native Buildpacksとは
Cloud Native Buildpacksは、ソースコードからクラウド準拠のイメージを作成するためのオープンソースのツールです。具体的には、Cloud Native Buildpacksは、アプリケーションのソースコードをDockerやOCI互換のイメージに変換するための方法を提供します。これにより、開発者はアプリケーションをパッケージ化し、任意のクラウド環境で実行することができます。
Buildpacksは、アプリケーションのランタイム環境を自動的に検出し、依存関係を取得し、アプリケーションをコンパイルし、DockerやOCI互換のイメージを作成します。これは、開発者がランタイムや依存関係の管理から解放され、アプリケーションの開発に集中することを可能にします。
Cloud Native Buildpacksは、HerokuとPivotalが共同で開発したもので、Buildpacks v3 APIを使用しています。これは、既存のBuildpacks v2 APIと比較して改善され、より安全で効率的なアプリケーションイメージを作成することができます。
Cloud Native BuildpacksはCloud Native Computing Foundation(CNCF)の一部であり、KubernetesやDockerなどと同じく、クラウドネイティブテクノロジーの一部となっています。
(ChatGPTから引用)
MRSKとは
- 37signalsが開発しているコンテナのデプロイツールです。雑に表現するとコンテナ版Capistranoです。
実装
イメージのビルド
通常MRSKでは、デプロイ時にDockerfileを使ってビルドしますが、今回はCloud Native Buildpacksを使ってビルドします。
Github Actionsでビルドし、GitHub Container Registryにpushするようにしました。
name: App Build
on:
push:
branches:
- main
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
register:
name: Package, Publish, and Register
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- id: checkout
uses: actions/checkout@v3
- id: setup-tools
uses: buildpacks/github-actions/setup-tools@v5.1.0
- id: setup-pack
uses: buildpacks/github-actions/setup-pack@v5.1.0
- id: package
run: |
pack build -e RAILS_MASTER_KEY=${{ secrets.RAILS_MASTER_KEY }} --builder heroku/buildpacks:20 --buildpack heroku/nodejs,heroku/ruby@2.0.0,heroku/procfile app
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: push docker image to ghcr
run: |
docker tag app ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
buildpackにheroku/procfile
を指定すると、Procfileに記載されたコマンドからentrypointを作成してくれます。
今回は、Procfileに以下のように記載しています。
web: bundle exec puma -C config/puma.rb
release: bundle exec rake db:migrate
worker: bundle exec sidekiq -C config/sidekiq.yml
schedule: bundle exec clockwork config/clock.rb
定期実行はclockworkを導入しました。
MRSKのサンプルでは、cronの実行をしていましたが、実装の簡潔さを優先しています。
デプロイ
デプロイは、MRSKを使ってデプロイします。
MRSKの設定ファイルは以下のようになります。
# Name of your application. Used to uniquely configure containers.
service: backend-service
# Name of the container image.
image: image/app_name
# Deploy to these servers.
servers:
web:
hosts:
- backend.example.com
options:
publish:
- ":3000"
worker:
hosts:
- worker.example.com
options:
entrypoint: worker
schedule:
hosts:
- schedule.example.com
options:
entrypoint: schedule
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
# server: registry.digitalocean.com / ghcr.io / ...
server: ghcr.io
username: username
# Always use an access token rather than real password when possible.
password:
- MRSK_REGISTRY_PASSWORD
# Inject ENV variables into containers (secrets come from .env).
env:
clear:
RAILS_SERVE_STATIC_FILES: true
RAILS_LOG_TO_STDOUT: true
TZ: Asia/Tokyo
PORT: 3000
RAILS_ENV: production
secret:
- RAILS_MASTER_KEY
- DATABASE_URL
- REDIS_URL
# Use a different ssh user than root
ssh:
user: app
traefik:
args:
accesslog: true
accesslog.format: json
# Configure a custom healthcheck (default is /up on port 3000)
healthcheck:
path: /up
max_attempts: 7
interval: 20s
optionsでDockerの起動時のオプションを指定できます。
デフォルトだとwebのポートが空いていないので、publishでポートを開放しています。
また、cmdでコマンドを指定した場合、rails serverの後ろにコマンドを追加して実行しようとするので、workerや定期実行させるコンテナには、Procfileで作成したentrypointを指定しています。
デプロイは、以下のようにします。
$ VERSION=latest mrsk deploy -P
VERSIONを指定しない場合、ローカルの状態からバージョンを取得しようとするので、明示的にlatestを指定しています。
また、-P
オプションをつけることで、ビルドをスキップしてくれます。
各種設定が終わっていれば、これでデプロイは完了です。
課題
実行はどこで行うか?
Github上のコメント等から推測すると、ローカルマシンからの実行が想定されている気がします。
弊社でもいったんローカルからの実行を想定しています。
マイグレーションの実行はどうするか?
用意されているhooksではマイグレーションの実行は難しいと感じています。
マイグレーション専用(あるいは他の用途と兼用)のサーバを用意し、先にリリースしてマイグレーション、その後本番をリリースするという方法が考えられます。
Github上のコメントでも、ローカルからコマンドを想定していそうなコメントがありました。
まとめ
色々と課題がありつつも、MRSKとCloud Native Buildpacksを使うことで、デプロイの簡潔さを実現できました。
MRSKの想定されてない使われ方をしているというのもあり、全然情報がないので、調べるのに苦労しました。
またまだできたばかりというのもあり、欲しい機能がまだ実装されていなかったり、謎の挙動があったり(バグっぽい)し、困りつつも、短期間でサーバーの移転が実現できたのはよかったです。
今後は、MRSKの機能が充実していくことを期待しています。
Discussion