情報工学徹底攻略実験とレポートの私的学習ガイド

レポート課題33日目・180分T3情報工学3_[学生番号]_[氏名].pdf

3日目 Dockerとコンテナ

アプリをまるごと箱に詰めて動かす「コンテナ」の仕組みを導入します。まず1個の箱を手で動かし、次に箱の構成を設定ファイルに書いてまとめて動かす方法(Docker Compose)を体験します。4日目以降のWebサーバーやAIは、すべてこの方法で動かします。

この日のゴール

  • Dockerが入り、サービスとして自動で動いている
  • docker run で、1個のコンテナを起動・終了できる
  • compose.yaml に書いた構成を docker compose で起動・確認・停止できる
  • 起動した練習用Webサーバーに、サーバーの中からもWindowsからもアクセスできる

この日から、Ubuntuの操作はすべて Windows 11 ターミナル(SSH接続) で行います。Windowsのターミナルから ssh t3admin@192.168.100.xxx で入ってから始めてください。

この日に出てくる主な言葉:

コンテナとは:仮想マシンとの違い

1日目に作った仮想マシンは、ハードウェアを丸ごとまねて、その上でOSを1つまるごと動かす仕組みでした。コンテナはもっと身軽で、OSの中心部分(カーネル)はホストのものを共有し、アプリとその動作に必要な部品だけを箱に詰めて、ほかから隔離して動かします。

仮想マシン(ハイパーバイザ型) ハードウェア ハイパーバイザ 仮想マシン1 仮想マシン2 アプリA アプリB 部品(ライブラリ) 部品(ライブラリ) ゲストOSカーネルごと丸ごと ゲストOSカーネルごと丸ごと コンテナ(コンテナ型) ハードウェア ホストOS(カーネルをみんなで共有) Docker(コンテナを動かす係) コンテナ1 コンテナ2 アプリA アプリB 部品(ライブラリ) 部品(ライブラリ)
図1仮想マシンとコンテナの構造の違い。仮想マシンは1台ごとにOS(カーネル)を丸ごと持つ。コンテナはホストのカーネルを共有し、アプリと必要な部品だけを箱に詰めるので、軽く、すぐ起動する。この実験では、仮想マシン(Proxmox上のUbuntu)の中でコンテナを動かしているので、両方が入れ子になっている。

課題1はまさにこの違いを問うものです。図を丸写しするのではなく、「何を共有し、何を分けているか」「その結果、起動の速さ・大きさ・隔離の強さがどう変わるか」を自分の言葉で説明できるようにしておきましょう。考察のヒント比べるときは「何を共有し、何を分けているか」を軸にします。共有するものが多いほど軽く速くなる一方、隔離は弱くなります。起動の速さ・大きさ・隔離の強さ・動かせるOSの自由度を三線表で比べると、課題1を整理しやすくなります。

イメージとコンテナ

Dockerでは、2つの言葉を区別します。

イメージ
コンテナのひな形。アプリと部品と設定を固めたもの。料理でいえば「レシピと材料のセット」
コンテナ
イメージから作って実際に動かしているもの。「そこから作った料理」。1つのイメージから何個でも作れる

イメージはレジストリと呼ばれるインターネット上の倉庫で配布されていて、手元にないイメージは、初めて使うときに自動でダウンロード(pull)されます。代表的な倉庫が Docker Hub です。nginx:stable のように、コロンの後ろに版を示すタグを付けて指定します。タグを書かなければ latest(最新)が使われます。

手順の解説

スクリーンショット(エビデンス)を撮るところ。マウスを乗せると撮るタイミングが表示され、押すとページ下のエビデンス一覧の該当項目へ移動します。考察を書くときに知っておきたいこと。マウスを乗せる(スマホでは押す)とヒントが表示されます。

2.1 Docker単体の基本操作

手順 1Windows 11 ターミナル(SSH接続)

Dockerを入れる

Windows 11 ターミナル(SSH接続)bash
sudo apt update
sudo apt install -y docker.io docker-compose-v2

docker.io はUbuntuが配布しているDocker本体のパッケージ、docker-compose-v2 は docker compose コマンドを使えるようにする追加部品です。

