docker-composeでUbuntuのイメージのみを管理しようとしてハマったので、ruby-jpで質問した
環境
$ docker --version Docker version 19.03.1
本題
Ubuntu18.04をベースイメージとしたDockerfileを作成し、docker-composeでコンテナの管理をしようとすると、イメージからコンテナを作成されていることが標準出力から確認できるのですが、attachをする過程でdocker-isucon-go-local_app_1 exited with code 0
となります。docker-compose ps
で確認すると下記のように表示されます。docker-compose exec app
を実行することでコンテナ内で操作をしたかったのですが、ERROR: No container found for app_1というエラーになってしまいます。
Name Command State Ports --------------------------------------------------------- docker-isucon-go-local_app_1 /bin/bash Exit 0
該当のファイル群
[docker-compose.yml] version: "3.7" services: app: build: context: ./containers/app/
[containers/app/Dockerfile] FROM ubuntu:18.04
公式ドキュメントよりdocker-composeは、サービスを管理するものであるということがわかりました。systemctlコマンドなどで管理するサービスのことを指すのではないかと思ったので、DockerfileのベースイメージをMySQLに変更すると、docker-compose ps
のStateがUpとなっていることを確認できました。
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
[containers/app/Dockerfile] FROM mysql:5.7 ENV MYSQL_ALLOW_EMPTY_PASSWORD=yes
Name Command State Ports ---------------------------------------------------------------------------------------- docker-isucon-go-local_app_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
最終的にDockerfileは、golangをインストールしたサービスを動かすため問題ないのですが、デバック過程でdocker exec app bash
でコンテナの状況を確認できないのは、辛いと思ったのでruby-jpで質問しました。
そして、
docker run
とdocker exec
の違いを調べる- Ubuntuをベースイメージとした時の、CMDはbin/bashとなっているので、コンテナが終了してしまう
というアドバイスを頂きました。
そこで、runとexecのhelpを確認するとexecは動いてるコンテナに対してのコマンドであることがわかりました。
$ docker run --help > Run a command in a new container $ docker exec --help > Run a command in a running container
ベースイメージのDockerfileがCMD ["/bin/bash"]を実行しているためコンテナがrun状態でないということが問題でした。
Dockerfileでdocker run -it
でビルドしたコンテナを操作できることを思い出したので、docker-composeでも同様のことができるのではないかと考えて調査してみると、公式ドキュメントに記載されていました。
Each of these is a single value, analogous to its docker run counterpart. Note that mac_address is a legacy option.
user: postgresql working_dir: /code domainname: foo.com hostname: foo ipc: host mac_address: 02:42:ac:11:65:43 privileged: true read_only: true shm_size: 64M stdin_open: true tty: true
ここで、-itが何を行なっているか調べるために再度docker run --help
を実行すると、疑似端末を割り当てattachされていないコンテナに対しても標準入力を待ち続けることがわかりました。
-i, --interactive Keep STDIN open even if not attached -t, --tty Allocate a pseudo-TTY
これらより、tty: trueを追加すればよさそうなので追加すると無事docker-compose exec app
でコンテナで操作を行うことができました。
version: "3.7" services: app: build: context: ./containers/app/ tty: true
知見
ruby-jpで質問した際に出た知見をまとめてます。
tty: true以外の方法で実現する場合
sleepコマンド
一定時間処理を待つ
使い方
sleep 7d
sleep inf
FROM ubuntu:18.04 CMD ["/bin/sh", "-c", "while true; sleep 1; done"]
stressコマンド
負荷をかけるツール
使い方
stress --vm-bytes 1B -m 1
やらない方がよい
tailコマンド
最終行から数行を表示するコマンド
使い方
tail -f /dev/null
readコマンド
標準入力から受け取った内容を1行単位で変数に入れるコマンド
使い方
read hoge
その他
sleep inifinity
やtail -f /dev/null
はSIGTERだとタイムアウト後、遅れて終了するので時間がかかるので、今回のケースでは利用しないほうが良いかもという意見もでました。これは、Linux関連の知識がないので現状調査方法がわからないためレベルが上がってから挑戦したいです。
参考文献
What is a TTY on Linux? (and How to Use the tty Command)
まとめ
- 質問に答えてくれた方々、ありがとうございました
- ruby-jpはいいぞ
- ruby-jpで質問、ログを追ってアウトプットする最強の学習メソッドがあるらしい
Docker実践ガイド 第2版 impress top gearシリーズ
- 作者: 古賀政純
- 出版社/メーカー: インプレス
- 発売日: 2019/02/18
- メディア: Kindle版
- この商品を含むブログを見る