docker buildkitを使いecsで本番モードでrailsを起動させる方法(master.keyの配送方法など)
ecsにrailsをデプロイする際にcredentials.yml.encに情報を書きこんでいる場合
credentials.yml.enc場合master.keyの情報も本番のecsに送らないと解読ができずエラーでrails コンテナが起動しない状態になってしまいます。
そこで今回はどのようにmaster.keyの情報を本番のecsに送れば良いかを説明していきます。
イメージにそのまま組み込めば良いのではないか?
特に何も指定しなければdocker buildする際にmaster.keyも一緒にイメージ化されてしまいます。
しかしmaster.keyまでイメージ化してしまうと、そのイメージを取得した誰でもredentials.yml.enc
中身を複合化し、機密情報を取得することができてしまいます。
NG!!!!!!!!
ではmsater.keyを.dockerignoreに入れてしまいイメージに含めなければ良いのでは?
確かに.dockerignoreにmsater.keyを含めればイメージには含まれないがcredentials.yml.encが複合化できないので、ここから情報を取得している実装の部分でエラーが発生して、docker buildに失敗してしまいイメージを作成できないのでそもそもデプロイできない😢
じゃあどうすれば良いか
やり方はいくつかあるが代表的になやり方は以下ではないかと思う
- マルチステージビルドで行う
- docker buildkitを使ってbuild時のみ一時的にmaster.keyをコンテナ側に送り、イメージには含めない
docker buildkit機能が最近のバージョンではデフォルトで入っているのでこれを使うのが一番楽な気がする
ということでdocker buildkitでmaster.keyの情報をecsにセットする方法を説明します!
まずdocker buildkitを使いmaster.keyを含めずイメージを生成する方法
まず今回使用するdocker-compose.yml, entrypoint.sh, Dockerfileを記載します。
また事前に下記でmaster.keyを作成し、機密情報を記載しておく
EDITOR=vi bin/rails credentials:edit
ちなみに環境を指定して作成することもできる
bin/rails credentials:edit --environment development
docker-compose.yml
version: "3.9"
services:
db:
image: postgres
volumes:
- postgresql_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
web:
build: .
volumes:
- ./web:/app
ports:
- "3000:3000"
depends_on:
- db
volumes:
postgresql_data:
entrypoint.sh
#!/bin/bash
set -e
# 本番有効
bin/rails db:migrate
rm -f tmp/pids/server.pid && bin/rails s
# 今回CMDコマンド使わないのでコメントアウト
# exec "$@"
Dockerfile
FROM ruby:3.0
ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
ENV DEBCONF_NOWARNINGS=yes
ENV TZ Asia/Tokyo
ENV RAILS_ENV production
ENV BUNDLE_DEPLOYMENT true
ENV BUNDLE_WITHOUT development:test
ENV RAILS_SERVE_STATIC_FILES true
ENV RAILS_LOG_TO_STDOUT true
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update -qq \
&& apt-get install -y cron \
&& apt-get install -y nodejs yarn postgresql-client
RUN rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY web/Gemfile /app/Gemfile
COPY web/Gemfile.lock /app/Gemfile.lock
RUN bundle install
# 本番用
COPY web/yarn.lock /app/yarn.lock
COPY web/package.json /app/package.json
COPY ./web /app
### ここのtargetでコンテナのどこのディレクトリファイルにidで指定したファイルを送るかを設定する
RUN --mount=type=secret,id=master_key,target=config/master.key,required=true rails assets:precompile \
&& yarn install --production --frozen-lockfile \
&& yarn cache clean \
&& rm -rf /app/node_modules /app/tmp/cache
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
RUN --mount=type=secret,id=master_key,target=config/master.key,required=true
上記の部分でapp配下のconfig/master.keyにidがmaster_keyで送られてきたファイルを一時的に設置するかを指定する
そして下記のコマンドを使ってdocker fileをbuildする
ただしコマンドはrailsのトップディレクトリーで実行している前提で書いてあるので
srcは./config/master.keyを指定してる
docker buildx build --secret id=master_key,src=./config/master.key -t ビルドイメージ名 .
id=master_keyを指定してbuildしているので、srcの./config/master.keyがDockerfileの
app/config/master.keyに一時的に送信されてbuildすることができる。
イメージにmaster.keyを含めずbuildはできたがecsでどのようにこのmaster.keyの情報を送れば良いのか
これはrailsガイドを見ればわかる!
railsガイドのmaster.keyの部分を見ると環境変数にRAILS_MASTER_KEYを設定すれば
master.keyではなく環境変数の方の値をみて複合化しますよと書いてあるので
ecsにはタスク定義でRAILS_MASTER_KEYを設定すれば良いです!
設定する部分はタスク定義の環境変数の部分に設定すればよい
ただ直接環境変数をタスク定義に打ち込むよりもパラメーターグループ経由で送る方がよりセキュアーです
方法は下記を見てください
Discussion