🧊

Dockerfile の再現性をちょっと高める

2023/12/01に公開

ライフイズテック株式会社 サービス開発部の山口 (@no_clock) です。塾プロダクトグループでソフトウェアエンジニアをしています。

Dockerfile でいつでもどこでも同じ環境を再現できる… と思いたいのですが、いろんな原因で壊れる(再現できなくなる)ことがあります。

本記事では、すこしだけ再現性を高める方法を考えます。 100 点は目指しません。

3 行でまとめると

  • FROM 命令で記述するベースイメージのタグはパッチバージョンまで細かく指定
  • 例えば Node.js なら npm ci, Ruby なら bundle install --deployment を使う
  • あくまで「すこしだけ」、割り切りが必要

FROM 命令

FROM 命令で指定するベースイメージのタグを なるべく細かく指定する ことで、イメージが変わるリスクを減らします。

たとえば node では、 Node.js のパッチバージョンや Linux ディストリビューションのコードネーム (bookworm) もしくはバージョン (alpine3.18) まで明記されたタグを使います。

FROM node:20.10.0-bookworm-slim

また、昨今は CPU アーキテクチャの違いから問題が生じるケースもあります( Apple silicon や AWS Graviton は ARM ベース)。固定して問題なければ、引数 --platform で固定できます。

FROM --platform=linux/arm64 node:20.10.0-bookworm-slim

より厳密には、イメージの digest 値を指定することも出来ます。ただし、可読性は落ちる上、プラットフォームも固定されます。

# node:20.10.0-bookworm-slim (linux/amd64)
FROM node@sha256:18aacc7993a16f1d766c21e3bff922e830bcdc7b549bbb789ceb7374a6138480

アプリケーション

.dockerignore でビルド結果などを除外する

イメージビルド時にアプリケーションの過去のビルド結果などが混入しないよう、 .dockerignore で除外します。

.dockerignore
node_modules
.next
out

(ビルドを CI でしか行わない場合は、 .gitignore でリポジトリから除外していれば事足ります)

インストールされるライブラリのバージョンを固定する

ライブラリのインストール時に、バージョンが固定されるようにします。

固定方法は、使用言語やパッケージマネージャーによります。例えば npm (Node.js) では npm ci を、 Bundler (Ruby) では --deployment オプション を使います。もちろん、ロックファイル (package-lock.json や Gemfile.lock) が正しく管理されている必要があります。

ちょっとだけ高まった

ベースイメージはほぼ固定され、ライブラリのバージョンも固定されました。ちょっとだけ再現性が高まったと言えます。ただし、再現性が下がるポイントはまだあります。

  • ベースイメージのタグが更新されるかもしれないし、消えるかもしれない
  • ライブラリの古いバージョンが提供されなくなるかもしれない
  • aptapk で追加するパッケージのバージョンが変わるかもしれない
  • (そもそもインターネットからコンテンツを取得している時点で、限界がある…)

ある程度のところで割り切っておくのが無難そうです。


ちょっと宣伝

ライフイズテック サービス開発部では、気軽にご参加いただけるカジュアルなイベントを実施しています。開催予定のイベントは、 connpass のライフイズテックグループからご確認ください!

Discussion