docker-jitsi-meetのbaseコンテナイメージ指定されている/initスクリプトは何だろうと思い調べた内容である。結論から言うと、s6というスーパバイザプログラムでプロセスを実行している。
目次
entrypoint /init
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# ...割愛 RUN \ apt-dpkg-wrap apt-get update && \ apt-dpkg-wrap apt-get install -y apt-transport-https apt-utils ca-certificates gnupg && \ apt-dpkg-wrap apt-get install -y wget && \ wget -qO - https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz | tar xfz - -C / && \ wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | apt-key add - && \ wget -q https://github.com/subchen/frep/releases/download/v1.3.5/frep-1.3.5-linux-amd64 -O /usr/bin/frep && \ apt-dpkg-wrap apt-get --purge remove -y wget && \ echo "deb https://download.jitsi.org $JITSI_RELEASE/" > /etc/apt/sources.list.d/jitsi.list && \ echo "deb http://ftp.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/backports.list && \ apt-dpkg-wrap apt-get update && \ apt-dpkg-wrap apt-get dist-upgrade -y && \ apt-cleanup && \ chmod +x /usr/bin/frep RUN \ [ "$JITSI_RELEASE" = "unstable" ] && \ apt-dpkg-wrap apt-get update && \ apt-dpkg-wrap apt-get install -y jq procps curl vim iputils-ping net-tools && \ apt-cleanup || \ true ENTRYPOINT [ "/init" ] # <-- これ |
s6 overlay
s6 overlayは、s6というunix系のスーパバイザツールをベースとしたDockerイメージ作成のためのツールセットのことらしい。s6は、daemontoolsやrunitのようなスーパバイザツールである。
Dockerfileのサンプルは以下のようになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
FROM debian:buster-slim ARG S6_VERSION=2.1.0.0 ADD https://github.com/just-containers/s6-overlay/releases/download/v$S6_VERSION/s6-overlay-amd64.tar.gz /tmp/ RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / # Do something if any # ARG PUID=1000 # ARG PGID=1000 # RUN addgroup -g ${PGID} myapp && adduser -D -u ${PUID} -G my app -h /app -D myapp ENTRYPOINT ["/init"] |
ENTRYPOINTは/initというスクリプトとなる。s6 overlayツールは、プロセス実行のライフサイクルをステージという単位で扱いプロセス実行している。docker-jitsi-meetは上記をbaseイメージとして使用し、各種サービスのコンテナイメージをbaseイメージから派生させ作成している。
s6 overlayのステージ
以下の初期ステージ、実行ステージ、終了ステージ、の3つのステージで構成される。
stage 1
イメージの準備ステージ。具体的には環境変数の設定などである。
stage 2
ユーザ提供のファイルが実行されるステージ。
- /etc/fix-attrs.dで所有者やパーミッションなどの設定
- /etc/cont-init.dのスクリプト実行
- /etc/services.dのサービスを実行しs6が監視を開始
stage 3
終了処理のステージ、プロセスのclean upと停止処理が行われる。
- /etc/cont-finish.dでfinalize処理
- SIGTERMでgracefulシャットダウン、SIGKILLで強制停止
基本的には、stage2と3のxxx.dで実行されるフックを使用し目的のプログラムを実行する感じになる。
試しに実行してみよう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$ docker run -it --rm s6demo0:latest /bin/sh [s6-init] making user provided files available at /var/run/s6/etc...exited 0. [s6-init] ensuring user provided files have correct perms...exited 0. [fix-attrs.d] applying ownership & permissions fixes... [fix-attrs.d] done. [cont-init.d] executing container initialization scripts... [cont-init.d] done. [services.d] starting services [services.d] done. # pstree s6-svscan-+-foreground---foreground---sh---pstree `-s6-supervise # Ctrl-Dで終了させる [cmd] /bin/sh exited 0 [cont-finish.d] executing container finish scripts... [cont-finish.d] done. [s6-finish] waiting for services. [s6-finish] sending all processes the TERM signal. [s6-finish] sending all processes the KILL signal and exiting. |
コンソールログから、ステージのライフサイクルを確認できる。また、実行したshは、s6-svscanというプロセスの管理下に置かれていることが分かる。s6-svscanに関する内容は以下にある。
参考)s6-svscan
s6 overlayを使ったイメージ作成と実行
単純な文字列を出力するだけのアプリを動かすイメージを作成する。
ファイル構成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ tree . . ├── Dockerfile ├── app │ ├── myapp1 │ └── myapp2 ├── docker-compose.yaml └── etc ├── cont-finish.d │ └── 01-fininalize ├── cont-init.d │ └── 01-config ├── fix-attrs.d │ └── 01-myattr └── services.d ├── myapp1 │ ├── finish │ └── run └── myapp2 ├── finish └── run 8 directories, 11 files |
- etc下にs6で必要となるリソースを配置する。すべてのステージのファイルは必要ではないが、サンプルでは用意する。
- app下にアプリケーションを置く。今回は、単なるsleepするシェルスクリプトである。
Dockerfileとdocker-compose.yaml
Dockerfile
s6 overlayのインストールとユーザ作成、/initを実行するだけのDockerfileである。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
FROM debian:buster-slim ARG S6_VERSION=2.1.0.0 # s6-overlayのインストール ADD https://github.com/just-containers/s6-overlay/releases/download/v$S6_VERSION/s6-overlay-amd64.tar.gz /tmp/ RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / # UserとGroupの作成 ARG PUID=1000 ARG PGID=1000 RUN addgroup --gid ${PGID} myapp && adduser --gid ${PGID} --uid ${PUID} --no-create-home --system myapp ENTRYPOINT ["/init"] |
docker-compose.yaml
ホスト側のフックのためのスクリプトを配置したディレクトリをマウントする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
version: "3.8" services: s6demo: image: s6demo:latest container_name: s6demo environment: MYENV: myenv volumes: - ./app:/app - ./etc/fix-attrs.d:/etc/fix-attrs.d - ./etc/cont-init.d:/etc/cont-init.d - ./etc/services.d:/etc/services.d - ./etc/cont-finish.d:/etc/cont-finish.d |
s6 overlayのリソース
etc/fix-attrs.d/01-myattr
1 |
/app true myapp,32768:32768 0700 0755 |
これは、以下の形式で記述している。/appディレクトリに対する所有者及びパーミッションを設定している。
1 |
path recurse account fmode dmode |
参考
etc/cont-init.d/01-config
1 2 3 |
#!/usr/bin/with-contenv bash echo $MYENV |
shebangで指定しているwith-contentというプログラムでは、コンテナの環境変数を構築しexecコマンドで引数で指定されるプログラムを実行している。
etc/services.d/myapp1/run
1 2 3 |
#!/usr/bin/with-contenv bash exec /app/myapp2 |
etc/services.d/myapp1/finish
1 2 3 |
#!/bin/bash echo "finish myapp1" |
etc/services.d/myapp2/run
1 2 3 |
#!/usr/bin/with-contenv bash exec /app/myapp2 |
etc/services.d/myapp2/finish
1 2 3 |
#!/bin/bash echo "finish myapp2" |
etc/cont-finish.d/
1 2 3 |
#!/bin/bash echo "finish myapp1" |
app
単なるsleepするだけのシェルスクリプト。
app/myapp1
1 2 3 4 5 6 7 8 9 |
#!/bin/bash echo "start myapp1" sleep 10 # わざと異常終了させてみる exit 1 |
app/myapp2
1 2 3 4 5 |
#!/bin/bash echo "start myapp2" sleep 20 |
イメージの実行
作成したイメージとアプリを実行してみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ docker-compose up Creating s6demo ... done Attaching to s6demo s6demo | [s6-init] making user provided files available at /var/run/s6/etc...exited 0. s6demo | [s6-init] ensuring user provided files have correct perms...exited 0. s6demo | [fix-attrs.d] applying ownership & permissions fixes... s6demo | [fix-attrs.d] 01-myattr: applying... s6demo | [fix-attrs.d] 01-myattr: exited 0. s6demo | [fix-attrs.d] done. s6demo | [cont-init.d] executing container initialization scripts... s6demo | [cont-init.d] 01-config: executing... s6demo | myenv s6demo | [cont-init.d] 01-config: exited 0. s6demo | [cont-init.d] done. s6demo | [services.d] starting services s6demo | start myapp2 s6demo | [services.d] done. s6demo | start myapp1 s6demo | finish myapp1 s6demo | start myapp1 s6demo | finish myapp2 s6demo | start myapp2 s6demo | finish myapp1 s6demo | start myapp1 ... |
このプログラムを実行すると、myapp1とmyapp2が終了しても繰り返しプロセスが実行されることが分かる(通常のサーバープログラムは、上記例のようにすぐにプロセスが終了することはない)。s6-svscanによるスーパバイザが機能していることが上記例から分かる。
1 2 3 4 5 6 7 8 9 10 11 |
$ watch --interval 1 'pstree -p -a' Every 1.0s: pstree -p -a s6-svscan,1 -t0 /var/run/s6/services |-s6-supervise,37 s6-fdholderd |-s6-supervise,267 myapp1 | `-myapp1,707 /app/myapp1 | `-sleep,709 10 `-s6-supervise,268 myapp2 `-myapp2,700 /app/myapp2 `-sleep,702 20 |
終了させる場合は、以下のようにできる。
1 2 3 4 5 |
$ docker-compose stop # or $ docker-compose kill -s SIGTERM # or $ docker-compose exec s6demo s6-svscanctl -t /var/run/s6/services |
コンテナのログには以下のように表示される。
1 2 3 4 5 6 7 8 9 |
s6demo | [cont-finish.d] executing container finish scripts... s6demo | [cont-finish.d] 01-fininalize: executing... s6demo | finish myapp s6demo | [cont-finish.d] 01-fininalize: exited 0. s6demo | [cont-finish.d] done. s6demo | [s6-finish] waiting for services. s6demo | [s6-finish] sending all processes the TERM signal. s6demo | [s6-finish] sending all processes the KILL signal and exiting. s6demo exited with code 0 |
その他
initやinit-stageXのスクリプトは、execlineというスクリプト言語で記述されている。シェルのようだがシェルとは異なる。コマンド実行に有用な機能が備わっている。
execline
参考リンク
- jitsi
- s6-overlay / s6 tools
コメント