このチュートリアルでは、Alibaba Cloud上でコンテナを扱う際にDocker Composeを使用して実践的な経験を積むことに焦点を当てています。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
#stop_grace_period(猶予期間の終了)
https://docs.docker.com/compose/compose-file/#stop_grace_period より
デフォルトでは、DockerはSIGKILLを送信する前にコンテナが終了するまで10秒待ちます。
SIGKILLを送信する前に、コンテナがSIGTERM(またはstop_signalで指定した停止信号)を処理しない場合に、コンテナを停止しようとしたときにどのくらい待つかを指定します。
これまで私の docker-compose ファイルにはこの設定 ( stop_grace_period ) がありませんでした。そのため、以下のように -t 0 を指定する必要がありました。
docker-compose up -d -t 0
-t 0 は、docker-compose がコンテナを終了させる前に 0 秒待機しなければならないことを指定します。タイムアウトのデフォルト値は10秒です。つまり、docker-composeを起動するたびに、コンテナが最終的に終了して再び起動されるまで10秒待たなければならないということです。
docker-compose
ファイルのstop_grace_periodでは、タイムアウト=0の値を指定することができます。
を使用して、以下を docker-compose.yml に追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
stop_grace_period: 0s
実行します。
docker-compose up -d
スリープタイムアウトの値を少し変更して、実行
docker-compose up -d
スリープタイムアウトの値を少し変更して、再度実行
docker-compose up -d
毎回ほぼ瞬時に再作成されるのを見てください。
stop_grace_periodをデフォルトの10秒に変更します。
docker-compose up -d
スリープタイムアウトの値を少し変更して実行
docker-compose up -d
スリープタイムアウトの値を少し変更して、再度実行
docker-compose up -d
レクリエーションに毎回10秒かかっている様子を見てみましょう。
docker eventsの出力を見てみると詳細がわかると思います。
stop_grace_period. 0s
2018-11-05T14:46:34.968709389+02:00 container kill .... lots of information ... signal=15
2018-11-05T14:46:34.984262101+02:00 container kill .... lots of information ... signal=9
stop_grace_period. 10s
2018-11-05T14:47:49.486907072+02:00 container kill .... lots of information ... signal=15
2018-11-05T14:47:59.510613956+02:00 container kill .... lots of information ... signal=9
signal=15
SIGTERM は終了信号です。プロセスを終了させますが、クリーンアップルーチンを実行させます。
signal= 9
SIGKILLはキルシグナルです。Kill the process: 直ちに。プロセスはシグナルをキャッチして処理することができず、クリーンアップすることができません。
上で出力されたイベントに基づいて、stop_grace_period. 0sはSIGKILLに行く前にSIGTERMから0.02秒待ちます。
上記のイベント出力に基づいて、stop_grace_period. 10sはSIGKILLになる前にSIGTERMから10秒以上待ちます。
これらのチュートリアルの残りの部分については、すべての docker-compose ファイルに次のように記述されます: stop_grace_period. 0s
注: 本番環境の作業環境に適した stop_grace_period を決定する必要があります。これは、アプリによって異なります。
#sysctls
コンテナに設定するカーネルパラメータの設定にはsysctlsを使用します。
カーネルパラメータとは?
Linux ではカーネルパラメータを使ってリソースの制限を設定することができます。カーネルパラメータはrootを含むすべての人に適用されます。
公式のリファレンス情報は https://www.kernel.org/doc/Documentation/sysctl/kernel.txt で確認できます。
Linux シェルで man sysctl を実行すると、実行時にカーネルパラメータを設定する方法が詳しく書かれています。
コンテナを再び起動してみましょう。
docker-compose up -d -t 0
を使ってコンテナを入力します。
docker exec -it compose-tuts_alpine_1 /bin/sh
表示されたプロンプトで以下の 3 つのコマンドを入力します。これら3つのカーネルパラメータの現在の実際の値が表示されます。
cat /proc/sys/net/core/somaxconn
cat /proc/sys/kernel/msgmax
cat /proc/sys/kernel/shmmax
期待される出力 .
/ # cat /proc/sys/net/core/somaxconn
128
/ # cat /proc/sys/kernel/msgmax
8192
/ # cat /proc/sys/kernel/shmmax
18446744073692774399
/ # exit
この3つの値を変更して、それらの値が適用されているかどうかを確認するためにコンテナを調査します。
docker-compose.yml に以下を追加します。
nano docker-compose.yml
その内容が、
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
sysctls:
net.core.somaxconn: 512
kernel.shmmax: 18102030100020003000
kernel.msgmax: 4000
実行します。
docker-compose up -d -t 0
docker exec -it compose-tuts_alpine_1 /bin/sh
表示されたプロンプトで以下の3つのコマンドを入力します。これら3つのカーネルパラメータの現在の新しい実際の値が表示されます。
cat /proc/sys/net/core/somaxconn
cat /proc/sys/kernel/msgmax
cat /proc/sys/kernel/shmmax
期待される出力 .
/ # cat /proc/sys/net/core/somaxconn
512
/ # cat /proc/sys/kernel/msgmax
4000
/ # cat /proc/sys/kernel/shmmax
18102030100020003000
/ # exit
見ての通り、これら3つのカーネルパラメータは全て変更されています。
Dockerでは、コンテナ単位でカーネルのパラメータを調整できることがわかりました。
https://docs.docker.com/compose/compose-file/#sysctls より
このオプションは、(バージョン3の)Composeファイルを使用してスウォームモードでスタックをデプロイする場合には無視されます。
#namespace付きのsysctls
( 前節からの続きで、重要な見出しを追加しました )
重要:
すべての sysctls がネームスペースになっているわけではありません。
Dockerはホストシステムを変更するコンテナ内の sysctlsの変更に対応していません。
現在サポートされているSYSCTLS
kernel.msgmax、kernel.msgmnb、kernel.msgmni、kernel.sem,
kernel.shmall, kernel.shmmax, kernel.shmmni, >kernel.shm_rmid_forced
fs.mqueue.* で始まる Sysctls
net.* で始まる Sysctls
この重要な文章は https://docs.docker.com/compose/compose-file/#sysctls のドキュメントにあるはずです。
fs.file-maxを変更しようとしたところ、このエラーが出ました。
ERROR: for compose-tuts_alpine_1 Cannot start service alpine: OCI runtime create failed: sysctl "fs.file-max" is not in a separate kernel namespace: unknown
これで理解できました: fs.file-max はネームスペースではありません。DockerはHOSTシステムを変更するコンテナ内のsysctlsの変更をサポートしていません。
fs.file-max の変更 (コンテナ内での) は、HOST サーバの設定を変更することになりますが、これは許可されていません。
ネームスペースは Linux 上のコンテナの基本的な側面です。https://en.wikipedia.org/wiki/Linux_namespaces を参照してください。
ネームスペースは、コンテナが孤立したバブル環境で存在することを可能にします。ネームスペースは、コンテナが完全なLinuxディストロであり、サーバ上で単独で動作していると思わせます。
fs.file-max は Linux の機能の一例ですが、現在のところコンテナ内ではネームスペースを分離することができません。
そのため、ネームスペースを持たないカーネルパラメータは HOST サーバ上で調整しなければなりません - その上で実行されるすべてのコンテナに適切なものになるようにしなければなりません。
#限界
Ulimit はシェルが利用できるリソース (サイズ、CPU 時間、優先度など) とシェルが起動するプロセスを制御します。
これを使うことで、バグのあるアプリケーションが過負荷をかけてサーバをクラッシュさせないようにすることができます。
Docker のコンテキストでは、コンテナ内で実行されるアプリケーションを制限するためにコンテナ内でこれを使うことができます。
シェルプロンプトでman ulimitを使って公式のドキュメントを読んでください。
ulimitがコンテナ内で実行されることを証明してみましょう。最大プロセス数と最大オープンファイル数を無茶苦茶に低く設定してコンテナを起動してみましょう。
docker-compose.ymlに以下のように追加します。
nano docker-compose.yml
# add this content
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 60171
stop_grace_period: 0s
ulimits:
nproc: 2
nofile:
soft: 2
hard: 4
コンテナを起動してみます。
docker-compose up -d -t 0
期待される出力 .
Recreating compose-tuts_alpine_1 ... error
ERROR: for compose-tuts_alpine_1 Cannot start service alpine: OCI runtime create failed: container_linux.go:348: starting container process caused "open /proc/self/fd: too many open files": unknown
予想通り: 開いているファイルが多すぎてエラーになります。コンテナは小さいですが、起動するには4つ以上のファイルを開く必要があります。
nproc ( プロセス数を 1 に変更。両方のnofileの制限を40以上に変更。
再実行します。
docker-compose up -d -t 0
これは完璧に起動します(私のCentOS 7サーバで)。
nproc を制限するにはカーネル 4.3 以上が必要です - 私のサーバのカーネルバージョンは 3.10.0-327.el7.x86_64 です。uname -r を実行してカーネルのバージョンを取得してください。
ulimit を設定してみましょう: fsize - 最大ファイルサイズ (KB)
を使用して、以下を docker-compose.yml に追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 60171
stop_grace_period: 0s
ulimits:
fsize: 10
実行します。
docker-compose up -d -t 0
docker exec -it compose-tuts_alpine_1 /bin/sh
10MBのファイルを作成して、ファイルサイズの制限である10KBを超えてみましょう。
/ # dd if=/dev/zero of=/tmp/output.dat bs=1M count=10
コンテナが存在するだけで、シェルセッションがクラッシュしました。
別の時間に私はエラーメッセージを得ました。
dd if=/dev/zero of=/tmp/output.dat bs=1M count=10
File size limit exceeded (core dumped)
#Configs
Configs は、コンテナ内のアプリケーションに必要な設定ファイルを宣言します。通常 /etc や F/opt の中にあるような設定ファイルが必要です。
docker-compose secrets は秘密の情報を保存するためのものです。
まず、docker-compose.yml の中で参照できるように、2つの小さな設定ファイルを作成する必要があります。
まず最初の設定ファイルを作成します。
nano config_data
'# config data
次に、2つ目のconfigファイルを作成します。
nano my_second_config.config
'# my_second_config.config の内容
ここで、DockerがこのSECOND FILEのみをmy_second_configFという名前のコンフィグとして作成する必要があります。
docker config create my_second_config my_second_config.config
これら2つの異なるConfigは、Configsの2つの異なる使い方をデモします。
docker-compose.yml に以下のように追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
configs:
- my_first_config
- my_second_config
configs:
my_first_config:
file: ./config_data
my_second_config:
external: true
トップレベルの configs 宣言 (下の 5 行目) は、このスタック内のサービスに付与される 2 つの config を定義しています。
サービスレベルの config (7 行目から 10 行目あたり) は、コンテナに 2 つの config へのアクセスを許可します。
両方の設定宣言を使用しなければなりません。
my_second_configはexternal: trueと定義されていることに注意してください。これはDockerのconfigオブジェクトとして存在します。
docker-compose upは'configs'設定をサポートしていません。スウォームへのデプロイにはdocker stack deployを使用する必要があります。
docker swarm init
docker stack deploy -c docker-compose.yml mystack
docker ps -a
期待される出力 .
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab50c7daf979 alpine:3.8 "sleep 600" 14 seconds ago Up 13 seconds mystack_alpine.1.jq3buvzkf2a3hpn7mwb0e43om
自動生成されたコンテナ名を取得するために docker ps を実行しなければなりません。
ランダムに生成されたコンテナ名が手に入ったので、それを exec で入力します: コンテナのランダムな配列は異なります。自分のコンテナ名を使って実行してください。
docker exec -it mystack_alpine.1.jq3buvzkf2a3hpn7mwb0e43om /bin/sh
期待される出力 .
/ # ls
bin lib my_second_config sbin usr
dev media proc srv var
etc mnt root sys
home my_first_config run tmp
/ # cat my_first_config
'# config data
/ # cat my_second_config
'# my_second_config.config contents
/ # exit
これらの設定は / ディレクトリにマウントされていることに注意してください。
Linux 管理者が config を見つけることができると思われるディレクトリにマウントしましょう。
docker-compose.yml に以下を追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
configs:
- source: my_first_config
target: /etc/my_first_config
- source: my_second_config
target: /opt/my_second_config
configs:
my_first_config:
file: ./config_data
my_second_config:
external: true
実行します。
docker stack rm mystack
2つの異なるターゲットパスに注意してください。/etc と /opt です。
docker stack deploy -c docker-compose.yml mystack
期待される出力 .
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
01156eb13576 alpine:3.8 "sleep 600" 4 seconds ago Up 2 seconds mystack_alpine.1.vg2m0ge161anuoz31c2mdgf1k
コンテナに入って、設定が要求されたディレクトリにあるかどうかを調べてみましょう。
docker exec -it mystack_alpine.1.vg2m0ge161anuoz31c2mdgf1k /bin/sh
期待される出力 .
/ # ls
bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr
/ # cat /etc/my_first_config
'# config data
/ # cat /opt/my_second_config
'# my_second_config.config contents
/ # exit
ls は設定が / ディレクトリにないことを確認します。
2つの cat コマンドは、設定が要求されたディレクトリの中にあることを示しています。
#secrets
secretsは上記で説明したように設定と非常によく似た働きをします。大きな違いは、secretsの内容が暗号化されていることです。
を使って docker-compose.yml に以下を追加してください。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
secrets:
- my_secret
secrets:
my_secret:
external: true
既存のスタックをすべて閉じます。
docker-compose down -t 0
docker stack rm mystack
docker container prune -f
Let's create my_secret:
echo a secret password | docker secret create my_secret -
最後のハイフンは、docker が標準入力 (この場合はエコーテキスト) から読み込まなければならないことを意味します。
ここで docker secret ls を実行すると、秘密がリストアップされています。
docker stack deploy -c docker-compose.yml mystack
自動生成されたコンテナ名を取得するためにdocker psを実行する必要があります。
docker ps -a
これでランダムに生成されたコンテナ名を exec で入力することができるようになりました。あなたのコンテナ名を使って実行してください。
docker exec -it mystack_alpine.1.xrgtrrfnwn2qet5pevj5n9 /bin/shwne
示されているようにコマンドを実行します。
- df to show /run/secrets/my_secret exist - in tmpfs - in ram.
- cat /run/secrets/my_secret ... to see the secret.
/ # df -h
Filesystem Size Used Available Use% Mounted on
/dev/mapper/docker-253:1-388628-c16342a3e1f1bfcdcebb82872fa626a5f35a2bea4e535aa9a889069b85c63332
10.0G 37.3M 10.0G 0% /
tmpfs 64.0M 0 64.0M 0% /dev
tmpfs 492.6M 0 492.6M 0% /sys/fs/cgroup
/dev/mapper/centos00-root
12.6G 5.5G 7.1G 43% /etc/resolv.conf
/dev/mapper/centos00-root
12.6G 5.5G 7.1G 43% /etc/hostname
/dev/mapper/centos00-root
12.6G 5.5G 7.1G 43% /etc/hosts
shm 64.0M 0 64.0M 0% /dev/shm
tmpfs 492.6M 4.0K 492.6M 0% /run/secrets/my_secret
tmpfs 492.6M 0 492.6M 0% /proc/acpi
tmpfs 64.0M 0 64.0M 0% /proc/kcore
tmpfs 64.0M 0 64.0M 0% /proc/keys
tmpfs 64.0M 0 64.0M 0% /proc/timer_list
tmpfs 64.0M 0 64.0M 0% /proc/timer_stats
tmpfs 64.0M 0 64.0M 0% /proc/sched_debug
tmpfs 492.6M 0 492.6M 0% /proc/scsi
tmpfs 492.6M 0 492.6M 0% /sys/firmware
/ # cat /run/secrets/my_secret
a secret password
/ # exit
以下のコマンドを実行すると、シークレットそのものが見えなくなります。
docker inspect my_secret
[
{
"ID": "vjvqnag6nu0p87xc0o94p315g",
"Version": {
"Index": 386
},
"CreatedAt": "2018-11-06T12:05:40.984748215Z",
"UpdatedAt": "2018-11-06T12:05:40.984748215Z",
"Spec": {
"Name": "my_secret",
"Labels": {}
}
}
]
サーバー上のすべてのsecretsのリストを見るには、以下を実行します。
docker secret ls
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