2021-12-06

Docker in Action を読む - 1: コンテナ、コマンドの実行

Docker に入門した(n 回目)。docker run などの基本的なコマンドを実行した。

Docker in Action を読みながらメモを取った。

コンテナの構築に使われる重要な特徴

  • PID namespace
  • UTS namespace
  • MNT namespace
  • IPC namespace
  • NET namespace
  • USR namespace
  • chroot syscall
  • cgroups
  • CAP drop
  • Security models

Docker を動かす

docker run --detach --name web nginx:latest
docker run -d --name mailer dockerinaction/ch2_mailer

docker run nginx:latest で最新の NGINX イメージをダウンロードした後、NGINX コンテナを実行する。 すでにダウンロード済みならダウンロードはしない。 docker run するたびに新しいコンテナが作成される。

Docker run reference | Docker Documentation

Detached
--detach (-d) をつけてコンテナを起動するとバックグラウンドでプログラムが実行され、ルートプロセスが終了した時点でコンテナが終了する。

デーモンやサービスと呼ばれるプログラムは --detach で実行するのに適している。

Interactive containers

docker run --interactive --tty --link web:web --name web_test busybox:1.29 /bin/sh

このコマンドを実行すると、コンテナの内部でシェルコマンドを実行できる状態になる。

Docker run reference | Docker Documentation

-t : Allocate a pseudo-tty
-i : Keep STDIN open even if not attached

--interactive はターミナルにアタッチされなくなるまで標準入力を開いたままにするオプション。--tty はコンテナに仮想的なターミナルを割り当てるオプション。--tty を指定して起動することで、コンテナへの入力やコンテナからの出力がターミナルで見れるようになる。

pseudo-tty
Pseudoterminal - Wikipedia

In some operating systems, including Unix and Linux, a pseudoterminal, pseudotty, or PTY is a pair of pseudo-device endpoints (files) which establish asynchronous, bidirectional communication (IPC) channel (with two ports) between two or more processes.

Pseudoterminal files

Pseudoterminals (pseudo-TTYs) are used by users and applications to gain access to the shell. A pseudo-TTY is a pair of character special files, a master file and a corresponding slave file. The master file is used by a networking application such as OMVS or rlogin. The corresponding slave file is used by the shell or the user's process to read and write terminal data.

とりあえずシェルへアクセスするのに使われることはわかった。

起動したコンテナの中で wget -O - http://web:80/ を実行すると "Welcome to nginx!" ページの html が取得できる。

Legacy container links を使わないようにする

Legacy container links | Docker Documentation

--link フラグをつけて実行すると、他のコンテナと通信することができる。 --link フラグは古い機能で、代わりに user-defined networks の利用が勧められている。

--link を使わずに上記で実行した wget までやってみる。

link なしでの実行
link フラグをつけないで実行し wget を実行すると html が取得できない。

/ # wget -O - http://web:80/
wget: bad address 'web:80'

ネットワークの作成
docker network create dia-netdia-net という名前の user-defined bridge network を作成する。

コンテナを接続する
docker network connect dia-net web

wget を実行する docker run -it --network dia-net --name web_test busybox:1.29 /bin/sh でネットワークを指定してコンテナを実行し、wget -O - http://web:80/ を実行すると html が取得できた。

コンテナを見る

実行中のコンテナは docker ps で確認できる。-a フラグを立てると実行していないコンテナも含めて表示する。

docker inspect CONTAINER でコンテナのメタ情報が出力できる。--format オプションで出力する値を指定できる。

ログは docker logs <コンテナ名> で見れる。また、--follow (-f) フラグを立てることで、停止するまで新しく来たログを次々表示することができる。

PID namespace

docker run -d --name namespaceA busybox:1.29 /bin/sh -c "sleep 30000"
docker run -d --name namespaceB busybox:1.29 /bin/sh -c "nc -l 0.0.0.0 -p 80"
docker exec namespaceA ps
docker exec namespaceB ps

docker exec | Docker Documentation
docker exec CONTAINER COMMAND は実行しているコンテナでコマンドを実行する。

ps で現在実行しているプロセスを表示すると、docker run で指定したコマンドの PID はともに 1 であることが確認できる。 各コンテナは ID 空間を共有しない。

docker run --pid host busybox:1.29 ps

--pid host を指定することでホスト側の PID 名前空間を使うことができる。 単に ps を実行するだけだと

PID   USER     TIME  COMMAND
    1 root      0:00 ps