手順 2Windows 11 ターミナル(SSH接続)

Dockerのサービスを有効にする

Windows 11 ターミナル(SSH接続)bash
sudo systemctl enable --now docker
sudo systemctl status docker
docker --version

Dockerは、裏で動き続ける係(dockerd というサービス)と、私たちが打つ docker コマンドの2つに分かれています。コマンドは係に「このコンテナを動かして」と頼むだけで、実際の作業は係がします。status で active (running)、--version で版が表示されれば準備完了です。エビデンス1の撮影ポイント撮影ポイント エビデンス1手順2で sudo systemctl status docker と docker --version を実行した直後。active (running) と版の表示が1画面に入るように撮る(status の表示が長いときは q で抜けてから --version を打つ)。エビデンス一覧の項目へ移動 ↓

手順 3Windows 11 ターミナル(SSH接続)

1個のコンテナを動かしてみる

Windows 11 ターミナル(SSH接続)bash
sudo docker run --rm hello-world
sudo docker管理者の権限でDockerに
runイメージからコンテナを作って動かせ
--rm終わったらコンテナを消す
hello-world使うイメージの名前

初回は手元にイメージがないので、まず Unable to find image 'hello-world:latest' locally(手元に見つからない)と出てから、倉庫からダウンロードされます。そのあと Hello from Docker! で始まるメッセージが表示されれば成功です。エビデンス2の撮影ポイント撮影ポイント エビデンス2手順3で sudo docker run --rm hello-world を実行した直後。Hello from Docker! のメッセージが見えるように撮る。初回のダウンロードの表示(Unable to find image …)も写っていると、何が起きたかを説明しやすい。エビデンス一覧の項目へ移動 ↓メッセージの中には、今起きたことが英語で説明されています。考察のヒントhello-world を動かすためにあなたがインストールしたのは Docker だけでした。アプリの動作に必要なものがすべてイメージに入っているからで、課題2(配布と環境再現の利点)の具体例になります。

  1. docker コマンドが、裏の係(Dockerデーモン)に連絡した
  2. 係が Docker Hub から hello-world のイメージを取ってきた
  3. 係がそのイメージから新しいコンテナを作り、中のプログラムを動かした
  4. プログラムが出したメッセージを、係がターミナルに届けた

なぜ毎回 sudo を付けるのか

Dockerの係は管理者(root)の権限で動いていて、docker コマンドを使える人は、実質的にサーバーの管理者と同じことができてしまいます。指導書が docker の前に必ず sudo を付けているのは、この強い権限を使う操作であることをはっきりさせるためと考えられます。付け忘れると permission denied while trying to connect to the Docker daemon socket と表示されます。

手順 4Windows 11 ターミナル(SSH接続)

コンテナとイメージの一覧を見る

Windows 11 ターミナル(SSH接続)bash
sudo docker ps -a
sudo docker images
docker ps -a
コンテナの一覧。-a を付けると、止まっているものも含めてすべて表示する。STATUS 欄が Up … なら動作中、Exited … なら終了済み
docker images
手元にあるイメージの一覧。REPOSITORY(名前)、TAG(版)、SIZE(大きさ)などが並ぶ

手順3では --rm を付けたので、hello-world のコンテナは終了と同時に消え、ps -a には出てこないことがあります。一方、イメージは残るので docker images には表示されます。「コンテナは消えても、ひな形は残る」ことが分かります。考察のヒントひな形(イメージ)と実体(コンテナ)を分けて管理しているから、コンテナを消しても同じものを何度でも作り直せます。環境の再現性を論じるときの根拠になります。エビデンス3の撮影ポイント撮影ポイント エビデンス3手順4で sudo docker ps -a と sudo docker images を続けて実行した直後。ps -a が空でも、images に hello-world が表示されていればよい。エビデンス一覧の項目へ移動 ↓

2.2 Docker Composeで構成を管理する

docker run では、設定をすべてコマンドの後ろに並べて打ちます。コンテナの数や設定が増えると、長いコマンドを毎回正確に打つのは大変です。Docker Composeは、その設定をcompose.yamlというファイルに書いておき、docker compose up の一言で、書いたとおりの構成を立ち上げる道具です。

