ようへいの日々精進XP

よかろうもん

docker-machine と DigitalOcean を使って "頼りになるのは, 近くの VM より遠くの VPS" な docker 環境を整える

tl;dr

個人的に利用している MacBook Air (11-inch, Mid 2012) は, まだ macOS Mojave のアップグレード対象になっていたりして, Apple から見放されていないようなので, しばらくは使い続けようかなと考えています. また, 購入時に奮発してメモリ 8GB にしたお陰で, 基本的な操作 (インターネットを見る, vim で何かを書く) であれば十分現役だと思っています. ということで, 今回, 利用する端末の情報は下記の通りです.

以下, OS の情報.

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.2
BuildVersion:   18C54

以下, ハードウェアの情報.

f:id:inokara:20190119172922p:plain

しかし, Docker for Mac を使っていて, Docker for Mac だけでメモリの使用量が 2GB だったりするのを見ると, 「おおっ」という気分になって Docker 環境を VPS あたりに逃してあげればメモリ使用量を抑えることが出来るよなーという思いから docker-machine と DigitalOcean を使って VPS 上に Docker 環境を揃えてみました.

頼りになるのは, 近くの VM より遠くの VPS

DigitalOcean

すでに DigitalOcean のアカウントは取得済み, アクセストークンも払い出し済みという前提で進めます. また, VPS を起動した後, 仮想マシン (以降は Droplet と呼びます) に対して Firewall の設定等を行いたいので, DigitalOcean が提供する各種リソースをコマンドラインで操作出来る doctl というツールを事前にインストールしておきましょう.

brew install doctl

今回, doctl については, 以下のバージョンを利用します.

$ doctl version
doctl version 1.12.2-release

尚, DigitalOcean の VPS にはいくつかのプラン (インスタンスタイプみたいなもの) がありますが, 今回は, 一番安価な メモリ 1GB, 1vCPU, 25GB SSD のタイプを利用します. このタイプですと, 1 時間あたり $0.007 ドル, 1 ヶ月に換算すると $5 となりますので, 一年稼働し続けても 7000 円程度と, これから MacBook Pro 13 インチあたりを新調するよりはお安く済みそうな気がします.

docker-machine

以下のバージョンの docker-machine を利用します.

$ docker-machine version
docker-machine version 0.16.0, build 702c267f

Docker 用の Droplet を起動

例のごとく, direnv を手元に用意しておくと良いでしょう. 以下のように .envrc の中に DigitalOcean のトークンを書いておきます.

export DIGITALOCEAN_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

以下のように docker-machine を実行します.

docker-machine create \
    --driver digitalocean \
    --digitalocean-access-token=${DIGITALOCEAN_ACCESS_TOKEN} \
    my-docker-host

以下, 実行例です.

$ docker-machine create \
>     --driver digitalocean \
>     --digitalocean-access-token=${DIGITALOCEAN_ACCESS_TOKEN} \
>     my-docker-host
Running pre-create checks...
Creating machine...
(my-docker-host) Creating SSH key...
(my-docker-host) Creating Digital Ocean droplet...
(my-docker-host) Waiting for IP address to be assigned to the Droplet...
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)...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env my-docker-host

docker-machine env my-docker-host を実行して, IP アドレス等を確認しましょう. 以下のように出力されます.

$ docker-machine env my-docker-host
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://xxx.xx.xx.xx:2376"
export DOCKER_CERT_PATH="/Users/user/.docker/machine/machines/my-docker-host"
export DOCKER_MACHINE_NAME="my-docker-host"
# Run this command to configure your shell:
# eval $(docker-machine env my-docker-host)

また, eval $(docker-machine env my-docker-host) を実行して環境変数に指定してしまいましょう.

Firewall を設定する

Droplet を作成するとデフォルトだと Firewall の設定は行われていません. この状態だと, どこからでも SSH アクセスが出来たり, Docker API を叩くことが可能な状態になっています. ただし, SSH でログインするには SSH キーが必要だったり, Docker にリモートアクセスする為のキーが必要だったりするので, 誰でもどこからでもアクセス出来るという状態ではありませんが...気持ち悪いので, 固定 IP からのみアクセスを許可するように Firewall を設定します.

事前に DigitalOcean の Web コンソール上で Firewall の設定をしておきましょう. 今回は MyNetwork という Firewall のエントリを事前に作成しておきましたので, 以下のように Firewall の ID と Droplet の ID を取得して Droplet に Firewall をアタッチします.

FIREWALL_ID=$(doctl compute firewall list --output=json | jq -r '.[]|select(.name | test("MyNetwork")) | .id')
DROPLET_ID=$(doctl compute droplet list --output=json | jq -r '.[]|select(.name | test("my-docker-host")) | .id')
doctl compute firewall add-droplets ${FIREWALL_ID} --droplet-ids ${DROPLET_ID}

一通り設定が終わったら

docker-machine ls してみましょう.

$ docker-machine ls
NAME             ACTIVE   DRIVER         STATE     URL                       SWARM   DOCKER     ERRORS
my-docker-host   *        digitalocean   Running   tcp://xxx.xx.xx.xx:2376           v18.09.1

docker-machine の設定を確認してみましょう.

$ docker-machine config my-docker-host
--tlsverify
--tlscacert="/Users/user/.docker/machine/machines/my-docker-host/ca.pem"
--tlscert="/Users/user/.docker/machine/machines/my-docker-host/cert.pem"
--tlskey="/Users/user/.docker/machine/machines/my-docker-host/key.pem"
-H=tcp://xxx.xx.xx.xx:2376

これで Docker を操作してみましょう

docker ps してみましょう.

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Nginx のコンテナを起動してみましょう.

$ docker run -p 80:80 -d nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
177e7ef0df69: Pull complete
ea57c53235df: Pull complete
bbdb1fbd4a86: Pull complete
Digest: sha256:b543f6d0983fbc25b9874e22f4fe257a567111da96fd1d8f1b44315f1236398c
Status: Downloaded newer image for nginx:latest
6b55bf40f43b261e97c2fcb02c729e9c26867d3aa07787d5cd55d56f42fd799a

ローカルホストではないので, コンテナにアクセスする為に docker-machine ip my-docker-host を実行して Droplet の IP アドレスを確認しつつ , 以下のように実行します.

$ curl $(docker-machine ip my-docker-host) -I
HTTP/1.1 200 OK
Server: nginx/1.15.8
Date: Sat, 19 Jan 2019 08:51:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 25 Dec 2018 09:56:47 GMT
Connection: keep-alive
ETag: "5c21fedf-264"
Accept-Ranges: bytes

いい感じです.

後始末

以下のように実行して Docker ホストを削除します. Droplet は一瞬で削除されるので驚きです.

docker-machine rm my-docker-host

以下, 実行例です.

$ docker-machine rm my-docker-host
About to remove my-docker-host
WARNING: This action will delete both local reference and remote instance.
Are you sure? (y/n): y
Successfully removed my-docker-host
$ doctl compute droplet list --output=json
null

以上

頼れるのは「近くの VM より遠くの VPS」というお話でした.