はじめに
LITTLE HOUR には完成したカフェメニューがあり、週末のポップアップ店でも同じサイトが必要です。ホームページだけでは不十分です。お客様には飲み物の詳細、価格、ローカルのイラスト、営業時間も必要です。あなたの仕事は、この体験全体を Docker イメージで届けることです。
用意されたファイルをパッケージ化してイメージを実行し、そこから新しいコンテナを起動して実際のサイトを確認します。アプリのコード作成や Docker のインストールは不要です。基本的なターミナル操作ができれば進められます。Docker、パス、ポート、各コマンドは使用時に説明します。カフェ、商品、価格、住所は架空です。
コマンドは Workstation、デザインの見本は Reference Menu、自分の実行中コンテナは Your Menu、環境の構成図は Topology を使います。Your Menu はステップ 2 でコンテナを起動すると利用可能になり、それまでは接続できない場合があります。各演習は独立した初期環境で始まります。
完全なメニューイメージをビルドする
このステップではカフェの要件を理解し、お客様向けサイト全体を含むイメージをビルドします。Reference Menu から始めてください。
お客様の体験を確認する
ホームページは LITTLE HOUR を紹介しています。A few good favourites の Flat white を開きます。詳細には $4.00、提供量、アレルゲン情報があります。Find us で営業時間を読み、LITTLE HOUR でホームに戻ります。これらのリンクとイラストも納品物の一部であり、省略できる装飾ではありません。

見本はポート 8082 に用意されています。自分のコンテナが停止していてもアクセスできるので、納品できた証拠には使わないでください。
納品するファイルを探す
Workstation に切り替えます。初期ディレクトリは /home/labex/project/cafe-menu です。pwd は現在のディレクトリを、ls はその中の名前を表示します。
pwd
/home/labex/project/cafe-menu
ls
menu、brand、notes が見つかります。menu/ はお客様向けページ、brand/ はスタイルシートとイラストです。notes/ は制作側の資料なので、公開メニューに含めてはいけません。提供ファイルは変更しないでください。
サイトのアドレスは URL パスです。サーバーは /menu/flat-white.html を公開ディレクトリ内のファイルに対応させます。外側のソースフォルダー menu/ には、詳細ページ用の内側の menu/ ディレクトリがあります。両方のソースグループを確認します。
ls menu
ls brand
ページには index.html、visit.html、404.html と詳細ディレクトリがあります。ブランド用ファイルには site.css と 3 枚の .svg イラストがあります。SVG は画像形式です。ページは実行中サイトの /assets/ 配下にすべてのブランド用ファイルがあることを想定しています。
パッケージのレシピを書く
Docker はプログラムをコンテナで実行します。イメージはコンテナ作成に使う保存済みパッケージで、コンテナはそのイメージの実行中または停止中のインスタンスです。Docker はインストール済みです。準備済みの menu-base:1 には Web サーバー Nginx とページが見つからない場合の設定が含まれます。公開ディレクトリは /usr/share/nginx/html/ です。カフェメニューはまだ入っていません。
Dockerfile はイメージの作り方を記述します。FROM はベースイメージを選びます。COPY はファイルをイメージにコピーします。最初のパスはビルドディレクトリからの相対的なコピー元、2 番目はイメージ内のコピー先です。ディレクトリの内容を正しい場所にコピーすると、既存のリンクを保てます。実行中コンテナがソースディレクトリに接続されるわけではありません。
コピーを 2 回明示します。ページを公開ディレクトリへ、ブランド用ファイルをその assets/ へコピーします。これで制作メモを除外できます。Nginx のベースには起動コマンドがあるため、追加する必要はありません。
cat > Dockerfile は指定ファイルを後続のテキストで置き換えます。引用符付きの DOCKERFILE はヒアドキュメントの開始です。最後に単独行で置かれた DOCKERFILE も含め、ブロック全体を貼り付けてください。引用符により内容をそのまま保持します。Workstation で実行します。
cat > Dockerfile <<'DOCKERFILE'
FROM menu-base:1
COPY menu/ /usr/share/nginx/html/
COPY brand/ /usr/share/nginx/html/assets/
DOCKERFILE
cat はファイル表示にも使えます。ビルド前に保存したレシピを読み、2 つのコピー先を確認します。
cat Dockerfile
イメージをビルドして保存する
docker build はレシピを読み、イメージを作ります。-t は名前とタグを付けます。ここでは little-hour-menu が名前、1 が選択したバージョンラベルです。末尾の点は現在のディレクトリをビルドコンテキスト、つまり Docker がビルドに使えるファイルの範囲として指定します。タグは便利なラベルですが、内容が完全である証拠ではありません。
docker build -t little-hour-menu:1 .
出力は Docker のバージョンによって異なります。コマンドが成功し、little-hour-menu:1 を示すはずです。COPY が失敗したら、pwd、コピー元の名前、保存した Dockerfile を確認し、レシピを修正して同じビルドを実行します。パスの誤りを隠すために提供ページを置き換えたり、プロジェクト全体をコピーしたりしないでください。
これで納品用イメージが保存されました。メニューのコンテナはまだ起動していません。
イメージを実行中のメニューとして公開する
このステップでは自分のコンテナを作成し、サイトを開きます。Workstation から始めます。
コンテナをサイトのポートにつなぐ
Nginx はコンテナ内部のポート 80 で待ち受けます。ポートはネットワークサービスを識別します。Your Menu からアクセスできるよう、実験インスタンスのポート 8081 に公開します。ポート 8082 の見本サイトには影響しません。
docker run はコンテナを作成して起動します。-d はバックグラウンド実行にし、ターミナルを引き続き使えるようにします。--name cafe-menu は後で使う名前です。-p 8081:80 は実験側のポート 8081 をコンテナ側のポート 80 に対応させます。最後の引数はビルドしたイメージを選びます。ソースディレクトリもボリュームもマウントしません。
docker run -d --name cafe-menu -p 8081:80 little-hour-menu:1
長い出力は新しいコンテナの ID で、起動のたびに変わります。ID だけではアプリが動き続けている証拠になりません。docker ps は実行中コンテナを一覧表示します。
docker ps
cafe-menu、イメージ little-hour-menu:1、8081->80/tcp を含む対応を見つけてください。他の学習用コンテナが表示されても操作しません。
名前が使用済みなら、別名で大量のコピーを起動しないでください。docker ps で自分のコンテナを探し、正しければ続行します。終了していたりポート対応が間違っていたりする場合は、docker logs cafe-menu でサーバーメッセージを表示します。自分の静的メニューだけを交換するには、docker rm -f cafe-menu でそのコンテナを停止・削除します。イメージとソースは残ります。
レシピやポートを修正後、必要なら再ビルドし、元の docker run を再実行します。削除は交換が必要なときだけ行い、正常起動のたびに実行しないでください。
自分の納品サイトを開く
Your Menu に切り替えます。コンテナ起動前に開いていたら再読み込みします。完全なレイアウトとイラストを持つ LITTLE HOUR が表示されます。これはポート 8081 のサイトであり、用意された Reference Menu ではありません。

