0.実験の目的
docker run で使用できる -t
オプションは「疑似 tty の割り当て」をするオプションとされている。
Docker run リファレンス — Docker-docs-ja 20.10 ドキュメント
-t
を付けた時に、pts(疑似端末/pseudo-tty)
を開いてる bash は、イメージの Dockerfile 内のCMD[/bin/bash
]で実行しているbash
である。という事を確認するのがこの実験の目的である。
つまり-t
オプション自身が、pts
を作成し、さらにそれを使用する bash
も作るという2つの作業を実行しているわけでない事を確認する。
言い換えると、どんなイメージでも -t
(現実的には -it
)だけで、コンテナに接続できるわけではない事を確認する。
ここでは、scratch から CMD ["/bin/bash"]
入りと CMD 無しのイメージを作って、CMD ["/bin/bash"]
の影響を観察する。
1. bash入りのイメージと bash 無しのイメージを作る
scratch
のイメージには何も入ってないので、bash
が使っているライブラリと、bash
自身をコピーするDockerfile
を作る
$ which bash # bash の正確なパス
/bin/bash
$ ldd /bin/bash # 依存関係の調査
linux-vdso.so.1 (0x00007ffca48e1000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fa3397df000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa3395db000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa3391ea000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa339d23000)
$
一番、はじめのlinux-vdso.so.1
は、find でも見つからない。これは特殊なライブラリで、カーネルに埋め込まれているそうなので、コピーの必要がなさそう。
小ネタ
このライブラリの名前linux-vdso.so
をURLバーに入れると猫画像が出た。
(いつマルウェアのサイトに変わるかもしれないので直リンクは省略)
Dockerfile では、COPY元のファイルを指定するには、Dockerfile の場所からの相対パスを書ないといけない。相対パスを書くのが面倒なので、カレントディレクトリに必要なものをコピーする。
$ cp /bin/bash .
$ cp /lib/x86_64-linux-gnu/libtinfo.so.5 .
$ cp /lib/x86_64-linux-gnu/libdl.so.2 .
$ cp /lib/x86_64-linux-gnu/libc.so.6 .
$ cp /lib64/ld-linux-x86-64.so.2 .
$ ls -ltr
total 3432
-rwxrwxrwx 1 yuhki yuhki 170784 Dec 27 16:05 libtinfo.so.5
-rwxrwxrwx 1 yuhki yuhki 14560 Dec 27 16:05 libdl.so.2
-rwxrwxrwx 1 yuhki yuhki 179152 Dec 27 16:05 ld-linux-x86-64.so.2
-rwxrwxrwx 1 yuhki yuhki 1113504 Dec 27 16:06 bash
-rwxrwxrwx 1 yuhki yuhki 248 Dec 27 16:11 Dockerfile1
-rwxrwxrwx 1 yuhki yuhki 266 Dec 27 16:12 Dockerfile2
-rwxrwxrwx 1 yuhki yuhki 2030928 Dec 27 16:13 libc.so.6
$
以下の2つのDockerfile
を作る。
Dockerfile1 (CMD 無し)
FROM scratch
COPY ./bash /bin/bash
COPY ./libtinfo.so.5 /lib/x86_64-linux-gnu/libtinfo.so.5
COPY ./libdl.so.2 /lib/x86_64-linux-gnu/libdl.so.2
COPY ./libc.so.6 /lib/x86_64-linux-gnu/libc.so.6
COPY ./ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
Dockerfile2 (CMD で bash 実行)
FROM scratch
COPY ./bash /bin/bash
COPY ./libtinfo.so.5 /lib/x86_64-linux-gnu/libtinfo.so.5
COPY ./libdl.so.2 /lib/x86_64-linux-gnu/libdl.so.2
COPY ./libc.so.6 /lib/x86_64-linux-gnu/libc.so.6
COPY ./ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
CMD ["/bin/bash"]
Dockerfile1のbuild
$ docker build -t my-scratch1 -f Dockerfile1 .
Dockerfile2のbuild
$ docker build -t my-scratch2 -f Dockerfile2 .
buildしたイメージの確認
$ docker images | grep scratch
my-scratch1 latest f4b3f18c5757 3 hours ago 3.51MB
my-scratch2 latest bd8539ac3f76 3 hours ago 3.51MB
$
2.ビルドしたイメージを実行する
2.1.CMD["/bin/bash"]無しのイメージからコンテナを生成
$ docker run -itd --name my-container2 my-scratch1
docker: Error response from daemon: No command specified.
See 'docker run --help'.
$
実行できない。No command specified
というエラーになる。
-t
オプションは付けているが、これはpseudo-tty
を生成するだけで、それを使うシェルが無いとそもそも起動できない事がわかる。
今度は、docker run
時に、引数で/bin/bash
を起動してみる。
$ docker run -itd --name my-container1 my-scratch1 /bin/bash
1983d63b34a9a584f7cb1922a1fa6686690342f99a658449b794a22adb552f0c
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1983d63b34a9 my-scratch1 "/bin/bash" 4 seconds ago Up 3 seconds my-container1
$
今度は、コンテナは終了しない。
2.2. CMD[/bin/bash]を指定したイメージからコンテナを生成
$ docker run -itd --name my-container2 my-scratch2
5e265705f95f1601d5b3bf3ec8b457a682f299abd1dabed9d25f19f1a3ba942a
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5e265705f95f my-scratch2 "/bin/bash" 3 seconds ago Up 2 seconds my-container2
$
起動できる。
敢えて /bin/bash
を起動しないくても、コンテナは終了しない。CMD で指定した /bin/bash
が効いているのがわかる。
以上の事から pts(疑似端末/pseudo-tty)
を使う bash
がいて、はじめて-t
オプションが意味を持ってくる事がわかった。