Docker で最初に覚える5つのコマンド
よるほろぐ編集部
Docker は、アプリケーションと依存関係をイメージから隔離したプロセスとして動かす仕組みです。docker run を打つたびに「何が作られ、いつ消えるのか」を追えるようになると、コマンドを暗記するより先に扱い方が身につきます。
この記事では、ほかのコンテナに触れない itnote-nginx-lifecycle という練習用コンテナを一つだけ使います。run、ps、exec、stop、rm の5コマンドを、作成から削除までの一つのライフサイクルとして試しましょう。logs と inspect は、外から動作を観察するための補助コマンドです。
始める前に Docker Engine へ接続できるか確かめる
以下は Bash または zsh を想定しています。Docker CLI が入っているだけではコンテナを起動できないため、まず Docker Engine(Server)まで応答するかを確認します。
docker version
出力に Client と Server の両方があれば、この練習を始められます。docker --version は CLI 自体の版だけを表示するため、Engine への接続確認にはなりません。
Cannot connect to the Docker daemon のようなエラーになった場合は、Docker Engine または Docker Desktop が起動していない、あるいは現在の Docker context が接続先を指していない状態です。先へ進まず、利用している環境の Docker Engine 起動方法と context を確認してください。
練習用の名前を予約する
コンテナ名は Docker の中で重複できません。普段の開発用コンテナと衝突しにくい、この記事専用の名前をシェル変数に入れます。
CONTAINER=itnote-nginx-lifecycle
docker ps -a --filter "name=$CONTAINER" \
--format 'table {{.Names}}\t{{.Status}}'
何も行が出なければ、その名前は使えます。すでに行が出た場合、所有者や用途が分からないコンテナを削除してはいけません。自分で前回の練習として作ったものだと確認できるなら、後述の停止・削除の手順をその名前だけに対して実行します。確認できないときは itnote-nginx-lifecycle-2 のような別名を CONTAINER に設定し、以降のコマンドは同じシェルで実行してください。
run で localhost 専用の Nginx を作成する
ここでは Alpine Linux ベースの nginx:alpine イメージを使います。-d はバックグラウンド起動、--name は後続操作に使う名前です。-p 127.0.0.1:8080:80 は、ホストの loopback アドレスの 8080 番だけをコンテナの 80 番へ公開します。単に -p 8080:80 とすると、環境によっては外部ネットワークから到達できるアドレスにも公開されるため、練習では明示的に localhost に限定します。
docker run -d \
--name "$CONTAINER" \
-p 127.0.0.1:8080:80 \
nginx:alpine
初回はイメージの取得後に長いコンテナ ID が表示されます。次にブラウザで http://127.0.0.1:8080/ を開くか、curl がある環境では次を実行します。
curl --fail http://127.0.0.1:8080/
Nginx の初期ページの HTML が返り、終了状態が 0 なら、ホストからコンテナへの経路はできています。Bind for 127.0.0.1:8080 failed: port is already allocated と表示されたときは、8080 番を別のプロセスが使っています。コンテナ側の 80 は変えずに、-p 127.0.0.1:18080:80 のようにホスト側だけを空いている番号へ変更し、アクセス先も http://127.0.0.1:18080/ にそろえます。
ps、logs、inspect で外から状態を観察する
docker ps は既定で実行中のコンテナだけを表示します。名前で絞ると、ほかの作業中のコンテナを一覧から選んでしまう心配がありません。
docker ps --filter "name=$CONTAINER"
STATUS が Up ...、PORTS が 127.0.0.1:8080->80/tcp(ホスト側を変更した場合はその番号)なら期待どおりです。停止後も確認するときだけ docker ps -a --filter "name=$CONTAINER" を使います。
リクエストを送ったあと、Nginx が標準出力・標準エラーに出したログを確認します。
docker logs --tail 10 "$CONTAINER"
標準的な Nginx の設定では、先ほどの GET / に対応するアクセスログが末尾に現れます。docker logs はコンテナの画面を再現するコマンドではなく、設定されたログドライバーが保持する標準出力・標準エラーを取得するものです。アプリケーションが応答しないときは、まずここで起動エラーを探す習慣をつけると原因を切り分けやすくなります。
ポート公開の実際の設定は inspect でも確認できます。
docker inspect \
--format '{{json .NetworkSettings.Ports}}' \
"$CONTAINER"
出力には 80/tcp に対応する HostIp と HostPort が JSON で現れます。HostIp が 127.0.0.1、HostPort が選んだホスト側ポートなら、意図した限定公開になっています。inspect は詳細な JSON 全体も返せますが、最初は欲しい項目だけを format で抜き出す方が読みやすくなります。
exec で実在する shell から内部を見る
exec は実行中のコンテナの中で別のプロセスを起動します。このイメージは Alpine Linux ベースなので、対話シェルには bash ではなく存在する /bin/sh を指定します。
docker exec -it "$CONTAINER" /bin/sh
プロンプトが変わったら、次を順に実行してください。
cat /etc/os-release
nginx -T
exit
cat /etc/os-release では Alpine Linux であることを、nginx -T では読み込まれている Nginx 設定を確認できます。exit はこの shell だけを終了し、Nginx の本体プロセスは動き続けます。docker exec -it "$CONTAINER" bash で executable file not found になるのは、最小構成の Alpine イメージに bash が含まれないためです。exec 自体も、コンテナの主プロセスが動いている間だけ実行できます。
stop して停止後の状態を残す
観察が済んだら、対象を名前で明示して停止します。
docker stop "$CONTAINER"
docker ps -a --filter "name=$CONTAINER"
最初のコマンドはコンテナ名を返します。次の出力で STATUS が Exited ... になれば成功です。Docker は主プロセスに停止シグナルを送り、終了を待ってから必要に応じて強制終了します。この段階ではコンテナの定義、書き込みレイヤー、ログなどがまだ残るため、docker logs "$CONTAINER" や docker inspect "$CONTAINER" を再確認できます。
この練習で docker stop $(docker ps -q) のような全件停止は使いません。自分の作業と無関係なコンテナまで止める危険があるからです。常に "$CONTAINER" のように対象を一つに絞ります。
rm で練習用コンテナだけを削除する
停止を確認してから、同じ名前だけを削除します。
docker rm "$CONTAINER"
docker ps -a --filter "name=$CONTAINER"
docker rm が名前を返し、続く一覧に対象の行がなければライフサイクルは完了です。実行中のコンテナに docker rm -f を使うと主プロセスが強制終了されるため、通常の終了手順としては選びません。また、全コンテナを対象にする docker container prune、シェル展開した一括 rm、docker image prune -a も、このような一点だけの練習や共有環境の掃除には不向きです。
docker run → running → docker stop → exited → docker rm → removed
│
├─ docker ps / logs / inspect で外から観察
└─ docker exec /bin/sh で内部を確認
—rm とボリュームの削除範囲を区別する
今回の run に --rm を付けなかったのは、停止状態を ps -a、logs、inspect で観察してから、自分の意思で rm するためです。--rm を付けたコンテナは、主プロセスが終了したときに自動削除されます。短い一回限りの処理には便利ですが、停止後のコンテナを調べる余地は残りません。
コンテナを rm すると、そのコンテナの書き込みレイヤーに置いたデータは消えます。一方、名前付きボリュームを -v itnote-data:/data のように明示してマウントしていた場合、コンテナを削除しても名前付きボリュームは残ります。docker rm -v や --rm が対象にするのは関連する匿名ボリュームであり、名前付きボリュームを消すには docker volume rm itnote-data を別途、用途を確認してから実行します。永続データの置き場と削除境界は、Docker のボリュームとネットワークの記事で詳しく扱っています。
この練習の次に読む Docker 連載
この記事の役割は、一つのコンテナを安全に作成・観察・削除する操作の土台です。アプリケーション用のイメージを自作する手順、データとネットワークの設計、複数コンテナの定義、イメージの最適化は、それぞれ Docker 連載で扱います。
- Dockerfile の書き方入門:自分のアプリをコンテナイメージにする
- Docker のボリュームとネットワーク:データ永続化とコンテナ間通信
- Docker Compose で複数コンテナを管理する:1ファイルで環境を再現
- Docker イメージを軽くする:マルチステージビルドと最適化テクニック