はじめに
docker run
とか docker-compose up -d
とかの 初回起動時のみ 処理したいことがある時はどうすればいいんだろう?
docker restart
とか docker-compose restart
とか systemctl restart docker
の時には動いてほしくないんだ。
やってみた結果 mariadb + zabbix で初回起動時のみ、構成用の .sql を流し込む。という動作ができるようになりました。
日本人にやさしそうなMIRACLE ZBXをdocker-composeでまとめた
経緯
zabbix の docker-compose.yml を作成しようとしたら、 dnf でインストールした後に特定ディレクトリにある .sql を MariaDB に食わせる必要がありました。
ビルド時には DB が起動してないので、流し込めない。
MariaDB の初回起動時の .sql ファイル流し込みだと、現時点の .sql は準備できるけど、zabbix のアップデートに追従できない。
rc.local 起動時のスクリプトで実行しようとしたら、ホスト機やサービスの再起動のたびに動いてしまう。
どうしよう。
動作の概要
ということで、MariaDB とか mysql とか postgresql とかの公式イメージでやってる、初回起動時の .sql 流し込みのアイデアを拝借しました。
考え方は以下のとおり
- Dockerfileの
ENTRYPOINT
でdocker-entrypoint.sh
というヘルパースクリプトを呼び出す。 - Dockerfileの
CMD
に"/sbin/init"
を書き込んでヘルパースクリプトに引数として渡す。 - ヘルパースクリプトは判別用のディレクトリの有無を確認し、
- ディレクトリが無い場合 -> 作成する
- ディレクトリが有る場合 -> なにもしない
- ヘルパースクリプトは前段の処理のあと、自身を起動した際の引数の文字列(=
/sbin/init
)を実行する
これで、コンテナを初回起動した場合のみ、特定の処理を挟み込むことができる。
検証
ホントにできるか検証します。
ファイルの準備
以下のようにファイルを準備します。
sample
|-- Dockerfile
|-- docker-compose.yml
`-- docker-entrypoint.sh
FROM centos:centos8
COPY docker-entrypoint.sh /tmp
ENTRYPOINT ["/tmp/docker-entrypoint.sh"]
CMD [ "/sbin/init" ]
version: '3'
services:
sample:
build: ./
container_name: sample
hostname: sample
restart: always
cap_add:
- SYS_ADMIN
security_opt:
- seccomp:unconfined
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
environment:
TZ: 'Asia/Tokyo'
#!/bin/sh
if [ ! -d "/tmp/check" ]; then
mkdir /tmp/check
echo `date` > /tmp/check/first_`date +%Y%m%d_%H%M%S`
else
echo `date` > /tmp/check/second_`date +%Y%m%d_%H%M%S`
fi
exec "$@"
動作確認
ビルド&初回起動 -> コンテナリスタート -> コンテナリスタート
としたとき docker-entrypoint.sh
で作成されるダミーファイルの状況を追ってみます。
# docker-compose up --build -d ; docker exec -it sample ls -1 /tmp/check
Creating network "sample_default" with the default driver
Building sample
Step 1/4 : FROM centos:centos8
---> 470671670cac
Step 2/4 : COPY docker-entrypoint.sh /tmp
---> 65969481a77a
Step 3/4 : ENTRYPOINT ["/tmp/docker-entrypoint.sh"]
---> Running in faa635fbdd2c
Removing intermediate container faa635fbdd2c
---> f0fd6de7dd9f
Step 4/4 : CMD [ "/sbin/init" ]
---> Running in 4d8a074a1da4
Removing intermediate container 4d8a074a1da4
---> cae2d8667ff6
Successfully built cae2d8667ff6
Successfully tagged sample_sample:latest
Creating sample ... done
first_20200220_213008
(↑初回起動時処理のファイルが作成されている)
# docker-compose restart ; docker exec -it sample ls -1 /tmp/check
Restarting sample ... done
first_20200220_213008
second_20200220_213025
(↑初回起動時ではない処理のファイルが作成されている)
# docker-compose restart ; docker exec -it sample ls -1 /tmp/check
Restarting sample ... done
first_20200220_213008
second_20200220_213025
second_20200220_213042
(↑初回起動時ではない処理のファイルが作成されている)
ということで、無事にそれっぽいことができました。
ここに zabbix をインストールしたときに作成される .sql を流し込めば、全自動で処理ができそうです。
もちろん、 /sbin/init
の動作もきちんとできていました。
# docker exec -it sample bash
(これでコンテナにログイン)
[root@sample /]# systemctl status
● sample
State: running
Jobs: 0 queued
Failed: 0 units
Since: Thu 2020-02-20 21:30:58 JST; 3min 14s ago
CGroup: /docker/f8a80d798e046e22c343f95b4fc9c9b8d623d0ef97ba39becfdc1debe21a0b35
tq83 bash
tq96 systemctl status
tq97 less
tqinit.scope
x mq1 /sbin/init
mqsystem.slice
tqsystemd-journald.service
x mq22 /usr/lib/systemd/systemd-journald
mqdbus.service
mq36 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
[root@sample /]#
うん、大丈夫そう。
さいごに
ん、よく考えたら、同じようなことを rc.local でやればよかったのかも。
Dockerfile のことを少し知れたので、勉強にはなりましたが。
"ヘルパースクリプト"という言葉自体、あまり使われていないのですね
実は全然イケてない方法だったり?使い方まちがってたりして?と、ちょっとビクビクします
もしくは当たり前すぎんだよ!てな感じでしょうか。。。
参考
http://docs.docker.jp/engine/reference/run.html
https://github.com/docker-library/mysql/tree/master/8.0