のように ps のみが表示されるが、ホスト側の PID 名前空間を使って ps するとプロセスが大量に表示される。

Software conflict

docker run -d --name webConflict nginx:latest
docker exec webConflict nginx -g 'daemon off;'

NGINX コンテナを実行したあと、さらにコンテナ内で nginx -g 'daemon off;' を実行する。

nginx -g 'daemon off;'
Command-line parameters
-g は global configuration directives を設定するパラメータである。

Core functionality
daemon on | off; は以下のように説明されている。

Determines whether nginx should become a daemon. Mainly used during development.

daemon off にするとフォアグラウンドで実行される。

今回はすでに NGINX を実行しているため、

2021/11/29 10:04:47 [emerg] 35#35: bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

というメッセージが表示される。Port conflict が起こって 2 番目のコマンドが失敗している。

docker run -d --name webA nginx:latest
docker run -d --name webB nginx:latest

このように、別々のコンテナで実行すればポートが衝突することなくサーバが立てられる。

衝突を避ける

docker create --cidfile web.cid nginx 

docker create はコンテナを作成するだけで実行はしない。 --cidfile はコンテナ ID をファイルに書き出す。 すでにファイルが存在している場合、コンテナは作成されない。

Environment-agnostic systems を構築する

Environment-agnostic は環境に依存しない、とらわれないことを意味していると思う。 似た表現として Platform-agnostic というものがあり、複数のプラットフォームでプロダクトが実行できることを示している。

Environment-agnostic systems の構築を助ける、Docker が持つ特徴として以下が挙げられる。

  • Read-only filesystems
  • Environment variable injection
  • Volumes

Read-only filesystems

docker run -d --name wp --read-only wordpress:5.0.0-php7.2-apache

を実行し、docker logs wp でログを見ると以下のように出力された。

noy72@noy72 docker-in-action % docker logs wp
WordPress not found in /var/www/html - copying now...
Complete! WordPress has been successfully copied to /var/www/html
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
Wed Dec  1 13:49:01 2021 (1): Fatal Error Unable to create lock file: Bad file descriptor (9)

lock file の生成に失敗していることがわかる。コンテナが読み込み専用のため、lock file の書き込みに失敗している。

docker run -d --name wp_writable wordpress:5.0.0-php7.2-apache

--read-only フラグをつけずに実行するとエラーを起こさずに実行できる。 書き込まれたファイルがどれなのかを調べるのには docker container diff CONTAINER が使える。

noy72@noy72 docker-in-action % docker container diff wp_writable
C /run
C /run/apache2
A /run/apache2/apache2.pid

--volume フラグを使うと、書き込み可能なホストのディレクトリをマウントすることができる。--read-only フラグと併用すると、指定した一部のディレクトリだけ書き込める状態にできる。

tmpfs

tmpfs - Linux技術者認定 LinuC | LPI-Japan

tmpfs - Wikipedia

tmpfsはUnix系OSにおける一時ファイルのためのファイルシステム名。

揮発性のディレクトリ?

docker run | Docker Documentation docker run--tmpfs フラグを使うことでコンテナに tmpfs をマウントできる。

MySQL と WordPress を繋げる(途中まで)

docker run -d --name wpdb -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5.7
docker run -d --name wp3 -p 8000:80 --read-only -v `pwd`/run/apache2:/run/apache2 --tmpfs /tmp wordpress:5.0.0-php7.2-apache
docker network create ch2
docker network connect ch2 wpdb
docker network connect ch2 wp3

M1 Mac だと MySQL の起動ができないので --platform linux/x86_64 を追加して docker run する。

--env (-e) は環境変数を設定する。

Restart

docker run | Docker ドキュメント

--restart フラグで restart policy (コンテナが終了したときに再起動する条件)を設定できる。

感想

Docker の知識がなさすぎたのでここまででも十分学びになっている。

英語で書かれているので読めているようで読めていない。サンプルコード(コマンド)を実行して雰囲気で読み進めている。

日々膨大な技術情報に接する環境にいるわけですから、限られた時間の中で正確に英文の技術情報を読み解かないといけません。英文法のスキルが足りないのは致命的です。「なんとなく」英文を読んでいるので、正確に内容を読めたかどうか英文法に従って客観的に自分でチェックできない。おそらく学生時代からの勉学の積み残しだと思われます。

(中略)
英語がちゃんと読めるようになって始めて自分の専門的技術力を高めるスタート地点に立てるのです。