いくつかあるのですが、「これだ!」みたいな方法が意外と見当たらなかったので書きます。
Docker を使ったデプロイにはいくつか方法があります。
- リモートへログインして Docker Hub 経由でイメージを取得してデプロイ
- ローカルからリモートの docker daemon へデータを送ってデプロイ
1. リモートへ SSH 接続してデプロイ
これが一番お手軽です。
- ローカルでイメージを作成
- 作成したイメージをリモートリポジトリ(Docker Hub など)にプッシュ
- リモートのマシンへログイン
- イメージをリポジトリから pull
- pull したイメージをもとにコンテナを作成
メリット
まず、とても簡単にできます。リモートへログインして直接コンテナを生成するので、迷う所がありません。
また、リモート側で docker-compose.yml を設定できます。このため、リモートマシン上にあるディレクトリを volumes へマウントできます。
デメリット
最大のデメリットは手動であることです。ローカルでイメージを更新したあと、いちいちリモートへログインして手動で pull する必要があります。Docker Hub と組み合わせて CI/CD をうまく構成できればやれなくはないとは思いますが、そもそも次に紹介する手法をとればもっと楽に実現できます。
また、この方法はリモートリポジトリを経由しなければなりません。そのため、プライベートリポジトリの数など制限があります。たとえば、Docker Hub の無料プランではプライベートリポジトリは 1 つしか作れません。もちろん、Docker Hub 以外にもリポジトリは色々あり、自前で立てることもできます。そのため、頑張ればプライベートリポジトリをいくつも作ることができます。しかし、そもそも次に紹介する方法ならリモートリポジトリを経由することなくデプロイできます。
2. Docker Context を使ってデプロイ
Docker には Context という機能があります。Docker Context を使うと、リモートの docker daemon にコマンドを実行することができます。
$ docker --context remote ps # リモートマシン上のコンテナ情報が取得できる $ docker --context remote run nginx # リモートマシンで nginxイメージのコンテナを立ち上げる $ docker --context remote build . # リモートの docker daemon に ビルドコンテキストのファイルが送信されて、リモートでイメージが作成される
しかも、コンテキストは簡単に作成できます。
$ docker context create remote --docker host=ssh://example.com --default-stack-orchestrator swarm
host には ~/.ssh/config に書かれた設定も利用できます。
docker-compose の host オプションでも似たことができます。
$ docker-compose --context remote up $ # あるいはこれでも $ docker-compose --host ssh://example.com up
context で一括管理をするとホストの変更が容易です。また、名前も自由につけられるのでわかりやすいです。そのため、利用できるのであれば host オプションより context をおすすめします*1。
version: "3" services: web: image: nginx volumes: - /usr/share/nginx:/usr/share/nginx:ro
上の docker-compose.yml を context や host オプションを使って立ち上げます。すると、リモートマシン上にコンテナが立ち上がります。また、コンテナの/usr/share/nginx
にリモートマシンの/usr/share/nginx
がマウントされます。
複数コンテナを同時に立ち上げるとエラーが起こる
たとえば、以下のように複数コンテナをまとめて立ち上げようとすると、SSHコネクションエラーが発生します。
version: '3' services: serviceA: image: nginx serviceB: image: nginx serviceC: image: nginx # ... serviceZ: image: nginx
どうやら、コンテナの分だけSSHコネクションが張られるようで、SSHコネクション数の制限に引っかかるみたいです。結局、僕は解決できず、独立したファイルに分けてデプロイすることにしました。
いい感じにデプロイしてみる
以下のような構成でリモートへデプロイしてみます。
./ ├ service-a │ ├ docker-compose.prod.yml │ └ docker-compose.yml ├ service-b │ ├ docker-compose.prod.yml │ └ docker-compose.yml ├ service-c │ ├ docker-compose.prod.yml │ └ docker-compose.yml ├ reverse-proxy │ ├ docker-compose.prod.yml │ └ docker-compose.yml └ deploy.sh
- service-a、b、cはそれぞれ独立したサービス
- reverse-proxyを介して各サービスへアクセスする
- コンフィグは docker-compose.yml + docker-compose.prod.yml を使う
このとき、以下のようなスクリプトを書きます。
#!/bin/bash SCRIPT_DIR=$(cd $(dirname $0); pwd) for dir in $(ls -d */ | sed -e 's!/!!'); do cd $SCRIPT_DIR/$dir files="" if [ -f "$SCRIPT_DIR/$dir/docker-compose.yml" ]; then files+="-f $SCRIPT_DIR/$dir/docker-compose.yml " fi if [ -f "$SCRIPT_DIR/$dir/docker-compose.prod.yml" ]; then files+="-f $SCRIPT_DIR/$dir/docker-compose.prod.yml " fi if [ -n "$files" ]; then docker-compose --context remote $files build docker-compose --context remote $files down docker-compose --context remote $files up -d fi done
各ディレクトリに入ってデプロイを行っています。context オプションを外せば、そのままローカルでテストができます(適宜docker-compose.dev.yml を追加するなど調整は必要です)。
まとめ
デプロイ時には Docker Context を使いましょう。
$ docker context create remote --docker host=ssh://example.com --default-stack-orchestrator swarm $ docker-compose --context remote up -d
*1:context に対応したのが 2020 年 6 月リリースのバージョンなので、バージョンによっては host オプションしか使えない可能性があります