Webuilder240

Dockerで1つのイメージ複数のコマンドを切り替える方法

2018-01-29 17:30:00 +0900

これをやりたい理由

作るDockeイメージは1つにしたいのだけど、デプロイする先によってコンテナの役割(例えばCronやJobワーカーを動かすコンテナとWebサーバーを実際に動かすコンテナ等)を分けたいときに利用する。

例えばAzureのWebApps for Container (Web Apps on Linux)で、 Webサーバーはスケールアウトしたいけど、Jobワーカーサーバーはスケールアウトしたくない(もしくはJobワーカーサーバーは任意のタイミングにしたい)とか 管理するコンテナを分けたいとかそういうときに利用すれば便利だと思っている。

やりかた

init.shという起動時の環境変数によって実行するコマンドを変更するスクリプトをCMDで実行してあげればOK。 これで実行時に環境変数を渡してあげればOK。

下記例はRubyアプリケーションを動かす際の自分のDockerfileの雛形のようなものである。

# Dockerfile
---
FROM ruby:2.5

ENV LANG C.UTF-8
ENV RACK_ENV production
EXPOSE 3000

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY Gemfile /usr/src/app/
COPY Gemfile.lock /usr/src/app/
RUN bundle install -j4 --without development test

RUN mkdir tmp
COPY . /usr/src/app
RUN chmod u+x init.sh
CMD "./init.sh"
# init.sh
---
#!/bin/bash
set -e

if [[ "${RUN_WEBAPP}" != "" ]]
then
  echo "Starting uniron ..."
  bundle exec unicorn -c config/unicorn.rb
else [[ "${RUN_WEBJOB}" != "" ]]
  echo "Starting sidekiq ..."
  bundle exec sidekiq -r ./app.rb -C ./sidekiq.yml
fi

以上の内容でDockerイメージをBuildして、docker runするときに環境変数を渡せばOK。

サンプルでWebサーバーを実行する場合

 docker run -e RUN_WEBAPP=true xxx

サンプルでJobワーカーサーバーを実行する場合

 docker run -e RUN_WEBJOB=true xxx

おわりに

ちなみにAWSのElasticBeanstalkあたりだとマルチコンテナーをそもそもサポートしているので、そっちを使うほうがまぁ普通だと思っている。 もしくはCronを利用しないで、SidekiqやDelatedJobあたりでワーカーがいくらスケールアウトしても問題ないようにするとか、 WebサーバーとWorkerの同居を許容してしまうとか、そういう方法で解決したほうが至極真っ当な感じはする。

余談

AzureからAWSのDynamoDBって利用すると遅いのかな。 ぶっちゃけ用途があえばCosmosDBでもよかったんだけど、メッセージングアプリっぽいの作りたくて、 MongoベースのAPIでまともに要件を満たせるのか感があって、不安...

関連しそうなブログ