手順 5Windows 11 ターミナル(SSH接続)

Composeが使えることを確かめる

Windows 11 ターミナル(SSH接続)bash
sudo docker compose version

Docker Compose version v2.… のように表示されれば使えます。エビデンス4の撮影ポイント撮影ポイント エビデンス4手順5で sudo docker compose version を実行した直後。版の表示が写っていればよい。エビデンス一覧の項目へ移動 ↓

手順 6Windows 11 ターミナル(SSH接続)

作業用のディレクトリを作る

Windows 11 ターミナル(SSH接続)bash
sudo mkdir -p /opt/compose-demo
cd /opt/compose-demo

/opt は追加のソフトを置く慣習的な場所です。Composeのコマンドは、compose.yaml があるディレクトリで実行するのが基本なので、構成ごとにディレクトリを分けます。

手順 7Windows 11 ターミナル(SSH接続)

compose.yaml を書く

Windows 11 ターミナル(SSH接続)bash
sudo nano /opt/compose-demo/compose.yaml
ファイルの中身/opt/compose-demo/compose.yamlyamlエディタで書く内容(ターミナルに打ち込まない)
services:
  web:
    image: traefik/whoami
    container_name: compose-whoami
    ports:
      - "8080:80"
    restart: unless-stopped

SSHで接続しているので、このガイドの「コピー」ボタンでコピーし、nanoの画面に貼り付けられます(Ctrl+Shift+V)。1日目と同じYAMLなので、字下げの数に気をつけます。

表1compose.yaml の各行の意味
行意味
services:ここから、動かすサービス(コンテナ)の一覧
web:サービスにつけた名前(自分で決めてよい)
image: traefik/whoami使うイメージ。whoami は、受け取ったリクエストの中身と自分の情報をそのまま返すだけの小さな練習用Webサーバー
container_name: compose-whoami作るコンテナの名前
ports: - "8080:80"Ubuntuの8080番に来た通信を、コンテナの80番へ渡す(ポート公開)
restart: unless-stopped自分で止めない限り、落ちても、サーバーを再起動しても、自動で起動し直す(再起動ポリシー(restart))考察のヒント再起動ポリシーがあると、夜中にサーバーが再起動しても、人の手を介さずにサービスが戻ります。課題3は、運用する人の立場(止まったときに誰が何をしなければならないか)から考えると書きやすくなります。
手順 8Windows 11 ターミナル(SSH接続)

確かめてから起動する

Windows 11 ターミナル(SSH接続)bash
cd /opt/compose-demo
sudo docker compose config
sudo docker compose up -d
sudo docker compose ps
config
compose.yaml を読み取り、解釈した結果を表示する。書き間違いがあれば、ここでエラーになる。起動前の点検考察のヒント「反映する前に検査する」考え方は、sshd -t、named-checkconf、nginx -t など、この実験に何度も出てきます。共通する目的をまとめておくと、複数の課題の考察で使えます。
up -d
書いたとおりに構成を立ち上げる。-d(デタッチ)は「裏で動かして、ターミナルはすぐ返して」という意味。初回はイメージのダウンロードが入る
ps
この構成のコンテナの状態。STATUS が Up、PORTS に 0.0.0.0:8080->80/tcp のように出ていれば、8080番がコンテナの80番につながっている

config と ps の画面がエビデンス5です。エビデンス5の撮影ポイント撮影ポイント エビデンス5手順8で up -d のあとに ps を実行した時点。config の解釈結果と、ps の STATUS(Up)と PORTS(0.0.0.0:8080->80/tcp)が見えるように撮る。長くて1画面に入らなければ2枚に分ける。エビデンス一覧の項目へ移動 ↓

手順 9Windows 11 ターミナル(SSH接続)

サーバーの中からアクセスする

Windows 11 ターミナル(SSH接続)bash
curl http://localhost:8080
sudo docker compose logs --tail 20

curlはURLにアクセスして、返ってきた中身を表示するコマンドです。localhost は「この機械自身」を指すので、サーバーの中から自分の8080番にアクセスしています。エビデンス6の撮影ポイント撮影ポイント エビデンス6手順9で curl http://localhost:8080 を実行した直後(サーバー側からのアクセス)。エビデンス6は「サーバー側とクライアント側の両方から届く」ことを示すものなので、手順10または11のクライアント側の画面と組にして載せる。エビデンス一覧の項目へ移動 ↓

