目次
CMD
の使用s6-overlay は、インストールが簡単 (tarball 1 つまたは 2 つを抽出するだけ!) のスクリプトとユーティリティのセットで、s6 をコンテナーの pid 1 として使用し、サービスのプロセス スーパーバイザーとして使用しながら、既存の Docker イメージを使用できます。
次の Dockerfile をビルドして試してください。
# Use your favorite image
FROM ubuntu
ARG S6_OVERLAY_VERSION=3.2.0.2
RUN apt-get update && apt-get install -y nginx xz-utils
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
CMD ["/usr/sbin/nginx"]
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
ENTRYPOINT ["/init"]
docker-host $ docker build -t demo .
docker-host $ docker run --name s6demo -d -p 80:80 demo
docker-host $ docker top s6demo acxf
PID TTY STAT TIME COMMAND
11735 ? Ss 0:00 _ s6-svscan
11772 ? S 0:00 _ s6-supervise
11773 ? Ss 0:00 | _ s6-linux-init-s
11771 ? Ss 0:00 _ rc.init
11812 ? S 0:00 | _ nginx
11814 ? S 0:00 | _ nginx
11816 ? S 0:00 | _ nginx
11813 ? S 0:00 | _ nginx
11815 ? S 0:00 | _ nginx
11779 ? S 0:00 _ s6-supervise
11785 ? Ss 0:00 | _ s6-ipcserverd
11778 ? S 0:00 _ s6-supervise
docker-host $ curl --head http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Jan 2022 13:33:58 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 17 Jan 2022 13:32:11 GMT
Connection: keep-alive
ETag: "61e56fdb-264"
Accept-Ranges: bytes
s6-overlay の以前のバージョン ( v2 ) から新しいバージョン ( v3 ) に移行する場合、すべてがスムーズに機能するために、サービスまたは s6-overlay の使用方法にいくつかの変更を加える必要がある場合があります。このドキュメントでは、v3 がどのように機能するかを正確に説明するよう努めていますが、主な違いと注意が必要な点をリストした別のページを用意しています。こんな状況の方はぜひ読んでみてください!
プロジェクトには次の目標があります。
cont-init.d
)、終了処理 ( cont-finish.d
) などのタスクと、それらの間の依存関係を持つ独自のサービスを実行できるようにする単純な init プロセスPID 1
機能を提供しますs6
およびs6-portable-utils
に含まれるユーティリティのセット全体。これらには、私たちの生活をずっと楽にしてくれる、便利で構成可能なユーティリティが含まれています。s6-log
使用するlogutil-service
を通じてログをそのままローテーションします。USER
ディレクティブの一部のサポート。すべての機能と互換性があるわけではありません。詳細はメモセクションに記載されています。 よく繰り返される Docker の信条の 1 つは「コンテナーごとに 1 つのプロセス」ですが、私たちはこれに同意しません。コンテナー内で複数のプロセスを実行すること自体に悪いことはありません。より抽象的な「コンテナごとに 1 つのこと」が私たちのポリシーです。つまり、コンテナは「チャット サービスの実行」や「gitlab の実行」など、1 つのことを実行する必要があります。これには複数のプロセスが関係する場合がありますが、問題ありません。
イメージ作成者がプロセス スーパーバイザーを敬遠するもう 1 つの理由は、プロセス スーパーバイザーは失敗したサービスを再起動する必要があり、Docker コンテナーは決して停止しないと考えているためです。
これは事実上、Docker エコシステムを破壊します。ほとんどのイメージは、エラーが発生すると終了する 1 つのプロセスを実行します。エラー時に終了すると、システム管理者が好みに応じて障害を処理できるようになります。イメージが決して終了しない場合は、エラー回復と障害通知の代替方法が必要になります。
私たちのポリシーは、「物」が失敗した場合、コンテナも失敗するはずだ、というものです。これは、どのプロセスを再起動できるか、どのプロセスがコンテナを停止するかを決定することによって行われます。たとえば、 cron
またはsyslog
失敗した場合、コンテナはほとんど悪影響なく再起動できますが、 ejabberd
が失敗した場合は、システム管理者がアクションを取れるようにコンテナを終了する必要があります。
「The Docker Way」の私たちの解釈は次のようになります。
私たちの init システムはまさにそれを行うように設計されています。イメージは他の Docker イメージと同様に動作し、既存のイメージのエコシステムに適合します。
「そのもの」の停止の詳細については、「使用法」セクションの「オプションの終了スクリプトの作成」を参照してください。
私たちのオーバーレイ init は、コンテナ化された環境で適切に実行できるように適切にカスタマイズされています。このセクションではステージがどのように機能するかを簡単に説明しますが、完全な init システムがどのように機能するかを知りたい場合は、次の記事を参照してください: プロセス 1 として s6-svscan を実行する方法
/etc/cont-init.d
に含まれる従来のワンショット ユーザー スクリプトを実行します。/etc/s6-overlay/s6-rc.d
で宣言されたユーザー s6-rc サービスを、依存関係に従って実行します。/etc/services.d
) を一時ディレクトリにコピーし、s6 にそれらを開始 (および監視) させます。/etc/cont-finish.d
に含まれる終了スクリプトを実行します。TERM
シグナルを送信します。とにかくプロセスが残ってはいけません。KILL
シグナルを送信します。その後、コンテナが終了します。 s6-overlay は、イメージ上に抽出できる tarball のセットとして提供されます。必要な tarball は、使用するイメージの機能によって異なります。ほとんどの人は最初の 2 つが必要で、他のものは都合の良いときに使用できる追加機能です。
s6-overlay-noarch.tar.xz
: この tarball には、オーバーレイを実装するスクリプトが含まれています。これを「noarch」と呼ぶのは、アーキテクチャに依存しないためです。つまり、スクリプトとその他のテキスト ファイルのみが含まれています。 s6-overlay を実行したい人は全員、この tarball を抽出する必要があります。s6-overlay-x86_64.tar.xz
: x86_64
をシステムのアーキテクチャに置き換えます。この tarball には、s6 エコシステムからの必要なバイナリがすべて含まれており、すべて静的にリンクされており、イメージのバイナリの邪魔にならないようになります。オーバーレイで使用されるバイナリを提供するすべてのパッケージがイメージに既に付属していることが確実にわかっていない限り、この tarball を抽出する必要があります。s6-overlay-symlinks-noarch.tar.xz
: この tarball には s6-overlay スクリプトへのシンボリックリンクが含まれているため、 /usr/bin
経由でアクセスできます。通常は必要ありません。すべてのスクリプトは PATH 環境変数を介してアクセスできますが、 #!/usr/bin/with-contenv
などのシバンを含む古いユーザー スクリプトがある場合は、これらのシンボリックリンクをインストールすると機能するようになります。s6-overlay-symlinks-arch.tar.xz
: この tarball には、2 番目の tarball によって提供される s6 エコシステムからのバイナリへのシンボリックリンクが含まれており、 /usr/bin
経由でアクセスできるようになります。通常は必要ありませんが、 #!/usr/bin/execlineb
などのシバンを含む古いユーザー スクリプトがある場合は、これらのシンボリック リンクをインストールすると機能するようになります。syslogd-overlay-noarch.tar.xz
: この tarball には、 syslogd
サービスの定義が含まれています。 s6 ログ インフラストラクチャを利用するために stderr にログを記録できないデーモンを実行しているが、古いsyslog()
メカニズムの使用をハードコードしている場合は、この tarball を抽出することができ、コンテナはsyslogd
デーモンの軽量エミュレーションを実行します。そのため、syslog ログが捕捉されてディスクに保存されます。これらの tarball をインストールするには、インストールする機能に対応する行を Dockerfile に追加します。たとえば、ほとんどの人は次のように使用します。
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
抽出時にファイルのアクセス許可を必ず保持してください (つまり、 tar
に-p
オプションを使用します)。
プロジェクトは標準の .tar.xz ファイルのセットとして配布されており、イメージのルートで抽出します。 ( tar
.tar.xz
ファイルを理解するには、xz-utils パッケージが必要です。このパッケージはすべてのディストリビューションで利用可能ですが、デフォルトのコンテナー イメージで常に利用できるわけではないため、 apt install xz-utils
またはapk add xz
が必要になる場合があります。アーカイブを展開する前に、同等のものを作成してください)。
その後、 ENTRYPOINT
を/init
に設定します。
現時点では、 RUN
ディレクティブでwget
またはcurl
実行する代わりに、Docker のADD
ディレクティブを使用することをお勧めします。 ADD
使用すると、Docker は https URL を処理できますが、ベース イメージでは https を使用できないか、https URL を使用できない可能性があります。 wget
またはcurl
がインストールされていること。
そこからは、いくつかのオプションがあります。
CMD
として実行します。CMD
の使用CMD
使用すると、オーバーレイを活用する便利な方法です。 CMD
、ビルド時に Dockerfile で指定することも、実行時にコマンド ラインで指定することもできます。どちらの方法でも問題ありません。これは、s6 によってセットアップされた環境で通常のプロセスとして実行されます。失敗するか終了すると、コンテナは正常にシャットダウンして終了します。この方法で対話型プログラムを実行できます。CMD のみが対話型コマンドを受け取り、サポート プロセスには影響がありません。
例えば:
FROM busybox
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
ENTRYPOINT ["/init"]
docker-host $ docker build -t s6demo .
docker-host $ docker run -ti s6demo /bin/sh
/package/admin/s6-overlay/libexec/preinit: notice: /var/run is not a symlink to /run, fixing it
s6-rc: info: service s6rc-oneshot-runner: starting
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
s6-rc: info: service legacy-services successfully started
/ # ps
PID USER TIME COMMAND
1 root 0:00 /package/admin/s6/command/s6-svscan -d4 -- /run/service
17 root 0:00 {rc.init} /bin/sh -e /run/s6/basedir/scripts/rc.init top /bin/sh
18 root 0:00 s6-supervise s6-linux-init-shutdownd
20 root 0:00 /package/admin/s6-linux-init/command/s6-linux-init-shutdownd -c /run/s6/basedir -g 3000 -C -B
24 root 0:00 s6-supervise s6rc-fdholder
25 root 0:00 s6-supervise s6rc-oneshot-runner
31 root 0:00 /package/admin/s6/command/s6-ipcserverd -1 -- /package/admin/s6/command/s6-ipcserver-access -v0 -E -l0 -i data/rules -- /packa
58 root 0:00 /bin/sh
66 root 0:00 ps
/ # exit
s6-rc: info: service legacy-services: stopping
s6-rc: info: service legacy-services successfully stopped
s6-rc: info: service legacy-cont-init: stopping
s6-rc: info: service legacy-cont-init successfully stopped
s6-rc: info: service fix-attrs: stopping
s6-rc: info: service fix-attrs successfully stopped
s6-rc: info: service s6rc-oneshot-runner: stopping
s6-rc: info: service s6rc-oneshot-runner successfully stopped
docker-host $
s6-overlay でコンテナを使用するもう 1 つの方法は、サービスを監視対象にすることです。任意の数のサービスを監視できます。通常、これらは CMD として実行するメイン デーモンのサポート サービスにすぎませんが、それが必要な場合は、空の CMD を使用してメイン デーモンを監視対象サービスとして実行することも妨げられません。その場合、デーモンは終了するたびに s6 によって再起動されます。コンテナーは、 docker stop
コマンドを介して、またはコンテナー内から/run/s6/basedir/bin/halt
コマンドを使用して停止するように指示された場合にのみ停止します。
監視付きサービスを作成するには 2 つの方法があります。現在もサポートされている古い方法は、「純粋な s6」サービス ディレクトリを作成することです。 /etc/services.d
にサービスの名前のディレクトリを作成し、そこに実行可能run
ファイルを置きます。これは、長期間存続するプロセスの実行を保存するファイルです。サービス ディレクトリの監視の詳細と、s6 がデーモンを処理する方法を構成する方法については、servicedir ドキュメントを参照してください。簡単な例は次のようになります。
/etc/services.d/myapp/run
:
#!/command/execlineb -P
nginx -g "daemon off;"
新しい方法は、 /etc/s6-overlay/s6-rc.d
ディレクトリに s6-rcソース定義ディレクトリを作成し、そのディレクトリの名前をuser
バンドルに追加します。つまり、同じ名前の空のファイルを作成します。 /etc/s6-overlay/s6-rc.d/user/contents.d
ディレクトリ内。このページでは、ソース定義ディレクトリの形式について説明します。 /etc/services.d
メソッドと同様に、 longruns (つまり、s6 によって監視されるデーモン) を定義できるだけでなく、 oneshots (つまり、1 回実行して終了するプログラム) も定義できることに注意してください。メインのサービスは、おそらくoneshotではなく、 longrunです。おそらく、常駐するデーモンが必要です。
この新しい形式の利点は、サービス間の依存関係を定義できることです。 B がAに依存している場合、最初にAが開始され、次にA の準備ができたときにBが開始され、コンテナーの終了が指示されるとBが停止します。最初に、次にA 。さまざまなプロセスが相互に依存する複雑なアーキテクチャがある場合、または単にワンショットとロングランを正確な順序で混在させる必要がある場合、これが最適です。
上の例は次のように書き直すことができます。
/etc/s6-overlay/s6-rc.d/myapp/type
:
longrun
/etc/s6-overlay/s6-rc.d/myapp/run
:
#!/command/execlineb -P
nginx -g "daemon off;"
/etc/s6-overlay/s6-rc.d/user/contents.d/myapp
: 空のファイル。 (これにより、s6-rc がコンテナーの起動時に開始するサービスのセットにmyapp
が追加されます。)
/etc/s6-overlay/s6-rc.d/myapp/dependencies.d/base
: 空のファイル。 (これにより、すべての基本サービスの準備ができた場合にのみmyapp
開始するように s6-rc に指示されます。これにより、競合状態が防止されます。)
新しい形式に切り替えることをお勧めしますが、その利点が必要ない場合は、 /etc/services.d
内の通常のサービス ディレクトリをそのまま使用しても問題なく機能します。
メイン サービスを CMD として実行する場合、何もする必要はありません。CMD が終了するとき、またはdocker stop
実行すると、コンテナーはサービスと同じ終了コードで自然に終了します。 (ただし、 docker stop
の場合、サービスは SIGTERM を取得することに注意してください。この場合、終了コードはサービスの処理方法に完全に依存します。トラップして 0 を終了することも、トラップして別の何かを終了することもできます。 、またはトラップせず、シェルに独自のコードを終了させます (通常は 130)。
ただし、メイン サービスを監視対象サービスとして実行する場合は状況が異なり、 docker stop
コマンドを送信するときにコンテナーにどのコードで終了するかを指示する必要があります。これを行うには、 finish
スクリプトを作成する必要があります。
/etc/services.d
内のレガシー サービスである場合は、実行可能な/etc/services.d/myapp/finish
スクリプトが必要です。/etc/s6-overlay/s6-rc.d/myapp/finish
ファイルが必要です (ファイルは実行可能である場合とそうでない場合があります)。このfinish
スクリプトはサービスの終了時に実行され、次の 2 つの引数を受け取ります。
finish
スクリプトでは、必要なコンテナ終了コードを/run/s6-linux-init-container-results/exitcode
ファイルに書き込む必要があります。それだけです。
たとえば、上記のmyapp
サービスのfinish
スクリプトは次のようになります。
#! /bin/sh
if test " $1 " -eq 256 ; then
e= $(( 128 + $2 ))
else
e= " $1 "
fi
echo " $e " > /run/s6-linux-init-container-results/exitcode
docker stop
コマンドをコンテナーに送信すると、 myapp
サービスが強制終了され、このスクリプトが実行されます。 myapp
の終了コード ( myapp
TERM シグナルをキャッチした場合) または 130 ( myapp
TERM シグナルをキャッチしなかった場合) を特別な/run/s6-linux-init-container-results/exitcode
ファイルに書き込みます。コンテナのシャットダウン手順の最後に s6-overlay によって読み取られ、コンテナはその値で終了します。
このセクションでは、s6-overlay v3より前のバージョンの機能について説明します。 fix-attrs は v3 でもまだサポートされていますが、いくつかの理由で非推奨になっています。その 1 つは、所有権を静的に変更できる場合に動的に変更するのは一般的に良いポリシーではないということです。もう 1 つの理由は、USER コンテナでは機能しないことです。 fix-attrs の代わりに、コンテナーを実行する前に、オフラインでホストをマウントする際の所有権と権限を管理することをお勧めします。必要な情報がすべて揃ったら、これを Dockerfile で行う必要があります。
とはいえ、以下は以前のバージョン用に書いたもので、現在でも適用可能です (ただし、これに依存するのはやめてください)。
たとえば、コンテナ内にホスト フォルダーをマウント/マップした場合など、続行する前に所有権とアクセス許可を修正すると興味深い場合があります。私たちのオーバーレイは、 /etc/fix-attrs.d
内のファイルを使用してこの問題に対処する方法を提供します。これは、fix-attrs ファイルが続くパターン形式です。
path recurse account fmode dmode
path
: ファイルまたはディレクトリのパス。recurse
: ( true
またはfalse
に設定します) フォルダーが見つかった場合、そのフォルダーに含まれるすべてのファイルとフォルダーを再帰的に調べます。account
: 対象のアカウント。アカウントが見つからない場合は、デフォルトでフォールバックuid:gid
を設定することができます。たとえば、 nobody,32768:32768
最初にnobody
アカウントを使用しようとし、その後、代わりにuid 32768
にフォールバックします。たとえば、 daemon
アカウントがUID=2
およびGID=2
の場合、 account
フィールドに指定できる値は次のとおりです。daemon: UID=2 GID=2
daemon,3:4: UID=2 GID=2
2:2,3:4: UID=2 GID=2
daemon:11111,3:4: UID=2 GID=11111
11111:daemon,3:4: UID=11111 GID=2
daemon:daemon,3:4: UID=2 GID=2
daemon:unexisting,3:4: UID=2 GID=4
unexisting:daemon,3:4: UID=3 GID=2
11111:11111,3:4: UID=11111 GID=11111
fmode
: ターゲットファイルモード。たとえば、 0644
。dmode
: ターゲットディレクトリ/フォルダーモード。たとえば、 0755
。ここにいくつかの実際の例があります。
/etc/fix-attrs.d/01-mysql-data-dir
:
/var/lib/mysql true mysql 0600 0700
/etc/fix-attrs.d/02-mysql-log-dirs
:
/var/log/mysql-error-logs true nobody,32768:32768 0644 2700
/var/log/mysql-general-logs true nobody,32768:32768 0644 2700
/var/log/mysql-slow-query-logs true nobody,32768:32768 0644 2700
これを行う古い方法は次のとおりです。
( /etc/fix-attrs.d/
を介して) 属性を修正した後、( s6-rc または/etc/services.d
を介して) ユーザーが提供するサービスを開始する前に、オーバーレイは/etc/cont-init.d
、たとえば:
/etc/cont-init.d/02-confd-onetime
:
#!/command/execlineb -P
with-contenv
s6-envuidgid nginx
multisubstitute
{
import -u -D0 UID
import -u -D0 GID
import -u CONFD_PREFIX
define CONFD_CHECK_CMD "/usr/sbin/nginx -t -c {{ .src }}"
}
confd --onetime --prefix="${CONFD_PREFIX}" --tmpl-uid="${UID}" --tmpl-gid="${GID}" --tmpl-src="/etc/nginx/nginx.conf.tmpl" --tmpl-dest="/etc/nginx/nginx.conf" --tmpl-check-cmd="${CONFD_CHECK_CMD}" etcd
この方法はまだサポートされています。ただし、より一般的で効率的な方法が登場しました。それは、 /etc/s6-overlay/s6-rc.d
にサービス定義ディレクトリを追加して、それらを一部にすることで、ワンショットの初期化タスクと終了タスクを s6-rc サービスとして作成することです。 user
バンドルの設定 (コンテナの起動時に実際に開始される)、 base
バンドルに依存するようにします (つまり、 base
後にのみ開始されます)。
s6-rc に関するすべての情報はここにあります。
コンテナーが開始されると、操作は次の順序で実行されます。
/etc/fix-attrs.d
内のファイルに従って実行されます。/etc/cont-init.d
内のワンショット初期化スクリプトは順番に実行されます。user
バンドル内のサービスは、依存関係によって定義された順序で s6-rc によって開始されます。サービスは、ワンショット (初期化タスク) またはロングラン (コンテナーの存続期間全体にわたって実行されるデーモン) の場合があります。サービスがbase
に依存している場合、サービスはそれ以前ではなくこの時点で開始されることが保証されます。そうでない場合は、より早く開始されている可能性があり、競合状態が発生する可能性があります。そのため、常にbase
に依存させることをお勧めします。/etc/services.d
の Longrun サービスが開始されます。user2
バンドル内のサービスが開始されます。 (ほとんどの人はこれを使用する必要はありません。よくわからない場合は、 user
バンドルを使用してください。)管理者が停止コマンドを送信したか、CMD が終了したためにコンテナーが停止すると、操作は逆の順序で実行されます。
user2
バンドル内のサービスが停止されます。/etc/services.d
の Longrun サービスが停止されます。down
スクリプトが実行されることを意味します。これが、s6-rc がファイナライズ タスクを実行できる方法です。/etc/cont-finish.d
内のワンショット終了スクリプトは順番に実行されます。 user2
バンドルのポイントは、その中で宣言されたユーザー サービスが/etc/services.d
バンドルの後に開始できるようにすることです。ただし、そのためには、 user2
のすべてのサービスが、 legacy-services
への依存関係を宣言する必要があります。つまり、サービスfoobar
遅く開始するには、次のことを行う必要があります。
/etc/s6-overlay/s6-rc.d/foobar
-rc.d/foobar で定義します。/etc/s6-overlay/s6-rc.d/foobar/dependencies.d/legacy-services
ファイルを追加します/etc/s6-overlay/s6-rc.d/user2/contents.d/foobar
ファイルを追加します。これにより、 foobar
/etc/services.d
内のすべての内容の後に開始されます。
デフォルトでは、 /etc/services.d
に作成されたサービスは自動的に再起動されます。サービスがコンテナを停止させる必要がある場合は、代わりにそれを CMD として実行する必要があります。ただし、監視対象サービスとして実行したい場合は、サービスが停止したときに実行されるfinish
スクリプトを作成する必要があります。コンテナを停止するには、 /run/s6/basedir/bin/halt
コマンドを呼び出す必要があります。終了スクリプトの例を次に示します。
/etc/services.d/myapp/finish
:
#!/command/execlineb -S0
foreground { redirfd -w 1 /run/s6-linux-init-container-results/exitcode echo 0 }
/run/s6/basedir/bin/halt
スクリプトの最初の行は/run/s6-linux-init-container-results/exitcode
ファイルに0
書き込みます。 2 行目でコンテナを停止します。コンテナ内から/run/s6/basedir/bin/halt
コマンドを実行してコンテナを停止すると、 /run/s6-linux-init-container-results/exitcode
が読み取られ、その内容が終了コードとして使用されます。コンテナを起動したdocker run
コマンド。ファイルが存在しない場合、またはdocker stop
などの理由でコンテナーが停止した場合、その終了コードはデフォルトで 0 になります。
終了スクリプトでは、より高度な操作を行うことができます。たとえば、ゼロ以外で終了した場合にのみサービスを停止するスクリプトを次に示します。
/etc/services.d/myapp/finish
:
#!/command/execlineb -S1
if { eltest ${1} -ne 0 -a ${1} -ne 256 }
/run/s6/basedir/bin/halt
一般に、終了スクリプトは、デーモンが終了した後のローカルのクリーンアップにのみ使用する必要があることに注意してください。サービスが非常に重要であるため、サービスが停止したときにコンテナーを停止する必要がある場合は、それを CMD として実行することを強くお勧めします。
すべてのサービスは専用のロガーを持つことができます。ロガーは、サービスの標準出力から自動的に読み取り、必要な場所にある自動的にローテーションされるファイルにデータを記録する s6 サービスです。通常、デーモンは stdout ではなく stderr にログを記録するので、 stderr をキャッチするには、シェルでexec 2>&1
を使用するか、execline でfdmove -c 2 1
を使用してサービスの実行スクリプトを開始する必要があることに注意してください。
s6-overlay は、 s6-log
プログラムのラッパーであるlogutil-service
と呼ばれるユーティリティを提供します。このヘルパーは次のことを行います。
S6_LOGGING_SCRIPT
に含まれるロギング スクリプトを読み取るnobody
ユーザーにドロップします(存在しない場合のデフォルトは65534:65534
) s6-log は永久に実行され、サービスからデータを読み取り、 logutil-service
に指定したディレクトリにデータを書き込みます。
ご注意ください:
s6-setuidgid
でユーザーを切り替える必要はありません。nobody
ユーザーが書き込み可能ですnobody
でも書き込み可能です。ログ フォルダーは、 cont-init.d
スクリプト内で、または s6-rc ワンショットとして作成できます。以下は、古い方法で実装されたログ記録サービスmyapp
の例です。
/etc/cont-init.d/myapp-log-prepare
:
#! /bin/sh -e
mkdir -p /var/log/myapp
chown nobody:nogroup /var/log/myapp
chmod 02755 /var/log/myapp
/etc/services.d/myapp/run
:
#! /bin/sh
exec 2>&1
exec mydaemon-in-the-foreground-and-logging-to-stderr
/etc/services.d/myapp/log/run
:
#! /bin/sh
exec logutil-service /var/log/myapp
そして、これは s6-rc に実装された同じサービス myapp です。
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/dependencies.d/base
: 空のファイル
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/type
:
oneshot
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/up
:
if { mkdir -p /var/log/myapp }
if { chown nobody:nogroup /var/log/myapp }
chmod 02755 /var/log/myapp
(詳細セクションの始まり)
したがって、 up
ファイルとdown
ファイルは特別です。これらはシェル スクリプトではなく、execlineb によって解釈される単一のコマンド ラインです。 execline について心配する必要はありません。 up
ファイルには 1 つのコマンド ラインが含まれることだけを覚えておいてください。したがって、複数の命令を含むスクリプトが必要な場合は、次の方法で実行できます。
up
ファイルでそのスクリプトを呼び出します。通常、 myapp-log-prepare
のファイルをup
する方法は次のとおりです。
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/up
:
/etc/s6-overlay/scripts/myapp-log-prepare
/etc/s6-overlay/scripts/myapp-log-prepare
: (実行可能である必要があります)
#! /bin/sh -e
mkdir -p /var/log/myapp
chown nobody:nogroup /var/log/myapp
chmod 02755 /var/log/myapp
実際のスクリプトの場所は任意で、 up
ファイルに記述している内容と一致する必要があるだけです。
ただし、ここではたまたま、スクリプトが非常に単純であるため、複雑になりすぎたり、理解しにくくなったりすることなく、 up
ファイルに完全に収まります。したがって、その気になれば、 up
ファイルを使用してさらに多くのことができることを示すために、これを例として含めることにしました。 execline 言語の完全なドキュメントはここで読むことができます。
(詳細セクションの最後で、上の三角形をもう一度クリックすると折りたたまれます。)
/etc/s6-overlay/s6-rc.d/myapp/dependencies.d/base
: 空のファイル
/etc/s6-overlay/s6-rc.d/myapp-log/dependencies.d/myapp-log-prepare
: 空のファイル
/etc/s6-overlay/s6-rc.d/myapp/type
:
longrun
/etc/s6-overlay/s6-rc.d/myapp/run
:
#! /bin/sh
exec 2>&1
exec mydaemon-in-the-foreground-and-logging-to-stderr
/etc/s6-overlay/s6-rc.d/myapp/producer-for
:
myapp-log
/etc/s6-overlay/s6-rc.d/myapp-log/type
:
longrun
/etc/s6-overlay/s6-rc.d/myapp-log/run
:
#! /bin/sh
exec logutil-service /var/log/myapp
/etc/s6-overlay/s6-rc.d/myapp-log/consumer-for
:
myapp
/etc/s6-overlay/s6-rc.d/myapp-log/pipeline-name
:
myapp-pipeline
/etc/s6-overlay/s6-rc.d/user/contents.d/myapp-pipeline
: 空のファイル
それはたくさんのファイルです!それが何を意味するのかを要約すると次のとおりです。
myapp | myapp-log
パイプラインにはmyapp-pipeline
名前が付けられ、この名前はuser
バンドルの一部として宣言されるため、コンテナーの起動時に開始されます。myapp-log-prepare
、 myapp-log
、およびmyapp
すべてbase
バンドルに依存します。つまり、これらはシステムが実際に起動する準備ができたときにのみ起動されます。実際には、 /etc/cont-init.d
と/etc/services.d
メソッドと同じことを実現しますが、内部的にははるかにクリーンで、より複雑な依存関係グラフを処理できるため、機会があればいつでもお勧めします。サービスとロガーを宣言する s6-rc 方法に慣れてください。サービスがロングランかワンショットかの宣言、パイプラインの宣言、必要な場合のサービス固有のタイムアウトの追加など、サービス定義ディレクトリの完全な構文は、ここにあります。
サービスを実行する場合は、それがサービスであってもロガーであっても、実行する前に権限を削除することをお勧めします。 s6
まさに次のようなことを行うためのユーティリティがすでに含まれています。
execline
中:
#!/command/execlineb -P
s6-setuidgid daemon
myservice
sh
で:
#! /bin/sh
exec s6-setuidgid daemon myservice
これらのユーティリティについて詳しく知りたい場合は、 s6-setuidgid
、 s6-envuidgid
、およびs6-applyuidgid
を参照してください。
カスタム スクリプトでコンテナ環境を利用できるようにしたい場合は、 with-contenv
ヘルパーを使用できます。これにより、これらすべてが実行環境にプッシュされます。次に例を示します。
/etc/cont-init.d/01-contenv-example
:
#! /command/with-contenv sh
env
このスクリプトはコンテナ環境の内容を出力します。
Docker の最新バージョンでは、読み取り専用のルート ファイルシステムでコンテナーを実行できます。コンテナがそのような場合は、 S6_READ_ONLY_ROOT=1
設定して、特定の領域への書き込みを試行しないように s6-overlay に通知する必要があります。代わりに、 /run
にマウントされた tmpfs へのコピーが実行されます。
s6-overlay は次のことを前提としていることに注意してください。
/run
存在し、書き込み可能です。そうでない場合は、そこに tmpfs をマウントしようとします。/var/run
、以前のバージョンとの互換性を保つための/run
へのシンボリック リンクです。そうでない場合は、そうなってしまいます。一般に、デフォルトの docker 設定では、 /run
に適切な tmpfs がすでに提供されているはずです。
あらかじめ定義された環境変数のセットを実行コンテキストに提供することで、何らかの方法で s6-overlay の動作を微調整することが可能です。
PATH
(デフォルト = /command:/usr/bin:/bin
): これは、CMD を含むコンテナ内のすべてのサービスが持つデフォルトの PATH です。別のディレクトリ (例: /usr/sbin
に保存されたバイナリに依存するサービスが多数ある場合は、この変数を設定します。 /command
、 /usr/bin
、 /bin
は、指定したパスにまだ存在しない場合、常にそのパスに追加されることに注意してください。S6_KEEP_ENV
(デフォルト = 0): 設定されている場合、環境はリセットされず、監視ツリー全体が元の環境変数セットを参照します。 with-contenv
nop に切り替えます。S6_LOGGING
(デフォルト = 0):0
: すべてを stdout/stderr に出力します。1
: 内部catch-all
ロガーを使用し、すべてをそのロガーに保存します。ロガーは/var/log/s6-uncaught-logs
にあります。 CMD
として実行されるものはすべて、stdout/stderr に出力されます。2
: 内部catch-all
ロガーを使用し、 CMD
の出力を含むすべてをロガーに保存します。 stdout/stderr には何も書き込まれません。S6_CATCHALL_USER
(デフォルト = root): 設定されており、 S6_LOGGING
が 1 または 2 の場合、キャッチオール ロガーはこのユーザーとして実行されます。このユーザーはイメージの/etc/passwd
で定義する必要があります。あらゆる権限の分離は、セキュリティに多少なりとも役立ちます。S6_BEHAVIOUR_IF_STAGE2_FAILS
(デフォルト = 0): サービス スクリプトの 1 つが失敗した場合にコンテナが行うべき動作を決定します。これには以下が含まれます:fix-attrs
で何かが失敗した場合/etc/cont-init.d
または新しいスタイルの s6-rc ワンショットが失敗した場合/etc/services.d
または新しいスタイルの s6-rc longrun が準備完了通知を期待しているとしてマークされ、割り当てられた時間内に準備完了に失敗した場合 (下記のS6_CMD_WAIT_FOR_SERVICES_MAXTIME
を参照)。 S6_BEHAVIOUR_IF_STAGE2_FAILS
の有効な値は次のとおりです。0
: スクリプトが失敗してもサイレントに続行します。1
: 続行しますが、煩わしいエラー メッセージで警告します。2
: コンテナを停止します。S6_KILL_FINISH_MAXTIME
(デフォルト = 5000): シャットダウン時に、 /etc/cont-finish.d
内のスクリプトが自然に終了するまでシステムが待機する時間 (ミリ秒単位)。この時間が経過すると、スクリプトに SIGKILL が送信されます。 /etc/cont.finish.d
内のスクリプトは順番に実行され、シャットダウン シーケンスはスクリプトごとにS6_KILL_FINISH_MAXTIME
ミリ秒待機する可能性があることに注意してください。S6_SERVICES_READYTIME
(デフォルト = 50): /etc/services.d
で宣言されたサービスでは、サービスが開始された瞬間と、サービスの準備が整っているかどうかをテストできる瞬間との間に、避けられない競合状態が発生します。この競合を避けるために、準備が整っているかどうかをテストする前に、少しの間 (デフォルトでは 50 ミリ秒) スリープします。マシンが遅いか非常にビジーな場合、 s6-svwait: fatal: unable to s6_svstatus_read: No such file or directory
ようなエラーが発生することがあります。その場合は、 S6_SERVICES_READYTIME
変数でスリープ時間を (ミリ秒単位で) 宣言して、スリープ時間を増やす必要があります。これは/etc/services.d
のみに関係することに注意してください。 s6-rc は競合状態の影響を受けません。S6_SERVICES_GRACETIME
(デフォルト = 3000): シャットダウン時に、残りのシャットダウンを続行する前に/etc/services.d
で宣言されたサービスが終了するまでs6
が待機する時間 (ミリ秒単位)。S6_KILL_GRACETIME
(デフォルト = 3000): すべてのプロセスが TERM シグナルを受信したシャットダウン手順の最後に、プロセスが終了していることを確認するためにKILL
シグナルを送信する前にプロセスが終了するまで、 s6
が待機する時間 (ミリ秒) 。S6_LOGGING_SCRIPT
(デフォルト = "n20 s1000000 T"): この環境は、何をどのようにログに記録するかを決定します。デフォルトでは、すべての行の先頭に ISO8601 が追加され、現在のログ ファイルが 1MB に達するとローテーションされ、最大 20 ファイルでアーカイブされます。S6_CMD_ARG0
(デフォルト = 設定なし): この環境変数の値は、Docker によって渡されるCMD
引数の先頭に追加されます。既存のイメージを s6-overlay に移行し、それをドロップイン置換にしたい場合に使用します。この変数を以前に使用した ENTRYPOINT の値に設定すると、移行が容易になります。S6_CMD_USE_TERMINAL
(デフォルト = 0): 出力にターミナルを必要とする CMD があり (通常、 docker run -it
でコンテナーを実行しているとき)、 S6_LOGGING
ゼロ以外の値に設定している場合は、この値を 1 に設定します。この設定により、CMD が実際に端末に出力されます。欠点は、出力がログに記録されないことです。デフォルト (この変数が0または未設定の場合) では、 S6_LOGGING
がゼロ以外の場合、CMD の stdout と stderr がログに記録されます。つまり、対話型ターミナルで実行している場合でも、それらはパイプに送られます。S6_FIX_ATTRS_HIDDEN
(デフォルト = 0): fix-attrs.d
スクリプトがファイルとディレクトリを処理する方法を制御します。0
: 隠しファイルと隠しディレクトリは除外されます。1
: すべてのファイルとディレクトリが処理されます。S6_CMD_WAIT_FOR_SERVICES
(デフォルト = 0): デフォルトでは、コンテナーが起動すると、 /etc/services.d
内のサービスが開始され、実行はuser2
バンドルと CMD (これらのいずれかが定義されている場合) の開始に進みます。ただし、 S6_CMD_WAIT_FOR_SERVICES
がゼロではない場合、コンテナの開始シーケンスは、 /etc/services.d
のサービスが準備ができてから、シーケンスの残りを進める前に待機します。これは、 /etc/services.d
のサービスがS6に準備ができている場合にのみ重要であることに注意してください。S6_CMD_WAIT_FOR_SERVICES_MAXTIME
(default = 0、ie infinite):最大時間(ミリ秒単位)サービスがCMD実行の手続き前に育てることができます。潜在的に無期限にブロックできるサービスがある場合、この変数を正の値に設定し、特定の時間の後にすべてが起きていなくても、コンテナを故障させることを好む。この値には、レガシーコンテナの初期化( /etc/cont-init.d
)およびサービス( /etc/services.d
)のセットアップ時間も含まれていることに注意してください。したがって、適切な値を計算するときに考慮してください。最大3.1.6.2までのS6-overlayのバージョンでは、デフォルトは5000(5秒)でしたが、解決した問題よりも不要なコンテナ障害が多いため、デフォルトではタイムアウトがありません。すべてのサービスを育てるために必要です。S6_READ_ONLY_ROOT
(default = 0):ルートファイルシステムが読み取り専用のコンテナで実行される場合、このenvを1に設定して、ユーザーが提供する初期化スクリプトを/etc
から/run/s6/etc
にコピーする必要があることをINITステージ2に通知します詳細については、許可などを変更しようとしています。読み取り専用のルートファイルシステムを参照してください。S6_SYNC_DISKS
(default = 0):このenvを1に設定して、INITステージ3にコンテナを停止する前にファイルシステムを同期しようとすることを通知します。注:これにより、ホストのすべてのファイルシステムが同期される可能性があります。S6_STAGE2_HOOK
(default = none):この変数が存在する場合、その内容は、サービスが開始される前に初期段階2で実行されるシェル抜粋として解釈されます。これを使用して、コンパイルおよび実行する直前に実行時にサービスデータベースに動的にパッチを当てることができます。間違った値は、コンテナがセキュリティを実行したり、セキュリティを危険にさらすのを防ぐことができるため、自分が何をしているのかを正確に知っている場合にのみ使用してください。疑わしい場合は、この変数を未定義のままにしておきます。S6_VERBOSITY
(デフォルト= 2):コンテナの開始時間と停止時間で、S6-RCおよび潜在的に他のツールの冗長性を制御します。デフォルトの2は通常冗長です。サービスの開始と停止操作をリストします。この数値を減らすことにより、コンテナを静かにすることができます。1は警告とエラーのみを印刷し、0はエラーのみを印刷します。また、この数を最大5に増やすことにより、コンテナをより冗長にする、つまり印刷のトレース情報とデバッグ情報を作成することもできますが、出力はすぐに非常に騒々しくなり、ほとんどの人はこれを必要としません。S6_CMD_RECEIVE_SIGNALS
(デフォルト= 0):コンテナに送信された信号をコンテナのPID 1またはCMDに送信するかどうかを決定します。デフォルトでは、たとえばdocker stop
実行すると、用語信号がコンテナのPID 1に送信され、コンテナシャットダウンシーケンス全体がトリガーされますが、CMDが存在する場合、殺される最後のプロセスの1つになります。 、他のすべてがダウンしていて、コンテナが終了しようとしている場合にのみ。この変数が1以上の場合、信号はPID 1からCMDに迂回されます。つまり、 docker stop
代わりにCMDにSigtermを送信し、コンテナはCMDが死んだときにのみシャットダウン手順をトリガーします。 Sigterm、Sigquit、Sigint、Sigusr1、Sigusr2、Sigpwr、Sigwinchのみが転用されることに注意してください。他の信号は無視されるか、転用できず、必ずしもPID 1によって処理されます。このオプションを使用すると、インタラクティブなCMDが動作するのを防ぐことができます。 'この変数を設定します。しかし、この場合、CMDを停止するインタラクティブな方法がすでにあるため、それは問題ありません。コンテナで実行されているソフトウェアがsyslogを必要とする場合は、 syslogd-overlay-noarch.tar.xz
tarballを抽出します。ログは/var/log/syslogd
のさまざまなサブディレクトリの下にあります。たとえば、メッセージは/var/log/ /var/log/syslogd/messages/current
/var/log/syslogd/messages/
directoryにあります。 /var/log/syslogd/messages/current