DockerでWebサーバーを立てて片付けるまでを通しでやってみよう(総合演習)
ここまでの Docker レッスンで学んだコマンドをひとつの流れにつないで、コンテナの一生を最後まで見届けます。
やることは「イメージを取得する → コンテナとして起動する → 動いているか確かめる → 止めて片付ける」。Dockerを使う日は、ほぼ毎日この順序をなぞることになります。
この4つが手に馴染むと、Dockerは急に怖くなくなります。コンテナは壊れたら消して作り直せばよい——その感覚が身につくのが、この演習のいちばんの狙いです。
ページの一番下に本物の疑似ターミナルがあります。読むだけで終わらせず、必ず自分で打ってみてください。状態はコマンドをまたいで続くので、上から順に打てばそのまま完走できます。
完成イメージ
最後まで進むと、こう表示されるところまで作ります。下の実行結果は、このページを作るときに実際にコードを走らせて得たものです。
$ docker ps -a CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE
STEP 1手元を確かめて、イメージを取ってくる
🎯 このステップのゴール: docker images で「まだ何も無い」ことを見てから、nginx のイメージを取得する
まずdocker --versionで、Dockerが動いていることを確かめます。これが返らないときは、Dockerそのものが起動していません。
次がdocker images。手元にあるイメージの一覧で、いまは見出しだけで中身が空です。この「空の状態」を先に見ておくのが大事で、次のコマンドで何が増えたのかがはっきり分かります。
docker pull nginxで、Webサーバーの公式イメージを取ってきます。イメージは「設計図」、コンテナは「そこから起動した実物」——この2つの区別が、Dockerを理解する土台になります。
取得の途中でPull completeやDigestが流れます。イメージは層(レイヤー)の積み重ねでできており、すでに持っている層は再取得されません。2回目以降が速いのはこのためです。
もう一度docker imagesを打つと、nginx が1件だけ増えています。まだ起動はしていません。設計図を手に入れただけの状態です。
docker --version docker images docker pull nginx docker images
$ docker --version Docker version 24.0.7, build afdd53b Docker Compose version v2.24.5 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE $ docker pull nginx latest: Pulling from library/nginx a1b2c3d4e5f6: Pull complete Digest: sha256:00009e3779b1... Status: Downloaded newer image for nginx:latest $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 00009e3779b1 数秒前 142MB
STEP 2コンテナとして起動して、外から見えるようにする
🎯 このステップのゴール: docker run に -d・--name・-p を付けて、名前の付いたコンテナを裏で動かす
いよいよ起動です。docker run -d --name web -p 8080:80 nginx——3つのオプションにそれぞれ役割があります。
-dは「裏で動かす」。付けないとログが画面に流れ続け、そのターミナルが使えなくなります。動かし続けるものには、ほぼ必ず付けます。
--name webは名前付けです。付けないとDockerがvibrant_einsteinのような名前を勝手に付けます。以降のコマンドをすべてwebという名前で指定できるので、付けておくと後が楽になります。
-p 8080:80が、この演習でいちばん間違えやすいところです。左がパソコン側、右がコンテナ側。「パソコンの8080番に来た通信を、コンテナの80番へ渡す」という意味で、逆に書くと繋がりません。
返ってきた長い英数字がコンテナIDです。docker psで確認すると、STATUS が running、PORTS に 8080:80と出ています。ここまで来れば、ブラウザでlocalhost:8080を開けばnginxの画面が見える状態です。
docker run -d --name web -p 8080:80 nginx docker ps
$ docker run -d --name web -p 8080:80 nginx 00003c6ef362 $ docker ps CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES 00003c6ef362 nginx:latest (image既定のコ running 8080:80 web
STEP 3本当に動いているのか、中を覗いて確かめる
🎯 このステップのゴール: docker logs と docker top で、コンテナの中で何が起きているかを見る
-dで裏に回したので、画面には何も出てきません。動いているかどうかを知る手段が要ります。
docker logs webが最初の一手です。コンテナの中のプログラムが出力した内容が読めます。listening on port 80と出ていれば、nginxはちゃんと待ち受けています。
うまく動かないときも、まずここを見ます。設定ファイルの書き間違いも、必要なファイルが無いことも、たいていログに出ています。「起動したのにすぐ終わる」ときは、docker ps -aで見つけてからdocker logs——これが調査の型です。
docker top webでは、コンテナの中で動いているプロセスが見えます。nginxのマスタープロセスとワーカープロセスが並んでいます。
ここにコンテナの正体が現れています。コンテナの中のプロセスは、ホストから見れば普通のプロセスです。仮想マシンのように別のOSが丸ごと動いているわけではなく、隔離されているだけ——だからコンテナは数秒で起動します。
docker logs web docker top web
$ docker logs web [notice] nginx:latest を起動しました [notice] listening on port 80 [info] Ready to accept connections $ docker top web UID PID PPID CMD root 1234 1 nginx: master process root 1256 1234 nginx: worker process
STEP 4起動時の設定を読み、ファイルを送り込む
🎯 このステップのゴール: docker inspect で設定を確かめ、docker cp で手元のファイルをコンテナへ渡す
docker inspect webは、そのコンテナの設定をすべて表示するコマンドです。IDや元になったイメージ、いまの状態が読み取れます。
これが必要になる理由があります。ポートの公開も名前も、docker runを打った瞬間に固定されます。あとから変えることはできません。だから「このコンテナはどんなオプションで起動したのか」を後から知る手段が要るのです。
実際の出力は数百行になるので、実務では--formatで必要な項目だけを取り出します。
次にdocker cpで、手元のindex.htmlをコンテナの中に送り込みます。nginxが公開しているフォルダに置けば、ブラウザに映る内容が自分のページに変わります。
ただし、この方法は覚え書きにしないでください。docker cpで入れたファイルは、コンテナを作り直すと消えます。本来はDockerfileのCOPYで焼き込むか、-vで外のフォルダを繋ぎます。どちらも「作り直しても同じ結果になる」やり方です。手作業で中身を直した環境は、再現できません——これはDockerを使う意味そのものに関わる話です。
docker inspect web docker cp ./index.html web:/usr/share/nginx/html/
$ docker inspect web
[
{
"Id": "00003c6ef362",
"Name": "/web",
"Image": "nginx:latest",
"State": { "Status": "running" }
}
]
$ docker cp ./index.html web:/usr/share/nginx/html/
./index.html を web:/usr/share/nginx/html/ にコピーしました
STEP 5止めて、また動かす
🎯 このステップのゴール: stop と start の違い、そして「止めても消えていない」ことを目で確かめる
docker stop webで停止します。いきなり切るのではなく、まず「終わってください」という合図を送り、10秒待ってから強制終了します。この猶予のあいだに、コンテナの中のプログラムは書きかけのファイルを保存したり、接続を閉じたりできます。
止めた直後にdocker psを打つと、何も出てきません。ここで「消えた」と思うのが、Dockerを始めた人がまず引っかかる場所です。
docker ps -aを打ってください。-aを付けると、停止中のものも含めて全部が出ます。webはexitedという状態で、ちゃんと残っています。
コンテナは停止しても消えません。中のファイルもログもそのままです。だから落ちたコンテナのログを後から読める——さっき見たdocker logsが、失敗の調査に使える理由がこれです。
docker start webで再開します。停止する前の状態がそのまま戻ります。docker runとの違いがここで、runは毎回新しいコンテナを作り、startは既にあるものを動かし直します。何度もrunを打つと停止したコンテナが溜まっていくのは、この違いを知らないときに起こります。
docker stop web docker ps docker ps -a docker start web docker ps
$ docker stop web web $ docker ps CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES $ docker ps -a CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES 00003c6ef362 nginx:latest (image既定のコ exited (0) 8080:80 web $ docker start web web $ docker ps CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES 00003c6ef362 nginx:latest (image既定のコ running 8080:80 web
STEP 6きれいに片付けて完了
🎯 このステップのゴール: コンテナとイメージを順に削除し、最初の空の状態に戻す
最後は片付けです。順序に決まりがあります。
動いているコンテナは削除できません。まずdocker stop webで止め、それからdocker rm webで消します。
ここで何が失われるかを、はっきり意識してください。docker rmすると、そのコンテナの中で作ったファイルも、さっきdocker cpで送り込んだファイルも、全部消えます。コンテナは「イメージの上に載った書き込み層」で動いていて、削除するとその層ごと捨てられるからです。残したいデータは、あらかじめボリュームで外に置いておく必要があります。
次にdocker rmi nginxでイメージを消します。rmiはremove imageの略です。コンテナが残っているとイメージは消せません——だからコンテナが先、イメージが後、という順序になります。
最後にdocker ps -aとdocker imagesで確かめます。どちらも見出しだけ——ステップ1で見た、あの空の状態に戻りました。
これで完走です。取得 → 起動 → 確認 → 停止 → 削除。この一周を自分の手で回せたなら、Dockerの日常操作はもう扱えます。あとはDockerfileで自分のイメージを作る、Composeで複数のコンテナをまとめて動かす——どちらもこの一周の上に乗っているだけです。
ページ下の疑似ターミナルで、ここまでを最初から自分の手で通してみてください。読んで分かるのと打てるのは、別物です。
docker stop web docker rm web docker rmi nginx docker ps -a docker images
$ docker stop web web $ docker rm web web $ docker rmi nginx Untagged: nginx:latest Deleted: sha256:00009e3779b1... $ docker ps -a CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE
仕上げ自分で最初から打ってみよう
🎯 このステップのゴール: ここまでの流れを、自分の手で最後まで通す
下は本物の疑似ターミナルです。まっさらな状態から始まるので、STEP1のコマンドから順に打って、マージまで辿り着いてください。読んで分かった気になるのと、自分で打てるのとは別物です。
詰まったら上のステップに戻って構いません。resetと打てば最初からやり直せます。
よくある質問
コンテナIDがページと違います
それで正常です。コンテナIDもイメージIDも、起動のたびに新しく作られます。このページに載っているIDは、生成時に実際に実行して得たものをそのまま載せているだけで、あなたの手元と一致する必要はありません。
止めたのにディスクの空きが増えません
停止と削除は別物だからです。docker stopはプログラムを止めるだけで、コンテナ本体もイメージもディスクに残ります。
本当に消したいならdocker rm(コンテナ)とdocker rmi(イメージ)まで進めます。溜まったものをまとめて片付けるならdocker system pruneですが、--volumesを付けるとデータごと消えて戻せません。実行する前にdocker system dfで何がどれだけ使っているかを見てください。
ブラウザで localhost:8080 を開いても表示されません
まずdocker psでPORTS列を見てください。ここが空欄なら、-pを付け忘れています。コンテナは隔離されたネットワークにいるので、この指定が外から届く唯一の入口です。
PORTSが出ているのに繋がらないなら、左右を逆に書いていないかを確認します。-p 8080:80の左がパソコン側、右がコンテナ側です。
それでも駄目ならdocker logsです。コンテナ自体が起動直後に落ちていることがあります。
この演習では Dockerfile を書かないんですか?
この疑似ターミナルにはエディタが無いため、ここでは公式イメージをそのまま動かす構成にしています。
Dockerfileの書き方はレッスン側で扱っています。FROMで土台を選び、COPYでファイルを入れ、CMDで起動時のコマンドを決める——そこまで進むと、この演習で使ったdocker runを自分で作ったイメージに対して打てるようになります。
🚩 次はこのカテゴリへ
コンテナを手元で動かせるようになったら、次はそれを置く場所です。AWSカテゴリでは、サーバーを借りる、ファイルを置く、権限を渡す、といったクラウドの基本操作をコマンドで練習できます。Dockerで作ったものを世に出すとき、必ず通る道です。
AWSコマンドのレッスンへ進む