画面の表示例curl の結果の例打ち込むものではなく、表示の例
Hostname: 5f3c2b1a9d8e
IP: 127.0.0.1
IP: ::1
IP: 172.18.0.2
RemoteAddr: 172.18.0.1:40912
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.5.0
Accept: */*
Hostname
コンテナの中から見た自分の名前(コンテナIDの短縮形)
IP
コンテナに割り当てられたアドレス。172.18.0.2 のような番号は、Dockerがコンテナ用に作った内部のネットワークのもの
RemoteAddr
コンテナから見た、アクセスしてきた相手
GET / HTTP/1.1 以下
curlが送ったリクエストの中身そのもの(4日目のHTTPで詳しく学ぶ)

logs --tail 20 は、この構成のコンテナが出したログの最後の20行です。

手順 10Windows 11 ターミナル

Windowsから届くか確かめる

Windows 11 ターミナルpowershell
Test-NetConnection 192.168.100.xxx -Port 8080

TcpTestSucceeded : True になるはずです。ここで「あれ?」と思えたら鋭いです。2日目のufwでは22番しか許可していないのに、8080番につながるのはなぜでしょうか。

Dockerが公開したポートは、ufwの設定をすり抜ける

Dockerは、ports: で公開したポートへの通信をコンテナに届けるために、Linuxの通信の振り分けの規則を自分で書き加えます。この規則は、ufwが通信を調べるよりも前の段階で働くため、ufwで許可していなくても、外からコンテナにつながります。Docker自身の公式の説明でも、ufwと組み合わせるとこうなることが注意されています。

つまり、Dockerを使うときは「ufwで閉じているから安全」とは言えず、ports: に何を書くかそのものが、外に窓口を開ける操作になります。4日目の80番も同じ理由で、ufwで許可しなくても外から見えます。2日目の課題1(不要なポートの危険性)や、このあとの課題3(ポート公開を定義する利点)の考察につながる大事な観察です。考察のヒントファイアウォールで閉じていても、ports: に書いたポートは外から届きます。つまり compose.yaml を見れば外に開いている窓口が分かる、とも言えます。課題3の利点を「安全の確認のしやすさ」から論じる材料になります。

手順 11Webブラウザ

ブラウザで開く

WindowsのブラウザでURL欄に http://192.168.100.xxx:8080 と入れると、手順9と同じような文字の画面が表示されます。User-Agent がブラウザの名前に、RemoteAddr がWindows PCのアドレスに変わっているはずです。サーバーの中から見たときと、何が同じで何が違うかを比べると、考察の材料になります。エビデンス6の撮影ポイント撮影ポイント エビデンス6手順11でブラウザに whoami の応答が表示された時点(クライアント側からのアクセス)。URL欄の http://192.168.100.xxx:8080 も写るように撮る。手順12の down より前に撮ること。エビデンス一覧の項目へ移動 ↓

手順 12Windows 11 ターミナル(SSH接続)

止めて片付ける

Windows 11 ターミナル(SSH接続)bash
cd /opt/compose-demo
sudo docker compose down
sudo docker compose ps

down は、この構成のコンテナを止めて削除します。ps の一覧が空になれば片付け完了です。compose.yaml は残っているので、もう一度 up -d すれば、同じ構成がすぐに再現できます。この「何度でも同じものが立ち上がる」ことが、Composeを使ういちばんの価値です。考察のヒント毎回コマンドを手で打つ場合と比べて、打ち間違い・人への引き継ぎ・変更の記録がどう変わるかを考えると、課題3の中心が書けます(Infrastructure as Code(IaC))。

片付けておかないと、8080番が開いたまま残ります(ufwをすり抜けるのは上で見たとおりです)。

ポート公開の仕組み(まとめ)

Windowsのブラウザ :8080 へ Ubuntu(ホスト) 192.168.100.xxx 8080番 コンテナ compose-whoami 80番 whoami ports: "8080:80" curl http://localhost:8080 サーバーの中から自分自身へ (手順9)
図2ポート公開の仕組み。"8080:80" の左がホスト(Ubuntu)のポート、右がコンテナのポート。Windowsからでも、Ubuntuの中からでも、8080番に来た通信はコンテナの80番に渡される。

結果と考察のための確認コマンド

Windows 11 ターミナル(SSH接続)bash
docker --version
sudo systemctl status docker
sudo docker run --rm hello-world
sudo docker ps -a
sudo docker images
sudo docker compose version
cd /opt/compose-demo
sudo docker compose config
sudo docker compose up -d
sudo docker compose ps
curl http://localhost:8080
sudo docker compose logs --tail 20
sudo docker compose down
Windows 11 ターミナルpowershell
Test-NetConnection 192.168.100.xxx -Port 8080

Test-NetConnection とブラウザでの確認は、down を実行する前に行ってください。止めた後では当然つながりません。

エビデンス(スクリーンショット6点)

  • ↑ 手順2で撮る
  • ↑ 手順3で撮る
  • ↑ 手順4で撮る
  • ↑ 手順5で撮る
  • ↑ 手順8で撮る
  • ↑ 手順9で撮る

課題を考えるための材料

課題1コンテナ型仮想化とハイパーバイザ型仮想化の違いを説明せよ。

知っておくとよい事実

  • ハイパーバイザ型は、仮想的なハードウェアの上で、仮想マシンごとに独立したOS(カーネルを含む)を動かす(1日目のProxmox)
  • コンテナ型は、ホストのOSのカーネルを共有し、プロセス(動いているプログラム)やファイル、ネットワークの見え方を分けることで隔離する
  • コンテナはOSを起動しないので、起動が速く、イメージも小さく、同じ機械により多く詰め込める
  • カーネルを共有するので、ホストと違う種類のOS(たとえばLinuxの上でWindows)をコンテナとして動かすことは基本的にできない

考える観点

  • 「何を共有し、何を分けているか」を軸に比べる(図1)
  • 起動の速さ、大きさ、隔離の強さ、動かせるOSの自由度などを、表で比べると整理しやすい(表は三線表で)
  • この実験では両方を入れ子で使っている。それぞれ何のために使っているか
課題2コンテナを利用することで、アプリケーション配布や環境再現にどのような利点があるか考察せよ。

知っておくとよい事実

  • イメージには、アプリだけでなく、必要な部品(ライブラリ)や設定まで一緒に固められている
  • 同じイメージからは、どの機械でも同じ中身のコンテナが作られる
  • イメージは倉庫(レジストリ)を通じて配布され、名前とタグだけで取り寄せられる

考える観点

  • 「自分のPCでは動いたのに、別の機械では動かない」という問題は、なぜ起きるのか。コンテナはそれをどう防ぐか
  • 今日、whoami や hello-world を動かすのに、あなたは何をインストールしたか(何をインストールせずに済んだか)
  • コンテナを消しても、compose.yaml から同じものがすぐ立ち上がったことは、何を意味するか
  • 弱点はないか(イメージの中身を誰が作ったか分からない、など)
課題3compose.yaml でポート公開や再起動ポリシーを定義しておく利点を説明せよ。

知っておくとよい事実

  • compose.yaml に書かれた設定は、ファイルとして残り、何度でも同じように適用される
  • 設定をコードとして管理する考え方をInfrastructure as Code(IaC)と呼ぶ
  • restart: unless-stopped は、障害やサーバーの再起動のあとも、人の手を介さずにサービスを復旧させる
  • Dockerで公開したポートは、ufwの設定に関係なく外から届く(手順10)

考える観点

  • 毎回コマンドを手で打つ場合と比べて、打ち間違い・引き継ぎ・変更の記録はどう変わるか
  • どのポートを外に見せるかが1つのファイルにまとまっていると、安全の確認はしやすくなるか
  • 夜中にサーバーが再起動したとき、再起動ポリシーがある場合とない場合で何が違うか

あなたの番号を設定

学生番号の下2桁を入れると、このサイトのコマンド例に出てくるIPアドレスやVM IDが、あなた用の値に置き換わります。値はこのブラウザの中だけに保存され、どこにも送信されません。