A few good favourites の Flat white を開きます。イラスト、価格、提供量、アレルゲン情報が必要です。Find us で営業時間を確認し、同じタブの LITTLE HOUR でホームへ戻ります。文字だけのホームページや壊れた画像では完全な納品になりません。
Topology に切り替えます。Menu homepage reachable と表示される場合があります。これは限られた観測であり、全ページの合格判定ではありません。次に納品の独立性と残りのお客様向けパスを確認します。
新しいコンテナとサイト全体を確認する
このステップではイメージから新しいインスタンスを起動し、制作側ディレクトリに依存せずに全体験を確認します。Workstation から始めます。
イメージとコンテナを区別する
コンテナを削除してもイメージは保存されたままです。このサイトにはお客様からの送信データやデータベースがないため、このコンテナの交換で業務データを失うことはありません。状態を持つアプリでは、この違いが重要になります。
ステップ 2 の交換コマンドで cafe-menu だけを削除します。
docker rm -f cafe-menu
同じ公開ポートで新しいインスタンスを起動します。
docker run -d --name cafe-menu -p 8081:80 little-hour-menu:1
別のコンテナ ID が表示されます。再ビルドも制作側ディレクトリのマウントもしていません。新しいインスタンスはイメージに格納済みのファイルを使います。
docker inspect はコンテナの実際の設定を表示します。--format はオブジェクト全体ではなく 1 つのフィールドを選びます。引用符付きテンプレートはマウント一覧を JSON に変換します。
docker inspect cafe-menu --format '{{json .Mounts}}'
[]
空のリストは、ホストディレクトリやボリュームのマウントがないことを示します。この演習で求める証拠です。ソースファイルが納品物の不足を裏で補っていません。マウントは他の場面では有効ですが、今回は自己完結した静的メニューが必要です。
実際のお客様向けパスをテストする
Your Menu に切り替えて再読み込みします。3 つのおすすめを順に選びます。Flat white は $4.00、Espresso は $3.00、Iced oat latte は $4.75 です。各詳細に正しい画像と情報が必要です。毎回 LITTLE HOUR でホームに戻ります。Find us で平日の営業時間 08:00–17:00 を確認します。Your Menu 内で操作してください。Reference Menu は別サーバーのテストになります。

Workstation に切り替えます。HTTP はブラウザーが使うリクエストとレスポンスのプロトコルです。成功レスポンスは 200、404 は要求したリソースが見つからないことを示します。接続失敗は別物で、有効なサーバーレスポンスを受信していません。
curl はリクエストを送ります。-sS は進捗を隠し、接続エラーは表示します。-o /dev/null は本文を捨てます。-w は引用符内の形式を出力し、%{http_code} がステータス、\n が改行です。Workstation 内の 127.0.0.1 は実験インスタンスを指します。自分のパソコンのターミナルから実行しないでください。
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/menu/flat-white.html
200 が表示されます。先のブラウザー確認で内容とイラストも確かめています。間違ったページを返す 200 だけでは不十分です。
制作メモは公開してはいけません。想定される URL を要求します。
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/notes/launch-notes.txt
期待値は 404 です。パッケージの境界として意図した成功です。HTTP エラーレスポンスで失敗する指定をしていないため、curl 自体は正常終了します。サイト全体を停止しても、動作するメニューの要件は満たせません。
Your Menu に戻り、LITTLE HOUR でホームに戻ります。メモのリクエストを拒否した後も通常のメニューは動く必要があります。お客様向け内容の完全性と、納品対象ではないリソースに対する適切な応答を確認できました。
まとめ
完全な静的メニューイメージをビルドし、サーバーポートを公開し、ソースのマウントなしで新しいコンテナを起動しました。実際のページ、画像、来店情報を確認し、制作メモは公開サイトから除外しました。次の独立したチャレンジでは、異なるソース構成のベーカリーに同じ判断を応用します。



