TT Lab
はじめる
学ぶ 学習パス コース

イメージのビルド

Dockerfileを一行ずつ積む

TT Labで続きを見る

このラボは本物のVM上で動きます

この環境はPodではなく、KubeVirtが起動した仮想マシンです。Linuxカーネルが別に動き、systemdが実際にサービスを管理し、dockerは模倣ではなく本物のDockerエンジンです。docker runで起動したコンテナは実際にプロセスになり、docker execもdocker logsもそのまま動作します。

以前はこのラボがPodの中で動いていました。カーネル権限をすべて落とした環境だったため、コンテナを起動するステップが塞がれており、イメージアーカイブを自分で展開してみるという回り道で学んでいました。もう回り道は必要ありません。

知っておくべきことが2つあります。

目標

Dockerfileの命令を1つずつ追加しながら、それぞれがイメージのどの部分を変えるのかをinspectで確認し、最後にレビューのチェックリストを通過するファイルを作ります。

なぜ重要なのか

Dockerfileは設定ファイルのように見えますが、実際には順序が意味を持つビルドスクリプトです。同じ命令でも、位置によってレイヤーが増え、キャッシュが壊れ、シークレットが残り続けます。このラボの目的は、命令を暗記することではなく、「この行はレイヤーを作るのか、設定を刻むのか」を毎回区別する習慣をつけることです。その区別1つで、サイズの問題とセキュリティの問題のほとんどを予防できます。

ステップ

各ステップで新しいタグでビルドし、前のステップの結果も残しておきます。

  1. /root/build1を作成し、/root/build1/Dockerfileの最初の行をFROM alpine:3.20として書きます。
  2. labhub/app:v1でビルドします。
  3. /root/build1/app.shを作成してapp-runningを出力させ、DockerfileにWORKDIR /appとCOPY app.sh /app/を追加して、labhub/app:v2でビルドします。
  4. CMDをJSON配列形式で追加してapp.shが実行されるようにし、labhub/app:v3でビルドします。実行すると、app-runningが出力される必要があります。
  5. ENV APP_ENV=prodとARG VERSIONを追加し、ARGで受け取った値をLABEL app.versionに刻みます。--build-arg VERSION=2.1.0でlabhub/app:v4をビルドします。
  6. ENTRYPOINTを配列形式にし、CMD ["default-arg"]をデフォルト値にして、引数なしで実行するとdefault-argが、override-argを渡すとoverride-argが出力されるようにしたうえで、labhub/app:v5でビルドします。
  7. LABEL org.opencontainers.image.title=labhub-appとEXPOSE 8080を追加して、labhub/app:v6でビルドします。
  8. 最終的な/root/build1/Dockerfileが、次の5項目をすべて満たすように整えて、labhub/app:v7でビルドします。
    • FROMにタグが固定されており、latestではありません
    • WORKDIRが最初のCOPYより前にあります
    • ENTRYPOINTまたはCMDがJSON配列です
    • ENV/ARGの名前に、TOKEN・SECRET・PASSWORD・API_KEYが含まれません

参考

ベースイメージを固定する

/root/build1を作成し、/root/build1/Dockerfileの最初の行をFROM alpine:3.20として書きます。

FROMにタグを明記してください。latestは、昨日のビルドと今日のビルドが変わる原因になります。

最初のビルド

labhub/app:v1でビルドします。

ビルドコンテキストには、Dockerfileがあるディレクトリを指定します。-tで名前を付けないと、あとで見つけにくくなります。

作業ディレクトリとファイルのコピー

/root/build1/app.shを作成してapp-runningを出力させ、DockerfileにWORKDIR /appとCOPY app.sh /app/を追加して、labhub/app:v2でビルドします。

WORKDIRはイメージ設定(Config.WorkingDir)に刻まれ、COPYはレイヤーを作ります。2つの命令の順序が、相対パスの意味を決めます。

デフォルトコマンドを指定する

CMDをJSON配列形式で追加してapp.shが実行されるようにし、labhub/app:v3でビルドします。実行すると、app-runningが出力される必要があります。

シェル形式で書くと/bin/sh -cで包まれ、PID 1がシェルになります。配列形式が必要な理由は、前のコースで見ました。

ビルド引数と環境変数の違い

ENV APP_ENV=prodとARG VERSIONを追加し、ARGで受け取った値をLABEL app.versionに刻みます。--build-arg VERSION=2.1.0でlabhub/app:v4をビルドします。

ARGはビルド中だけ存在し、ENVはイメージに残ります。ビルド引数で受け取った値をイメージに残すには、LABELに刻んでください。

ENTRYPOINTとCMDの組み合わせ

ENTRYPOINTを配列形式にし、CMD ["default-arg"]をデフォルト値にして、引数なしで実行するとdefault-argが、override-argを渡すとoverride-argが出力されるようにしたうえで、labhub/app:v5でビルドします。

ENTRYPOINTは固定され、CMDは実行時の引数で置き換えられます。どちらも配列形式で書いてください。

標準ラベルとポートの宣言

LABEL org.opencontainers.image.title=labhub-appとEXPOSE 8080を追加して、labhub/app:v6でビルドします。

OCI標準のラベルキーは、org.opencontainers.image.で始まります。EXPOSEは、ポートを開くのではなく、文書化するための命令です。

レビューのチェックリストを通過させる

最終的な/root/build1/Dockerfileが、次の5項目をすべて満たすように整えて、labhub/app:v7でビルドします。

ここまでのDockerfileを、5項目に合わせて整えてください。採点では、ファイルの内容とビルド結果の両方を確認します。