多くのdockerイメージは単体デーモンが起動する形式で作られているため、コンテナ内のコマンドを実行する手順が思いつかなくなりがちです。
このような場合、たいていはdocker exec
コマンドの理解を深めることで必要な操作をカバーできます。
コンテナにシェルログインさえできてしまえば、従来型のサーバー管理と同じように操作できます(コンテナログイン不要のケースも後述)。
また、やや特殊なケースながら、ワーキングディレクトリに依存する操作への対応を後半で補足します。
コンテナ上でコマンドを実行
docker execの基本的な使い方は、コンテナ名の後にコマンドを並べる書式です。たとえばコンテナ内で実行中のプロセスをpsコマンドで調べる場合、以下のように実行します。
$ docker exec your-container-name ps aux
dockerコンテナへのbashログインは、atachではなくexec -itで
dockerのコンテナ・インスタンスの状態を知りたいとき、通常のOSと同じようにbashなどでシェル操作したい場合があります。この場合、docker exec -it
オプションが使えます。
$ docker exec -it INSTANCE_NAME /bin/bash
起動中のdockerに接続するコマンドにはdocker attach
があります。ただし、docker attachは使える環境が限定されるため、あまり使う必要がありません。
リモートホスト上のdockerコンテナについては、dockerにsshdをバンドルするのではなく、ホストOSにSSHログインしたうえでdocker exec -itという手順になります。
クラスタ構成については Kubernetes の方がこなれており、dockerには限界があります。Kubernetesにも kubectl execというdocker execと同じ用途のコマンドがあります。
接続に成功すると、コンテナ上のプロンプトが表示され、psやlsなども使えます。
コンテナログインは不要
コンテナとは標準入出力でパイプ接続可能なため、たとえばPostgreSQLのバックアップ・リストアは以下のようなコマンドでネットワーク越しに直接実行可能です。
$ docker exec pg_container pg_dump -Upostgres target_db > backup.sql
$ cat backup.sql | docker exec -i pg_container psql -Upostgres
以下のように標準入出力の前後でコンテナ上の動作とクライアント側の動作が分かれており、シェルのリダイレクトでネットワーク転送できます。
また、dockerとkubernetesのコマンド構成はほぼ同じです。
また、REPL環境がある場合には
$ docker exec -it pg_container psql -Upostgres
のようにpsqlに直接接続したり、rails console
を起動することも可能です。
Tips: bashコマンド化
シェルログインを頻繁に行う場合、~/.bashrcに以下のような関数を定義しておくと、dbash コンテナ名のように実行できて便利です。末尾のbashを付け忘れてエラー、という失敗がなくなります。
function dbash() {
command docker exec -it $1 bash
}
Tips: docker execのカレントディレクトリを変更してコマンド実行
Rubyのbundlerなどでbundle exec
を実行したい場合のように特定のカレントディレクトリでコマンドを実行しなくてはならないケースがあります。
特にdockerを利用して完成済のコンテナのカレントディレクトリを変更したうえでワンライナーを実行する手順が意外に見当たりませんでした。
docker run
には-wオプションでワーキングディレクトリを指定する方法がありますが、docker execにはありません。
いろいろとためした結果、たどりついたのは
$ docker exec some_container "bash -c cd /opt && bundle exec rails s"
のように&&で2つのコマンドを連続実行する手順でした。
また、cdはbashなどのシェルにバンドルされたコマンドのためbash -c cd
の形式で呼び出す必要がありました。
dockerを活用するには、dockerそのものというよりむしろシェルの知識が必要な印象です。
Chuma Takahiro