n番煎じですが、Multi-stage buildsを使って環境別のコンテナイメージを作成する一例になります。
環境別にパッケージや挙動・設定が異なるのは望ましくないですが、
こういう書き方をする場合もあるということが誰かの参考になれば幸いです。
今回は、環境別にコンテナイメージを作成する場合のDockerfileとGitHub Actionsについて紹介します。
環境別のコンテナイメージを作成したい時とは
環境別のコンテナイメージを作成したいケースは、以下のようなケースがあります。
- 環境別にインストールするパッケージやライブラリを変更する
- 環境別に設定ファイルを変更する
KubernetesのConfigMapなどで外部から追加・差し替えができる場合は、イメージを環境別に作成する必要はありません。
ですが、差し替えするのが簡単ではない場合もあり、そういった場合は環境別にコンテナイメージを作成した方がメンテが楽な場合があります。 ※1
環境別にコンテナイメージを作成する
環境別にコンテナイメージを作成するために、今回達成したい要件をまとめます。
- AlpineをベースにしてRedisを動かすイメージを作成する
- 全てのIPv4,IPv6アドレスからの接続を許可する
- ローカルの場合、BashとVimを利用できるようにする
- ローカルの場合、ログレベルをdebugにする
- 本番の場合、ログレベルをwarningに変更する
これを踏まえたDockerfileは以下のようになります。
# 全ての環境で共通 FROM alpine:3.16 as base RUN apk add --update --no-cache redis RUN sed -i 's/bind 127.0.0.1 -::1/bind 0.0.0.0 ::/g' /etc/redis.conf CMD ["redis-server"] # ローカル FROM base as dev RUN apk add --update --no-cache bash vim RUN sed -i 's/loglevel notice/loglevel debug/g' /etc/redis.conf # ステージング FROM base as staging # 本番 FROM base as production RUN sed -i 's/loglevel notice/loglevel warning/g' /etc/redis.conf
ローカルでdevステージを動かす
ローカルではdocker comose
を使って動かしたいので、compose.yamlを用意します。 ※2
ローカル向けでは、buildのオプションのtarget
にdev
を指定することで、devステージのイメージが利用されます。
services: redis: build: target: dev ports: - 6379:6379
docker compose up
を実行して起動することで動作確認ができます。
実際にBashなどが起動できるかは、docker compose exec -it redis bash
で動作確認ができます。
今回はRedis用のイメージとして書いていますが、アプリケーションにも同様の仕組みが使えるので、 是非使ってみてください。
ステージングと本番向けのイメージをGitHub Actionsでビルドする
mainブランチが更新されたら、ステージング・本番向けにそれぞれイメージをビルドする仕組みを作ります。
こちらもローカル同様にtarget
にstaging
か、production
を指定することで実現しています。
name: Build images on: push: branches: - main jobs: build_and_push: strategy: matrix: stage: [staging, production] steps: - uses: actions/checkout@v3 - docker/setup-qemu-action@v2 - docker/setup-buildx-action@v2 - name: Build and push uses: docker/build-push-action@v3 with: context: . target: ${{ matrix.stage }} push: false
といった形で、各環境別にイメージを作成する方法について紹介しました。
実際に利用するケースはあまりないですが、どうしても利用したい場合などは、こういった書き方を検討してみてください。
※1 色々書いてますが、ローカルを含めた全ての環境で同一イメージを利用することが望ましいです
※2 動作確認の都合上、docker-composeではなくdocker composeを使っています