はじめに
Docker Machineを使ったアプリのデプロイにて、VPSや自サバを対象とするケースの記事が少ない印象だったので本記事を書きました。
Docker Machineの機能を利用することで普段使いのローカルPCから直接(sshログイン無しに)VPSや自サバ上へDockerを構築、イメージとコンテナを管理、アプリをデプロイすることができます。
Docker Machineでのリモート化による嬉しい点には以下があります。
- ローカルからできるので、対象のDockerホストサーバにログイン→ソースやイメージをPull、する必要がない。
- サードパーティのデプロイツールに頼らずDockerの標準機能だけでアプリがデプロイできる。
- 複数のDockerホストを扱うとき必要があるとき、すべてローカルから操作できる。
本記事では個人開発サービスやスタートアップサービスアプリなどのデプロイを前提とし、1つのConoha VPS上にDocker Composeでデプロイするまでを記載します。KubernetesやDocker Swarmを使った複数ホストが対象のクラスタリング利用は含まれていません。
前提・環境
Mac (ローカル側)
MacOS: High Sierra 10.13.6
Docker for Mac: Docker Engine, Docker Machineのバージョンはこのスクショ画像を参照
Conoha VPS (サーバホスト側)
OS: Ubuntu 18.04 LTS (Bionic Beaver)
SSH公開鍵認証ログインできるユーザーを作成して設定
本記事ではrootユーザではVPSへ直接ログインできないことを前提とします。そのため、Docker Machineを経由して対象ホストへログインするためのSSH公開鍵認証のログインができるユーザーが必要です。
こちらの記事などを参照することでユーザ作成できます。
Generic DriverでVPS上にDockerホストを構築
以下のスクリプトを実行することでVPS上にDockerがインストールされ、1つのMachineとして構築されます。
#!/bin/bash
IP=対象VPSのIPアドレス
USER=username
KEY=~/.ssh/id_rsa
NAME=conoha1 # Dockerホストサーバへの任意の名前
docker-machine create \
--driver generic \
--generic-ip-address=$IP \
--generic-ssh-user $USER \
--generic-ssh-key $KEY \
$NAME
今回はDockerホストとなるサーバがVPSなので--driver generic
を指定します。
ちなみに、公式ドキュメントを見ると、AWS、GCP、Azure、Degital Ocean、OpenStackとクラウドサービスごとにドライバーが用意されていることがわかります。
【注意】 visudoで設定を変更しないとエラーになる。
上記のdocker-machine
コマンドを実行すると下記のようなエラーとなり失敗するかと思われます。
Running pre-create checks...
Creating machine...
(conoha1) Importing SSH key...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with ubuntu(systemd)...
Error creating machine: Error running provisioning: ssh command error:
command : sudo hostname conoha1 && echo "conoha1" | sudo tee /etc/hostname
err : exit status 1
output : sudo: no tty present and no askpass program specified
どうやらdocker-machineがVPSホストに入ってsudo実行しようとしてもパスワード入力が必要なので処理を続けられないようです。
ググってみると、こちらのissueで同様の話があがっており、最終的にこちらのgenericドライバーに関するドキュメントの更新に反映されています。
This user has to have password-less sudo privileges. If it's not the case, you need to edit the sudoers file and configure the user as a sudoer with NOPASSWD.
つまり、対象ユーザはsudo実行時にパスワード入力を必要としない設定にする必要があります。
私の場合、下記のように、sudoグループのユーザーはsudo実行時にパスワード入力不要の設定にしています。(この設定は当然、ユーザーを乗っ取られた場合、好き放題サーバを操作されてしまうので、設定した際にはユーザのログインしっぱなしなどを決してしないようにする必要があるでしょう。)
# Allow members of group sudo to execute any command
# %sudo ALL=(ALL:ALL) ALL # original setting
%sudo ALL=(ALL) NOPASSWD:ALL
対象リモート先Dockerホストを操作できるかを確認
はじめにVPS上のDockerをMackから操作できるか確認しましょう。
コンテキスト指定
以下のコマンドでdocker
コマンドがVPS上のDockerを指すように指定します。
$ NAME=conoha1 # docker-machine createで指定したホスト名
$ eval $(docker-machine env $NAME)
$ env | grep DOCKER # 指定した環境変数を確認
docker-machine env $NAME
は実行するとわかりますが、環境変数のexportをしているのでevalに食わせることで適用されます。
これでリモート先と繋がります。docker image ls
などを実行するとMac上のDockerではなくVPS上に配置されたDockerであることが確認できると思います。
コンテキストを解除
操作し終わったら以下のコマンドでコンテキストを解除しましょう。解除するとローカル上のDockerが対象に戻ります。
$ eval $(docker-machine env -u)
MacからDocker Composeでアプリをデプロイ
Docker ComposeでVPS上のDockerにアプリをデプロイしてみましょう。
本記事ではMySQLを利用するGo言語のAPIサーバアプリケーションを例とします。
サンプルアプリについて
ファイル構成はこのような感じです。
.
├── Dockerfile
├── db
│ └── init
│ └── init.sql
├── deploy.sh
├── docker-compose.prod.yml
├── docker-compose.yml
├── go.mod
├── go.sum
├── main.go
└── scripts
└── create_docker_machines.sh
Macのローカル上でdocker-compose build
=>docker-compose up
をするとDockerでアプリケーションが立ち上がる前提とします。
なので本記事ではDockerfile
とmain.go
のコードの詳細は割愛します。main.go
は環境変数を参照してMySQLに接続しHTTPサーバを立ち上げるアプリだとみなしてください。
docker-compose.prod.yml
で本番環境用上書き設定
普段のローカル開発ではdocker-compose.yml
のみを利用しますが、VPS環境(本番環境とします)にDocker Composeでデプロイする際はdocker-compose.prod.yml
という別ファイルを用意しdocker-compose.yml
の内容を上書きすることで環境の差異を補いましょう。
上記のサンプルアプリの例ではそれぞれ以下のようになります。
version: '2'
services:
api:
build: .
ports:
- "5000:5000"
depends_on:
- db
links:
- db
db:
image: mysql:5.7.22
ports:
- "3306:3306"
volumes:
- "./db/init:/docker-entrypoint-initdb.d"
environment:
MYSQL_ROOT_PASSWORD: localmysqlpass
MYSQL_DATABASE: superappdb
version: '2'
services:
db:
volumes:
- mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: prodsecurepass
volumes:
mysql_data:
driver: local
mysqlイメージの使い方に関しては公式を参照。
prodの方のファイルでdb
サービス(MySQL)のvolumeと環境変数を上書き変更しています。
注意点としてvolumeはDocker Machineでの操作であっても、ローカル(Mac)側ではなくリモート先(VPS)のホスト上のリソースがvolumeとなりコンテナにマウントされます。
上記のdocker-compose.prod.yml
の場合、Docker Composeのトップとしてdata volumeを明示的に定義しているので、実行するとリモート先ホスト内にvolumeが作成されデータが永続化されます。
ビルド&デプロイ用スクリプトを用意してデプロイ
デプロイ用のスクリプトを用意しましょう。上記のアプリ構成にあるdeploy.sh
がそれにあたります。
内容は以下になります。
#!/bin/bash
set -eu
export DEPLOY_DOCKER_MACHINE="conoha1" # 設定したDocker Machineの名前
export DEPLOY_SERVICE="api" # ビルド対象のDocker Composeサービス
# Change docker context to production environment
eval $(docker-machine env $DEPLOY_DOCKER_MACHINE)
# Build, and then Deploy
docker-compose build --no-cache $DEPLOY_SERVICE
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --no-deps -d $DEPLOY_SERVICE
# Reset docker context
eval $(docker-machine env -u)
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --no-deps -d
のように-f
オプションを指定することでprod設定で上書きされ、アプリがリモート先ホストで立ち上がります。
./deploy.sh
でMacからデプロイ完了です!