Docker コンテキストとは?
Docker コンテキストは、ひとことで言うと、Docker CLI で入力したコマンド (docker) の操作対象ホストを切り替えるための仕組みです。
例えば、Conoha
などの VPS サーバー や、Azure (ACI)、AWS (ECS) といったクラウドサービス上の Docker エンジンに対して、ローカルホストから docker コマンドを実行できるようになります。
カレントコンテキストは、docker compose use コマンドで簡単に切り替えることができるので、ローカルでのコンテナのテストが終わったら、コンテキストを Azure (ACI) に切り替えてクラウド環境上で docker compose up するといったことが簡単にできます。
当然、接続先のコンテナサービスごとに接続プロトコルは異なるのですが、Docker は標準で Azure や AWS をターゲットとしたコンテキストの作成に対応しており、実際に docker コマンドを実行するときは接続プロトコルを意識しないで済むようになっています。
ここでは、より汎用的な SSH 接続を用いるコンテキストを作成し、リモートホスト上の Docker エンジンに対して Docker コマンドを実行してみます。
前提条件:
- リモートホストに Docker がインストールされていること
- リモートホストに SSH キーで SSH 接続できるようなっていること(参考: SSH の使い方)
- 接続先のユーザーが
sudoなしでdockerコマンドを実行できるようなっていること(参考: docker グループへの追加)
デフォルト・コンテキスト
Docker Desktop をインストールすると、デフォルトのコンテキストとして、default という名前のコンテキストが作成されます。
Docker コンテキストの一覧を表示するには、docker context ls コマンドを使用します。
$ docker context ls
NAME TYPE DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default * moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
default コンテキストのエンドポイントは unix:///var/run/docker.sock となっており、これはローカルホスト上の Docker デーモンに対して Docker コマンドを実行することを示しています。
リモートホストへの SSH 接続設定
SSH 接続に使用するユーザー情報などは、~/.ssh/config ファイルにまとめて記述しておくと便利です。
というか、これを使わないと、細かい接続設定を行うのが困難なので作成しておきましょう。
Host conoha
Hostname example.com
Port 22
User maku
IdentityFile ~/.ssh/id_ed25519ここでは、Conoha VPS
を使う想定で、設定名を conoha にしましたが、このあたりは自由に決めてください。
SSH キー(秘密鍵)にパスフレーズが設定されている場合は、SSH agent に秘密鍵とそのパスフレーズを設定しておく必要があります。
$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /Users/maku/.ssh/id_ed25519: (秘密鍵のパスフレーズを入力)
Identity added: /Users/maku/.ssh/id_ed25519 (maku@macbook.local)
SSH 接続用の Docker コンテキストを作成する
新しい Docker コンテキストを作成するには、docker context create コマンドを使用します。
--docker オプションを次のように指定すると、SSH 接続用のコンテキストを作成できます。
$ docker context create --docker "host=ssh://conoha" my-context
ssh://conoha という接続 URI では、前述の ~/.ssh/config で設定した名称を使用していることに注意してください。
ssh://maku@example.com:22 のように、明示的な URI を指定することもできます。
次のように実行すると、新しいコンテキスト my-context が作成されていることを確認できます。
$ docker context ls
NAME TYPE DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default * moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
my-context moby ssh://conoha
この段階では、まだカレントコンテキストは default のままです。
コンテキストを切り替えて Docker コマンドを実行する
使用する Docker コンテキストを切り替えるには、docker context use コマンドを使用します。
# コンテキストを切り替え
$ docker context use my-context
my-context
# カレントコンテキストを確認(アクティブなコンテキストに * 印が付いている)
$ docker context ls
NAME ...(省略)...
my-context * ...(省略)...
default ...(省略)...
# 次のようにカレントコンテキスト名だけ表示することも可能
$ docker context show
my-context
あとは、いつも通り docker コマンドを実行すると、SSH 接続先の Docker ホストで処理されるようになります。
$ docker container run --rm hello-world
例えば、リモートホスト側で次のような感じで Web サーバーを起動し、ローカルホスト側からアクセスできるようになります(もちろんポートが適切に開放されている必要があります)。
# リモートホスト上の Web サーバー(nginx コンテナ)を起動
$ docker container run --rm -d -p 8000:80 --name web nginx
# ローカルホストからアクセス
$ curl http://example.com:8000
# リモートホスト上の Web サーバーを停止
$ docker container stop web
上記の例では、あらかじめ docker context use コマンドで使用するコンテキストを切り替えておきましたが、docker コマンド実行時に --context オプションでコンテキスト名を指定することもできます。
次のように実行すれば、各コンテキストで使用する Docker ホストの詳細情報を確認できます。
$ docker --context default info # デフォルトコンテキスト(ローカルホスト)で実行
$ docker --context my-context info # 今回作成したコンテキスト(リモートホスト)で実行
本番環境用のコンテキストは常に選択していると危険なので、--context オプションでのみ使用した方がよいかもしれません。
$ docker --context production compose up -d
Docker コンテキストを削除する
必要なくなった Docker コンテキストは、docker context rm コマンドで削除できます。
$ docker context use default # デフォルトコンテキストに戻しておく
$ docker context rm my-context # 不要なコンテキストを削除
$ docker context ls # コンテキストの一覧を確認
NAME ...(省略)...
default * ...(省略)...
バインドマウント時の注意
Docker コンテキストとバインドマウントを組み合わせて使用するときは、マウント時の source パスの指定方法に注意する必要があります。
source パスを下記例の ./meili_data のように相対パスで記述すると、それは docker コマンドを実行する PC 上のカレントパスとして展開されます。
version: "3.9"
services:
meilisearch:
image: "getmeili/meilisearch:v1.6"
container_name: meilisearch
ports:
- "7700:7700"
environment:
- MEILI_ENV=production
- MEILI_NO_ANALYTICS=true
- MEILI_MASTER_KEY
volumes:
- type: bind
source: ./meili_data
target: /meili_data
bind:
create_host_path: true # ./meili_data が存在しなければ作成例えば、カレントディレクトリが /Users/maku/myproject の状態で docker --context my-context compose up -d と実行すると、my-context コンテキストが指し示すリモートホスト上に /Users/maku/myproject というディレクトリが生成されてしまいます(存在しなければ)。
このパスは、おそらくリモートホスト上では意味を持ちません。
このような振る舞いを防ぐには、source パスを最初から絶対パスで指定する必要があります。
volumes:
- type: bind
source: /opt/meili_data # ターゲットホスト上の絶対パスを想定して記述
target: /meili_data
bind:
create_host_path: trueあるいは、バインドマウントではなく、ボリュームマウント を使ってしまうのが手っ取り早いです。 ボリュームマウントを使用すると Docker のシステムがデータを一元管理してくれるため、ファイルシステム上のパスに関連する問題が発生しなくなります。
version: "3.9"
services:
meilisearch:
image: "getmeili/meilisearch:v1.6"
container_name: meilisearch
ports:
- "7700:7700"
environment:
- MEILI_ENV=production
- MEILI_NO_ANALYTICS=true
- MEILI_MASTER_KEY
volumes:
- type: volume # ボリュームマウントを使用する
source: meili_data # 一番下で定義しているボリュームを指定
target: /meili_data
volume:
nocopy: true # ボリューム生成時にコンテナから内容をコピーしない
# 作成するボリュームの定義
volumes:
meili_data:
# name: meili_data # プロジェクト名のプレフィックスを付けたくないとき