docker exec を使いこなす

多くのdockerイメージは単体デーモンが起動する形式で作られているため、コンテナ内のコマンドを実行する手順が思いつかなくなりがちです。
このような場合、たいていはdocker execコマンドの理解を深めることで必要な操作をカバーできます。

## docker exec `ssh`不要でコンテナ操作可能 * コンテナ内でコマンドを実行できる * `-it`オプションで端末にコンテナに接続できる --- ## オプション * `-i` 標準入力を接続。ローカルの`cat`出力リダイレクトにも使える * `-t` 仮想端末の接続 * `-u user` ユーザー指定 --- ## コンテナ内で作業 `docker exec -it CONTAINER bash` * `bash`ではなく`rails c`などでも良い * bashは`exit`または`Ctrl-d`で切断 --- ## docker attachとの違い `attach`はコンテナのメインプロセス(各種サーバーなど)に接続 * `exec -it`は指定コマンドを起動して接続 * `attach`の使い途は少ない。ログは`logs`で * `attach`はCtrl-cで切断すると、コンテナごと終了 --- ## 可能な操作 コンテナに入っているコマンドを実行可能 * 何が入っているかは利用イメージ次第 * なければ`apt-get`などで追加もできる * ただし再起動で消える --- ## 起動していないコンテナには接続できない 以下のようなケースは`docker logs`でログ収集 * 異常終了したコンテナ * 設定不良でメインプロセスを起動できないコンテナ --- ## Kubernetesも同様 * [kubectl exec](../kubernetes/20200710-kubectl-exec.md) * リモートクラスタのコンテナを直接操作可能

コンテナにシェルログインさえできてしまえば、従来型のサーバー管理と同じように操作できます(コンテナログイン不要のケースも後述)。

また、やや特殊なケースながら、ワーキングディレクトリに依存する操作への対応を後半で補足します。

コンテナ上でコマンドを実行

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