スタックを宣言して照合する
このラボは本物のVM上で動きます
この環境はPodではなく、KubeVirtが起動した仮想マシンです。Linuxカーネルが別に動き、systemdが実際にサービスを管理し、dockerは模倣ではなく本物のDockerエンジンです。docker runで起動したコンテナは実際にプロセスになり、docker execもdocker logsもそのまま動作します。
以前はこのラボがPodの中で動いていました。カーネル権限をすべて落とした環境だったため、コンテナを起動するステップが塞がれており、イメージアーカイブを自分で展開してみるという回り道で学んでいました。もう回り道は必要ありません。
知っておくべきことが2つあります。
- 最初の起動に1分ほどかかります。VMが起動してDockerをインストールするためです。Podのラボ(通常40秒)より遅くなります。
- ブラウザープレビューはありません。VMへの接続は、採点用のポート1つしか開いていません。Webサーバーを起動した場合は、VMの中で
curlを使って確認してください。
目標
2つのサービスで構成されるスタックをComposeファイルで宣言し、同じスタックを手でも起動したうえで、宣言した値と実際の値が正確に一致するかを照合します。
なぜ重要なのか
Composeを「複数のコンテナを一度に起動するツール」としてしか理解しないと、半分しか得られません。本当の価値は、スタックの形がファイルに書かれ、リポジトリに残ることです。そして、この価値は、ファイルと現実が一致しているときにだけ成り立ちます。誰かが手でコンテナを変更した瞬間、ファイルはドキュメントではなく嘘になり、その嘘は次のデプロイまで誰も気づきません。そのため、このラボの最後のステップは、新しい機能を作ることではなく、照合です。宣言的なツールを使うチームが必ず身につけるべき習慣が、ここにあります。
ステップ
/root/ops3/compose.yamlを、次の構造で作成します。インデントは2スペースで、最上位のキー(services:、volumes:、networks:)は必ず行の先頭から始める必要があります。
- 最上位に
services:を置き、その下にweb:とcache:の2つのサービスを、2スペースのインデントで宣言します。 webのimageはnginx:1.27-alpine、cacheのimageはalpine:3.20とし、cacheには、動き続けるようにcommandも書きます。- 最上位に
networks:を置き、その下にappnet:を宣言したうえで、2つのサービスの両方のnetworks:リストに- appnetを入れます。 webにports:を置き、"127.0.0.1:8081:80"を入れます。cacheにはportsを置きません。- 最上位に
volumes:を置き、webdata:を宣言したうえで、webのvolumes:にwebdata:/usr/share/nginx/htmlを入れます。 cacheにenvironment:でCACHE_TTLの値60を入れ、webにdepends_on:で- cacheを入れます。- 同じスタックを手で起動します。ネットワーク名は
ops3net、コンテナ名はops3-web(nginx:1.27-alpine、127.0.0.1:8081:80をパブリッシュ)とops3-cache(alpine:3.20、環境変数CACHE_TTL=60)で、どちらもops3netに接続します。 - このステップで新しく作るものはありません。ステップ6までの宣言と、ステップ7の実際のコンテナが、イメージ・ポート・環境変数の3項目で正確に一致しているかを確認します。
参考
- 最上位のキーの順序は、
services:→volumes:→networks:にすると、読みやすくなります。 - このラボのステップ8の採点では、composeファイルをパースして得た値と、
docker inspectの値を、直接比較します。 - よくある間違い1: サービス名をインデント4スペースにすると、構造が変わります。正確に2スペースです。
- よくある間違い2: ステップ7でイメージタグを
nginx:alpineのように違う書き方にすると、ステップ8の照合でずれます。
サービスを2つ宣言する
最上位にservices:を置き、その下にweb:とcache:の2つのサービスを、2スペースのインデントで宣言します。
最上位のservicesの下に、サービス名を2スペースのインデントで置きます。インデントがずれると、ファイル全体の意味が変わります。
イメージとコマンドを指定する
webのimageはnginx:1.27-alpine、cacheのimageはalpine:3.20とし、cacheには、動き続けるようにcommandも書きます。
alpineはデフォルトのコマンドがすぐに終了するため、動き続けるcommandも一緒に書く必要があります。
共用のネットワークを宣言する
最上位にnetworks:を置き、その下にappnet:を宣言したうえで、2つのサービスの両方のnetworks:リストに- appnetを入れます。
最上位でnetworksを宣言し、各サービスからその名前を参照します。両方の場所で必要です。
ポートはループバックにだけ
webにports:を置き、"127.0.0.1:8081:80"を入れます。cacheにはportsを置きません。
ポートの文字列の先頭に、バインドアドレスを付けられます。内部通信だけを行うサービスには、portsを使いません。
名前付きボリュームを宣言する
最上位にvolumes:を置き、webdata:を宣言したうえで、webのvolumes:にwebdata:/usr/share/nginx/htmlを入れます。
最上位のvolumesで名前を宣言し、サービスでは対象パスと一緒に書きます。
環境変数と起動順序
cacheにenvironment:でCACHE_TTLの値60を入れ、webにdepends_on:で- cacheを入れます。
depends_onは順序だけを保証し、準備状態は保証しないことを覚えておいてください。
同じスタックを手で起動する
同じスタックを手で起動します。ネットワーク名はops3net、コンテナ名はops3-web(nginx:1.27-alpine、127.0.0.1:8081:80をパブリッシュ)とops3-cache(alpine:3.20、環境変数CACHE_TTL=60)で、どちらもops3netに接続します。
ネットワークを先に作り、コンテナを接続します。宣言ファイルに書いた値と、まったく同じ値を使ってください。
宣言と実際を照合する
このステップで新しく作るものはありません。ステップ6までの宣言と、ステップ7の実際のコンテナが、イメージ・ポート・環境変数の3項目で正確に一致しているかを確認します。
採点では、composeファイルから読み取った値と、実際のコンテナのinspectの値を、直接比較します。1文字でも違えば、ずれています。