My tech diary

ソフトウェアエンジニアをやっています。技術的内容を中心に調べたことを書いていきます。

Docker利用時のソースコードの変更反映

ソースコード変更の Docker コンテナへの反映について、ちょうどいい機会があったので基礎も含めて整理します。 (タイミングよく投稿されていた) 以下の Qiita の記事に書かれていることが全てだけど、補足してまとめておきます。

References

image と container

抽象化された概念の理解は、以下のような感じでいいと思っています。

  • image: 実行環境の構成を保存した情報
  • container: image を実際に動かした実行環境

その上で、以下の点を理解できていれば、今回の話的には大丈夫です。

  • container を動かすには、ベースとなる image が必ず必要なこと
  • container を破棄しても image が残っている場合があること
  • リポジトリ内のソースコードは、 image 内に含まれている場合と container 上に含まれている場合があること

なお image は実際には layer に分かれて保存されますので、そこが分かっていると image size の削減や差分 build の高速化を図ったりできます。

image の状態管理

image は実際に動いているわけではないので、状態としては存在するか否かの2択です。 そのため、操作としては、簡単に言えば、作成する、破棄するの2つとなります。

デフォルトのオプション設定で、それぞれの操作を行うコマンドは以下のとおりです。

作成する:

  • docker image build
  • docker-compose build

破棄する:

  • docker image rm
  • docker-compose rm

container の状態管理

container は実際に動いているので、状態としては、存在しない <=> 存在する <=> 動いている、の3択です。 よって、それぞれの状態遷移を起こすための操作が行えます。

デフォルトのオプション設定で、それぞれの操作を行うコマンドは以下のとおりです。

作成する:

  • docker container create
  • docker-compose create (Deprecated)

起動する:

  • docker container start
  • docker-compose start

停止する:

  • docker container stop
  • docker-compose stop

破棄する:

  • docker container rm
  • docker-compose rm

作成・起動を一気にやる:

  • docker-compose up

停止・破棄を一気にやる:

  • docker-compose down

host と Docker container の関係

host というのは、 Docker container を動かす実行環境のことですね。 Docker for Mac を使っている場合なら macOS のことです。

Docker container は host とは切り離された状態で (無関係に) 動きますので、一度 container を立ち上げてしまえば、 host 上のファイルの変更は container 上には反映されません。

ただし、 host 上のファイルシステムの一部を volume として、 Docker container に mount することができるので、その場合は、 host 上のファイルの変更が container にそのまま反映されます。

Case Study

Dockerfile を変更した場合

Dockerfile 内の記載内容は、 image を作るためのものなので、 Dockerfile を書き換えた場合は image から作り直す必要があります。 もちろん、その image を使って動いている container も作り直す必要があります

docker-compose.yaml を変更した場合

docker-compose.yaml の記載内容のうち build section 以外は、出来上がった image を使って、その設定内容で container, volume, network を作成するためのものなので、これを書き換えた場合は image を作り直す必要はありません。ただ、 container は作成時にこの設定ファイルの内容を取り込みますので、 docker-compose restart (stop -> start) だけではダメで、 container の再作成を行う必要があります

また、 docker-compose.yaml の中の build section の設定内容を書き換えた場合は、 image の再作成が必要になります

その他のファイルを変更した場合

これは本当にケースバイケースなのですが、大きく分けて以下のようなケースが考えられます。

そのファイルが image に含まれている場合

Dockerfile 内で ADDCOPY によって、対象ファイルを image に取り込んでいる場合は、基本的には image (および container) の再作成が必要になります

ただし、そのファイルの変更が動的に動作に反映される場合、 container 上でそのファイルを書き換える (host の volume を mount している場合は host 上で書き換えてもいい) ことで、一時的に、その container での動作に反映することも可能です。その場合、 host 上で永続化していない container に対する変更内容は、 container を再作成することで元に戻ってしまうことに注意が必要です。

例としては、例えば Gemfile は普通 image にも含めると思いますが、 container 動作中に Gemfile を書き換えて bundle install することで、新たな gem を container にインストールすることができます。しかし、この container を再作成すると、このインストールした状態もリセットされてしまうため、再度 Gemfile の書き換え (host の volume を mount していない場合) や bundle install が必要になるわけです。

さらに、その gem のインストールに、 image のビルド中にだけ使って、最終 image には含めていない native library が必要だったりすると、そのインストールも必要だったりして、結局は image の再作成からやり直したほうが効率的だったりします。

そのファイルが image に含まれていない場合

image に含めていないファイルを container が利用するということは、基本的には host などから volume を mount したり、 network 経由等で取得したりという構成になっているかと思います。この場合は、変更反映のための image の再作成は不要です

container については、そのファイル内容の変更が動的に動作に反映されるかどうか (live reload が有効かどうか) によって、 container の再起動や、設定反映のためのコマンド発行が必要かどうかが変わります。この部分は、アプリケーションの実装次第になるため、随時調べるか、とりあえず restart or 再作成 してみる、というのがよいかと思われます。