おさらい
前回までのエントリでは、Photon OS をデプロイして初期設定を行いました。
もともとの目的は、vCenter Server Appliance 6.5(vCSA 6.5)をお行儀のよい構成でインストールするために必要な DNS サーバを作ることです。よって今回は、前回構築した Photon OS 上で、bind をサービスする Docker コンテナを作ります。
設計
こんな感じにします。
ベース OS の選択には特にこだわりはないので、流行に乗って Alpine Linux にします。最新版を使います。
設定ファイルの置き場所は悩みどころですが、設定の変更などがしやすくなるのでこうしました。ポータビリティは下がりますが、配布予定もないし単一のサーバでしかホストしないのでよしとします。
Docker Compose は蛇足です。本来は複数のコンテナを連携させるときに使うものですが、使ってみたかったので使ってみます。
以降、やっぱり文字ばかりになるので、きれいな孔雀の写真を載せておきます。配色が Photon OS のそれと似ていますね。
Dockerfile を作る
まずは Dockerfile です。作ります。コンテナイメージのレシピみたいなものです。
kuro@kuro-ph01 [ ~ ]$ vim Dockerfile
kuro@kuro-ph01 [ ~ ]$ cat Dockerfile
FROM alpine:latest
RUN apk add bind --no-cache
EXPOSE 53/udp
CMD ["/usr/sbin/named", "-c", "/etc/bind/named.conf", "-u", "named", "-g"]
bind の設定ファイル群を作る
コンテナの中で動かす bind のための設定ファイルを作ります。
メインの named.conf と、ゾーン定義の二つのファイルを作りました。作ったファイルはひとつのディレクトリにまとめておきます。コンテナの中の named ユーザが読み取れるように、パーミッションも変更します。
kuro@kuro-ph01 [ ~ ]$ mkdir conf
kuro@kuro-ph01 [ ~ ]$ vim conf/named.conf
kuro@kuro-ph01 [ ~ ]$ cat conf/named.conf
acl localnet {
127.0.0.1;
192.168.0.0/24;
};
options {
version "unknown";
directory "/var/bind";
pid-file "/var/run/named/named.pid";
recursion yes;
notify no;
listen-on { any; };
listen-on-v6 { none; };
allow-query { localnet; };
allow-query-cache { localnet; };
allow-recursion { localnet; };
allow-transfer { none; };
forwarders { 192.168.0.1; };
};
zone "kuro.local" IN {
type master;
file "/etc/bind/kuro.local.zone";
};
kuro@kuro-ph01 [ ~ ]$ vim conf/kuro.local.zone
kuro@kuro-ph01 [ ~ ]$ cat conf/kuro.local.zone
$TTL 1h
@ IN SOA ns.kuro.local postmaster.kuro.local. (
2017030501 ; serial
1h ; refresh
15m ; retry
1d ; expire
1h ; minimum
);
@ IN NS ns.kuro.local.
ns IN A 192.168.0.249
kuro-vc01 IN A 192.168.0.250
kuro-esx01 IN A 192.168.0.251
kuro@kuro-ph01 [ ~ ]$ chmod 755 conf
kuro@kuro-ph01 [ ~ ]$ chmod 644 conf/*
コンテナイメージをビルドして起動する
ここまで用意ができたら、あとはビルドして起動させるだけです。
まずはビルドします。ビルドは build サブコマンドです。末尾でビルドしたい Dockerfile を含むディレクトリを指定します。今回はカレントディレクトリなのでドット(.)です。
kuro@kuro-ph01 [ ~ ]$ docker build -t bind .
Sending build context to Docker daemon 11.78 kB
Step 1 : FROM alpine:latest
latest: Pulling from library/alpine
627beaf3eaaf: Pull complete
Digest: sha256:58e1a1bb75db1b5a24a462dd5e2915277ea06438c3f105138f97eb53149673c4
Status: Downloaded newer image for alpine:latest
---> 4a415e366388
Step 2 : RUN apk add bind --no-cache
---> Running in 84d3fb22724e
fetch http://dl-cdn.alpinelinux.org/alpine/v3.5/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.5/community/x86_64/APKINDEX.tar.gz
(1/5) Installing libgcc (6.2.1-r1)
(2/5) Installing libxml2 (2.9.4-r1)
(3/5) Installing bind-libs (9.10.4_p6-r0)
(4/5) Installing libcap (2.25-r1)
(5/5) Installing bind (9.10.4_p6-r0)
Executing bind-9.10.4_p6-r0.pre-install
Executing busybox-1.25.1-r0.trigger
OK: 9 MiB in 16 packages
---> 29500538ea16
Removing intermediate container 84d3fb22724e
Step 3 : EXPOSE 53/udp
---> Running in a8ea36f4c12f
---> f08f46db2947
Removing intermediate container a8ea36f4c12f
Step 4 : CMD /usr/sbin/named -c /etc/bind/named.conf -u named -g
---> Running in a2fd9c1acd90
---> bf1581067386
Removing intermediate container a2fd9c1acd90
Successfully built bf1581067386
kuro@kuro-ph01 [ ~ ]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
bind latest bf1581067386 41 seconds ago 8.772 MB
alpine latest 4a415e366388 2 weeks ago 3.984 MB
できたイメージは images サブコマンドで確認できます。無事にできたようなので動かしてみましょう。
起動は run サブコマンドです。バックグラウンドで起動(-d)させ、ホストのポートとディレクトリをコンテナに割り当て(-p、-v)ます。
kuro@kuro-ph01 [ ~ ]$ docker run -d -p 53:53/udp -v $(pwd)/conf:/etc/bind --restart always --name bind bind
442a5494f13328641cc3ba6c526a65591874f01476255a47f962dbc8922e0f3b
kuro@kuro-ph01 [ ~ ]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
442a5494f133 bind "/usr/sbin/named -c /" 3 seconds ago Up 2 seconds 0.0.0.0:53->53/udp bind
起動状態は ps サブコマンドで確認できます。この結果の STATUS が Up になっていれば、少なくともコンテナは正しく動いています。あとはコンテナ内で bind が正しく動いていれば問題ありません。
というわけで、まずは自分自身に DNS のクエリを投げてみます。ミニマル構成の Photon OS には nslookup も dig もないので、bindutils をインストールしてから試します。
kuro@kuro-ph01 [ ~ ]$ sudo tdnf install bindutils
[sudo] password for kuro
Sorry, try again.
[sudo] password for kuro
Installing:
bindutils x86_64 9.10.4-1.ph1 6.86 M
Total installed size: 6.86 M
Is this ok [y/N]:y
Downloading:
bindutils 3116681 100%
Testing transaction
Running transaction
Complete!
kuro@kuro-ph01 [ ~ ]$ dig @192.168.0.249 kuro-vc01.kuro.local
; <<>> DiG 9.10.4-P1 <<>> @192.168.0.249 kuro-vc01.kuro.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49190
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;kuro-vc01.kuro.local. IN A
;; ANSWER SECTION:
kuro-vc01.kuro.local. 3600 IN A 192.168.0.250
;; AUTHORITY SECTION:
kuro.local. 3600 IN NS ns.kuro.local.
;; ADDITIONAL SECTION:
ns.kuro.local. 3600 IN A 192.168.0.249
;; Query time: 0 msec
;; SERVER: 192.168.0.249#53(192.168.0.249)
;; WHEN: Tue Mar 21 00:04:46 JST 2017
;; MSG SIZE rcvd: 98
kuro@kuro-ph01 [ ~ ]$ nslookup google.com 192.168.0.249
Server: 192.168.0.249
Address: 192.168.0.249#53
Non-authoritative answer:
Name: google.com
Address: 172.217.25.238
定義したゾーンの情報も引けていますし、再帰問い合わせもできています。よさそうです。
別の端末からも叩いてみます。例えば Windows から。
C:\Users\kuro>nslookup kuro-vc01.kuro.local 192.168.0.249
サーバー: UnKnown
Address: 192.168.0.249
名前: kuro-vc01.kuro.local
Address: 192.168.0.250
C:\Users\kuro>nslookup google.com 192.168.0.249
サーバー: UnKnown
Address: 192.168.0.249
権限のない回答:
名前: google.com
Address: 216.58.197.142
よいですね。
うまく動かない場合は、以下のように logs サブコマンドで named のログを見るか、
kuro@kuro-ph01 [ ~ ]$ docker logs bind
20-Mar-2017 15:00:53.955 starting BIND 9.10.4-P6 <id:a6837d0> -c /etc/bind/named.conf -u named -g
20-Mar-2017 15:00:53.955 running on Linux x86_64 4.4.41-1.ph1-esx #1-photon SMP Tue Jan 10 23:46:44 UTC 2017
20-Mar-2017 15:00:53.955 built with '--build=x86_64-alpine-linux-musl' '--host=x86_64-alpine-linux-musl' '--prefix=/usr' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--with-openssl=/usr' '--enable-linux-caps' '--with-libxml2' '--enable-threads' '--enable-filter-aaaa' '--enable-ipv6' '--enable-shared' '--enable-static' '--with-libtool' '--with-randomdev=/dev/random' '--mandir=/usr/share/man' '--infodir=/usr/share/info' 'build_alias=x86_64-alpine-linux-musl' 'host_alias=x86_64-alpine-linux-musl' 'CC=gcc' 'CFLAGS=-Os -fomit-frame-pointer -D_GNU_SOURCE' 'LDFLAGS=-Wl,--as-needed' 'CPPFLAGS=-Os -fomit-frame-pointer'
20-Mar-2017 15:00:53.955 ----------------------------------------------------
20-Mar-2017 15:00:53.955 BIND 9 is maintained by Internet Systems Consortium,
20-Mar-2017 15:00:53.955 Inc. (ISC), a non-profit 501(c)(3) public-benefit
20-Mar-2017 15:00:53.955 corporation. Support and training for BIND 9 are
20-Mar-2017 15:00:53.955 available at https://www.isc.org/support
20-Mar-2017 15:00:53.955 ----------------------------------------------------
20-Mar-2017 15:00:53.955 found 1 CPU, using 1 worker thread
20-Mar-2017 15:00:53.955 using 1 UDP listener per interface
.
.
.
あるいは、以下のようにしてコンテナ内のシェルに入って調査します。ps や ls をしているのはただの例なので、実際は自由にトラブルシュートしてください。
kuro@kuro-ph01 [ ~ ]$ docker exec -it bind /bin/ash
/ # ps -ef
PID USER TIME COMMAND
1 named 0:00 /usr/sbin/named -c /etc/bind/named.conf -u named -g
8 root 0:00 /bin/ash
12 root 0:00 ps -ef
/ # ls -l /etc/bind/
total 8
-rw-r--r-- 1 1000 1000 306 Mar 20 13:57 kuro.local.zone
-rw-r--r-- 1 1000 1000 495 Mar 20 14:04 named.conf
なお、Dockerfile で記述した通り、今回は CMD 行で named を -g で起動させています。このため、exec サブコマンドでなく attach サブコマンドを利用しても、named につながるだけで何のトラブルシュートもできない点には注意が必要です。上記のように、exec サブコマンドを利用して明示的に新規プロセスとしてシェルを起動する必要があります。また、Alpine Linux のシェルは /bin/bash ではなく /bin/ash です。
exec サブコマンドは起動中のコンテナに対してしかできない操作なので、もしそもそもコンテナの起動がコケている場合は、上記のコマンドではシェルに入れません。この場合は、exec サブコマンドを run サブコマンドに置き換えて、明示的に起動させます。これによりコンテナの CMD 指定が /bin/ash でオーバライドされるので、named は起動されずに(=コンテナが落ちずに)シェルがフォアグラウンドで実行されます。
よくあるのは、docker ps したときの STATUS が Restarting のままになるトラブルです。大体の場合、named が設定ファイルの読み込みでコケてこうなります。コケて named が落ちてコンテナが終了するものの、restart オプションによって延々と再度の起動が試行されている状態です。この場合は、ファイルのパーミッションや、ボリュームマウントの指定が正しいか確認します。
Docker Compose で操作する
ここまでで当初の最低限の要件は満たせたので、あとはオマケです。
まっさらな状態にするために、動かしていたコンテナを停止し削除、イメージも全部消しておきます。
kuro@kuro-ph01 [ ~ ]$ docker stop bind
bind
kuro@kuro-ph01 [ ~ ]$ docker rm bind
bind
kuro@kuro-ph01 [ ~ ]$ docker rmi bind
Untagged: bind:latest
Deleted: sha256:bf1581067386a7eb1de3b86773c2d89a4f901ab190d6e74679c541a91e5c1d12
Deleted: sha256:f08f46db294799dbdf60b982abc0431ffb11bb046558888b434ba3cbbe47091e
Deleted: sha256:29500538ea168fc7cee66a294b3ed90a3420cc299ac9d84896b2784ecf81f609
Deleted: sha256:c193e93d56d7b0dc758de256cf867bc724aa3ef55ddb14dfdb804b09303fb84e
kuro@kuro-ph01 [ ~ ]$ docker rmi alpine
Untagged: alpine:latest
Untagged: alpine@sha256:58e1a1bb75db1b5a24a462dd5e2915277ea06438c3f105138f97eb53149673c4
Deleted: sha256:4a415e3663882fbc554ee830889c68a33b3585503892cc718a4698e91ef2a526
Deleted: sha256:23b9c7b43573dd164619ad59e9d51eda4095926729f59d5f22803bcbe9ab24c2
kuro@kuro-ph01 [ ~ ]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
kuro@kuro-ph01 [ ~ ]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
あとは、以下な感じになるようにディレクトリを切って、これまでに作ったファイルを移動させておきます。
[~/docker]
└ [bind]
├ Dockerfile
└ [conf]
├ kuro.local.zone
└ named.conf
kuro@kuro-ph01 [ ~ ]$ mkdir -p docker/bind
kuro@kuro-ph01 [ ~ ]$ mv Dockerfile conf docker/bind
では、今回作ったコンテナを、Docker Compose で操作できるようにしてみます。
本来は複数コンテナを簡単に連携させるために使うものですが、旨味は少ないながらも単一のコンテナを操作したいだけの目的でも使えます。
まずは Docker Compose をインストールします。上記ドキュメントに記載があるコマンドをそのまま実行するだけです。
kuro@kuro-ph01 [ ~ ]$ sudo curl -L "https://github.com/docker/compose/releases/download/1.11.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 600 0 600 0 0 330 0 --:--:-- 0:00:01 --:--:-- 330
100 8066k 100 8066k 0 0 23737 0 0:05:47 0:05:47 --:--:-- 15090
kuro@kuro-ph01 [ ~ ]$ sudo chmod +x /usr/local/bin/docker-compose
kuro@kuro-ph01 [ ~ ]$ sudo docker-compose --version
docker-compose version 1.11.2, build dfed245
インストールができたら、設定ファイルを作ります。
kuro@kuro-ph01 [ ~ ]$ vim docker/docker-compose.yml
kuro@kuro-ph01 [ ~ ]$ cat docker/docker-compose.yml
version: "2.0"
services:
bind:
container_name: bind
build: bind
image: bind
volumes:
- ./bind/conf:/etc/bind
ports:
- 53:53/udp
restart: always
あとは起動させるだけです。バックグラウンドで実行させたいので、up サブコマンドに -d を付けます。
kuro@kuro-ph01 [ ~ ]$ cd docker
kuro@kuro-ph01 [ ~/docker ]$ sudo docker-compose up -d
Building bind
Step 1 : FROM alpine:latest
latest: Pulling from library/alpine
627beaf3eaaf: Pull complete
Digest: sha256:58e1a1bb75db1b5a24a462dd5e2915277ea06438c3f105138f97eb53149673c4
Status: Downloaded newer image for alpine:latest
---> 4a415e366388
Step 2 : RUN apk add bind --no-cache
---> Running in 7cb9b9b1d9c5
fetch http://dl-cdn.alpinelinux.org/alpine/v3.5/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.5/community/x86_64/APKINDEX.tar.gz
(1/5) Installing libgcc (6.2.1-r1)
(2/5) Installing libxml2 (2.9.4-r1)
(3/5) Installing bind-libs (9.10.4_p6-r0)
(4/5) Installing libcap (2.25-r1)
(5/5) Installing bind (9.10.4_p6-r0)
Executing bind-9.10.4_p6-r0.pre-install
Executing busybox-1.25.1-r0.trigger
OK: 9 MiB in 16 packages
---> 3f4617f7e3e7
Removing intermediate container 7cb9b9b1d9c5
Step 3 : EXPOSE 53/udp
---> Running in 828a66a3c5f8
---> 47c21a9ae08f
Removing intermediate container 828a66a3c5f8
Step 4 : CMD /usr/sbin/named -c /etc/bind/named.conf -u named -g
---> Running in 13e41b8d96c7
---> 85edc496264d
Removing intermediate container 13e41b8d96c7
Successfully built 85edc496264d
WARNING: Image for service bind was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating bind
docker-compose.yml の記述に従って、各サービス(コンテナ)が起動されます。build が指定されていた場合は、Dockerfile に従ってコンテナイメージのビルドも行います。
起動状態は、ps サブコマンドで確認できます。
kuro@kuro-ph01 [ ~/docker ]$ sudo docker-compose ps
Name Command State Ports
------------------------------------------------------------------
bind /usr/sbin/named -c /etc/bi ... Up 0.0.0.0:53->53/udp
ログの確認は logs サブコマンドです。
kuro@kuro-ph01 [ ~/docker ]$ sudo docker-compose logs
Attaching to bind
bind | 20-Mar-2017 16:20:24.015 starting BIND 9.10.4-P6 <id:a6837d0> -c /etc/bind/named.conf -u named -g
bind | 20-Mar-2017 16:20:24.015 running on Linux x86_64 4.4.41-1.ph1-esx #1-photon SMP Tue Jan 10 23:46:44 UTC 2017
bind | 20-Mar-2017 16:20:24.015 built with '--build=x86_64-alpine-linux-musl' '--host=x86_64-alpine-linux-musl' '--prefix=/usr' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--with-openssl=/usr' '--enable-linux-caps' '--with-libxml2' '--enable-threads' '--enable-filter-aaaa' '--enable-ipv6' '--enable-shared' '--enable-static' '--with-libtool' '--with-randomdev=/dev/random' '--mandir=/usr/share/man' '--infodir=/usr/share/info' 'build_alias=x86_64-alpine-linux-musl' 'host_alias=x86_64-alpine-linux-musl' 'CC=gcc' 'CFLAGS=-Os -fomit-frame-pointer -D_GNU_SOURCE' 'LDFLAGS=-Wl,--as-needed' 'CPPFLAGS=-Os -fomit-frame-pointer'
bind | 20-Mar-2017 16:20:24.015 ----------------------------------------------------
bind | 20-Mar-2017 16:20:24.015 BIND 9 is maintained by Internet Systems Consortium,
bind | 20-Mar-2017 16:20:24.015 Inc. (ISC), a non-profit 501(c)(3) public-benefit
bind | 20-Mar-2017 16:20:24.015 corporation. Support and training for BIND 9 are
bind | 20-Mar-2017 16:20:24.015 available at https://www.isc.org/support
bind | 20-Mar-2017 16:20:24.015 ----------------------------------------------------
bind | 20-Mar-2017 16:20:24.015 found 1 CPU, using 1 worker thread
bind | 20-Mar-2017 16:20:24.015 using 1 UDP listener per interface
.
.
.
コンテナの停止や削除は、それぞれ stop サブコマンドや rm サブコマンドで実行できます。
kuro@kuro-ph01 [ ~/docker ]$ sudo docker-compose stop
Stopping bind ... done
kuro@kuro-ph01 [ ~/docker ]$ sudo docker-compose rm
Going to remove bind
Are you sure? [yN] y
Removing bind ... done
kuro@kuro-ph01 [ ~/docker ]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
当然ながら、それぞれネイティブの docker コマンドによる操作も可能です。
イメージの削除は docker-compose コマンドではできないので、docker コマンドで個別に行う必要があります。ただし、イメージをビルドしなおしたいだけであれば、build サブコマンドを利用するか、up サブコマンドの実行時に –build オプションを付与することで実現できます。
まとめ
Docker 上で bind を動かし、Docker Compose で操作できるようにしました。
自前でがんばりたくない場合は、探せば Docker Hub に既成の bind サービス用コンテナがいくつかある(例えばこれとか)ので、そういうのを使うのも有効です。その手の既成コンテナはだいたい Webmin がくっついていて非常に楽です。
また、今回は Docker Compose を使いましたが、単一コンテナを扱いたいだけなのであれば、Makefile を利用することもできそうです。Photon OS にも make はインストールできます。
次回は vCSA 6.5 の導入を行います。