以前、Docker を自力で学習しようとして挫折しました。コマンドもオプションもできることが多すぎて、どれがファーストステップなのか分かりませんでした。『仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん(マイナビ出版)』を購入して、ようやくそれらしいことができるようになりました...。嬉しかったので叩いたコマンドをメモとして残します。
この記事は Docker v20.10、macOS Monterey でのハンズオンです。
Hello World
公式サイトから Docker Desktop for mac をダウンロードしてインストールします。
まずは Hello World を実行してみます。
docker run hello-world
以下のような結果が出力されれば、最初の一歩は完了です。
> Unable to find image 'hello-world:latest' locally
> latest: Pulling from library/hello-world
> 2db29710123e: Pull complete
> ...
> Hello from Docker!
> This message shows that your installation appears to be working correctly.
> To generate this message, Docker took the following steps:
> 1. The Docker client contacted the Docker daemon.
> 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
仕組み
Docker は docker hub などで公開された「イメージ」を PULL(ダウンロード)してローカルに保存します。イメージには、nginx やら mysql やら node やら、ローカルインストールするような各種ソフトウェアから OS までさまざまなものが揃っています。
イメージから「コンテナ」を作り START すると各種サービスが稼働します。「ネットワーク」を使うとコンテナ同士を連携させることもできます。ローカルマシン上に小さなPCがいくつも動いているようなイメージですね。
nginx など Web サーバーを稼働させた場合は HTTP を経由して小さな PC にアクセスします。利用が終わったら STOP で電源を切り、RM で廃棄します。
runコマンド
コンテナを動かすには、コンテナの作成、起動、イメージのプル、のステップが必要です。
docker container create
docker container start
docker container pull
これらは run
コマンドでまとめて実行することができます。
サンプルとしてWeb サーバーの nginx を run
コマンドで稼働します。
docker run --name container01 -d -p 8080:80 nginx:1.21
--name
コンテナ名を指定する。
-d
バックグラウンドで実行を継続する。
-p 8080:80
ホストの 8080 番ポートをコンテナの 80 番ポートにバインドする。
nginx:1.21
バージョンを省略すると latest を指定したのと同じ。
http://localhost:8080 にアクセスすると「Welcome to nginx!」の画面が表示されます。
cpコマンド
cp
コマンドでホストからコンテナにファイルをコピーすることができます。
稼働させたコンテナ "container01" のインデックスページを差し替えてみます。
# サンプルとして送り込む HTML を作成
echo "<html>
<head></head>
<body>test</body>
</html>" >index.html
docker cp ./index.html container01:/usr/share/nginx/html/
container01:/usr/share/nginx/html/
コンテナ名:コピー先のパス
この例では nginx の公開フォルダにファイルを送り込んでいる
http://localhost:8080 をリロードするとコンテンツが「test」に変わります。
execコマンド
exec
コマンドを使うと稼働させたコンテナの中でコマンドを実行することができます。コマンドとしてシェルを渡すと、SSH で接続したかのようにコンテナを操作することができます。
Docker イメージは Linux ベースで作られていてそのほとんどが bash を備えているため、稼働させたコンテナ "container01" で bash を実行してみます。
docker exec -it container01 bash
-i
ホストのキーボード入力をコンテナに送る。
-t
ホストとコンテナのターミナルをバインドする。
正確な補足ではないので tty,pts あたりで検索すると理解が深まるかもです。
uname
コマンドを叩くと Linux らしきものが動いているのが分かります。
# root@4643ee0e17a5:/
uname -a
Linux 4643ee0e17a5 5.10.104-linuxkit #1 SMP Thu Mar 17 17:08:06 UTC 2022 x86_64 GNU/Linux
ls
コマンドを叩くとさきほどの cp
コマンドで送り込んだファイルが格納されていることが分かります。
# root@4643ee0e17a5:/
ls -l /usr/share/nginx/html/
> -rw-r--r-- 1 root root 497 Jan 25 15:03 50x.html
> -rw-r--r-- 1 501 dialout 51 May 5 12:10 index.html
確認が終わったら exit
で抜けます。
# root@4643ee0e17a5:/
exit
Dockerfile
イメージはプルするだけでなく、毎回ファイルコピーなどのカスタマイズを加えることが多くなりそうです。毎回実行する手順は Dockerfile
というファイルにひとまとめにしておくことができます。
任意のフォルダを作成します。
mkdir image
サンプルとしてインデックスページを作成します。
echo "<html>
<head></head>
<body>foobar</body>
</html>" >image/index.html
Dockerfile
を作成します。
touch image/Dockerfile
# ./image/Dockerfile
FROM nginx
COPY index.html /usr/share/nginx/html/
build
コマンドでビルドします。
docker build -t image01 ./image/
> [+] Building 0.1s (7/7) FINISHED
> => [internal] load build definition from Dockerfile
> => => transferring dockerfile: 92B
> => [internal] load .dockerignore
...
-t
image01 という名前でイメージを作成する。
イメージのリストを確認すると、新しく「image01」が追加されています。
docker image ls
> REPOSITORY TAG IMAGE ID CREATED SIZE
> image01 latest a7ca92fca6b5 3 seconds ago 142MB
run
コマンドで実行します。
docker run --name container02 -d -p 8081:80 image01
http://localhost:8081 にアクセスして「foobar」が表示されれば成功です。
ネットワーク
次は 2 つのコンテナを run
してネットワークで連携させてみます。
サンプルとして WordPress とデータ保存の mysql のコンテナを稼働してみましょう。
# ネットワークの作成
docker network create network01
# mysql のコンテナ
docker run \
--name container03 \
-dit \
--net=network01 \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=db1 \
-e MYSQL_USER=user1 \
-e MYSQL_PASSWORD=pass \
mysql:5.7 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--default-authentication-plugin=mysql_native_password
# wordpress のコンテナ
docker run \
--name container04 \
-dit \
--net=network01 \
-p 8082:80 \
-e WORDPRESS_DB_HOST=container03 \
-e WORDPRESS_DB_NAME=db1 \
-e WORDPRESS_DB_USER=user1 \
-e WORDPRESS_DB_PASSWORD=pass \
wordpress:5.9
それぞれのコンテナは同じネットワーク「network01」上に存在し、mysql のコンテナに生成した「db1」というデータベースに wordpress のコンテナがアクセスします。
http://localhost:8082/ にアクセスすると WordPress のセットアップ画面が表示されます。任意のログイン情報を入れてセットアップすると mysql のコンテナの db1 にテーブルが作成されます。
サンプルとして cp
コマンドでダンプファイルを送り込んで、exec
コマンドで mysql に取り込んでみます。
# ダンプを吐き出す
mkdir db
mysqldump {ローカルのDB名} -p > ./db/restore.sql
# cp コマンドでコンテナに送り込む
docker cp ./db/restore.sql container03:/var/lib/mysql/
# mysql のコンテナでコマンドを実行
docker exec -it container03 mysql db1 -uroot -p
> Enter password
> # "rootpass" で入る
# ダンプを取り込む
mysql> source /var/lib/mysql/restore.sql
# データが取り込まれたか確認する
mysql> select user_login from wp_users;
> +------------+
> | user_login |
> +------------+
> | user1 |
> | user2 |
> +------------+
# 確認できたら抜ける
mysql> exit
docker-compose.yml
イメージに対する操作手順を Dockerfile
に書いたのと同じように、複数コンテナの操作手順は docker-compose.yml
にひとまとめにして書くことができます。
前述の wordpress と mysql の設定は以下のように書けます。
# docker-compose.yml
version: "3"
services:
container_mysql:
image: mysql:5.7
container_name: container05
networks:
- net000
volumes:
- type: bind
source: $PWD/db
target: /tmp/db
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: db1
MYSQL_USER: user1
MYSQL_PASSWORD: pass
container_wordpress:
depends_on:
- container_mysql
image: wordpress:5.9
container_name: container06
networks:
- net000
ports:
- 8083:80
environment:
WORDPRESS_DB_HOST: container_mysql
WORDPRESS_DB_NAME: db1
WORDPRESS_DB_USER: user1
WORDPRESS_DB_PASSWORD: pass
networks:
net000:
docker-compose.yml
は compose up
コマンドを使って一気にコンテナを稼働します。
docker compose -f ./docker-compose.yml up -d
さきほど cp
コマンドで送り込んだダンプは、ボリュームをマウントしてコンテナ内に送り込むようにしました。
# docker-compose.yml の抜粋
volumes:
- type: bind
source: $PWD/db
target: /tmp/db
type:bind
コピーでなくホストのファイルシステムを参照する。
コンテナの中に入るとダンプが送り込まれていることが確認できます。
docker exec -it container05 bash
> root@bd5bd4aeff49:/#
ls -la /tmp/db
> drwxr-xr-x 4 mysql root 128 May 5 08:06 .
> drwxrwxrwt 1 root root 4096 May 5 13:37 ..
> -rw-r--r-- 1 mysql root 140399 May 5 13:34 restore.sql
compose up
コマンドで立ち上げたコンテナ群は compose down
で停止します。
docker compose -f ./docker-compose.yml down
stop/rmコマンド
現在稼働しているコンテナ群を確認してみます。
docker container ls
> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
> 76f3edbed706 wordpress:5.9 "docker-entrypoint.s…" 12 minutes ago Up 12 minutes 0.0.0.0:8082->80/tcp container04
> 05edbb9b4af8 mysql:5.7 "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 3306/tcp, 33060/tcp container03
> ed0ab41237df image01 "/docker-entrypoint.…" 15 minutes ago Up 15 minutes 0.0.0.0:8081->80/tcp container02
> 2884a2cd7478 nginx:1.21 "/docker-entrypoint.…" 21 minutes ago Up 21 minutes 0.0.0.0:8080->80/tcp container01
run
コマンドで稼働したコンテナはローカルに保存されます。たまり続けるとストレージを圧迫するので、使い終わったら stop
で停止し rm
で削除します。
# コンテナの停止
docker container stop container01
# コンテナの削除
docker container rm container01
同じようにイメージやネットワークも削除します。
docker image ls
> REPOSITORY TAG IMAGE ID CREATED SIZE
> image01 latest 51b935b7a7db 41 minutes ago 142MB
> mysql 5.7 8aa4b5ffb001 7 days ago 462MB
> wordpress 5.9 b44d413c437a 2 weeks ago 606MB
> nginx 1.21 fa5269854a5e 2 weeks ago 142MB
# イメージの削除
docker image rm image01
GUI でもクリック操作で停止や削除できるため、全てをかたっぱしから消したい時はこちらのほうが楽かもしれません。