このチュートリアルでは、Alibaba Cloud上でコンテナを扱う際にDocker Composeを使用して実践的な経験を積むことに焦点を当てています。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
#生産性のヒント
私はよく使うDockerコマンド用にいくつかのbash aliasesを定義しています。ここではそのうちの2つを紹介します。
alias nnc='nano docker-compose.yml'
alias psa='docker ps -a'
シェルで psa を入力すると、チュートリアルで docker ps -a をハイライトしてからコピーし、alt-tab でコンソールウィンドウに移動してからペーストするよりも速いです。
docker-compose.yml の編集が速くなりました。
1、Chromeを使用している場合は、オートコピー拡張機能をインストールしてください。ブラウザでハイライトしたテキストを自動的にコピーしてくれます。
2、チュートリアルでdocker-compose.ymlのテキストをハイライト表示します。
3、AltタブでLinuxコンソールへ
4、type nnc ( editorで docker-compose.yml ファイルを開きます )
5、右クリックして貼り付けます(これは使用しているコンソールソフトウェア固有のものです)。
6、保存
拡張子とエイリアスを使用しない場合、このプロセスには上記の6つのステップの代わりに12のステップが必要になります。
シェルで psa を入力するのは、チュートリアルで docker ps -a をハイライトしてからコピーし、alt-tab でコンソールウィンドウに移動してからペーストするよりも速いです。
docker-compose.yml の編集が速くなりました。
1、Chromeを使っている場合は、オートコピー拡張機能をインストールしてください。ブラウザでハイライトしたテキストを自動的にコピーします。
2、チュートリアルでdocker-compose.ymlのテキストをハイライト表示します。
3、AltタブでLinuxコンソールへ
4、type nnc ( エディタが docker-compose.yml ファイルを開く )
5、右クリックして貼り付けます(これは使用しているコンソールソフトウェアに固有のものです)。
6、保存
拡張子とエイリアスを使用しない場合、このプロセスには上記の6つのステップの代わりに12のステップが必要になります。
#Deploy: placement constraints
docker-composeの配置制約は、制約を定義することで、タスクをスケジューリング/実行できるノード/サーバを制限するために使用されます。
まず、ノード/サーバのラベルを定義する必要があります。次に、これらのラベルに基づいて配置制約を定義します。
ノードにラベルを追加する構文
docker node update --label-add label-name=label-value hostnam-of-node
このためにはサーバのホスト名が必要です。シェルでホスト名を入力して、あなたのホスト名を取得します。
以下、自分のホスト名を使ってください。( localhost.localdomain = 私のホスト名)
docker node update --label-add tuts-allowed=yes localhost.localdomain
docker node update --label-add has-ssd=yes localhost.localdomain
ノードを検査してラベルが存在することを確認することができます。
head -n 13 は先頭のみを表示します。 / head 13行の長いinspectの出力。
docker node inspect self | head -n 13
期待される出力 .
[
{
"ID": "wpk3r9ypjd8f0p3koh1dikvie",
"Version": {
"Index": 443
},
"CreatedAt": "2018-11-06T09:29:29.644400514Z",
"UpdatedAt": "2018-11-07T09:55:18.065758325Z",
"Spec": {
"Labels": {
"has-ssd": "yes",
"tuts-allowed": "yes"
},
ここで、docker-compose.yml の一番下に配置規則を追加します。
docker-compose.yml に次のように追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
placement:
constraints:
- node.labels.has-ssd == yes
- node.labels.tuts-allowed == yes
stack deployコマンドは、両方の制約に一致するノードにのみサービススタックを配置します。
両方の制約が私たちのノードと一致しているので、デプロイは成功します。
docker stack deploy -c docker-compose.yml mystack
実行中のコンテナをリストアップしてみましょう。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
42f8a9b43faf alpine:3.8 "sleep 600" 12 seconds ago Up 11 seconds mystack_alpine.1.ezwejfbrmhbk0k5yd9a53ei85
成功しました。mystackにある全てのサービスをリストアップしてみましょう。
docker stack services mystack
ID NAME MODE REPLICAS IMAGE PORTS
ji5dnn9klinx mystack_alpine replicated 1/1 alpine:3.8
成功しました。REPLICAS欄を参照してください。リクエストされた1つのサービスのうち、1つのサービスが実行されています。
それでは、デプロイができないように制約テストを変更してみましょう。
docker-compose.ymlに以下を追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
placement:
constraints:
- node.labels.has-ssd == yeszzz
- node.labels.tuts-allowed == yeszzz
以前に展開したスタックを削除します。
docker stack rm mystack
docker stack deploy -c docker-compose.yml mystack
mystackのサービスを一覧にしてみましょう。
docker stack services mystack
ID NAME MODE REPLICAS IMAGE PORTS
jdg2bgxx5nfa mystack_alpine replicated 0/1 alpine:3.8
デプロイは適切なノードを見つけることに成功しませんでした。REPLICAS カラムを参照してください。要求された 1 つのサービスのうち 0 つのサービスが実行されています。
ノードラベルの使用方法の例。
1、ssds を必要とする特定のアプリがそのようなノードでのみ実行できるように ssds でノードをラベル付けします。
2、アプリケーションがそのようなノードを見つけることができるように、グラフィックカードでノードをラベル付けします。
3、必要に応じて国名、州名、都市名をノードにラベル付けします。
4、バッチとリアルタイムのアプリケーションを分離します。
5、開発ジョブは開発用マシンでのみ実行してください。
6、開発中のアプリケーションを物理的なコンピュータ上でのみ実行してください - CPUやRAMを浪費するコードが同僚に悪影響を与えないようにしてください。
Placementeについての詳しい情報はこちらをご覧ください: https://docs.docker.com/compose/compose-file/#placement
制約についてはこちらをご覧ください: https://docs.docker.com/engine/reference/commandline/service_create/#specify-service-constraints-constraint
#Deploy: replicas
任意の時間に実行するコンテナの数を指定します。
これまではデフォルトのreplicasを1つだけ使用していました。
ここでは3つのreplicasを実行するデモをしてみましょう。
docker-compose.ymlに以下のように追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
replicas: 3
以前に実行していたmystackの削除
docker stack rm mystack
期待される出力 .
Removing service mystack_alpine
Removing network mystack_default
新しいスタックを展開します。
docker stack deploy -c docker-compose.yml mystack
期待される出力 .
Creating network mystack_default
Creating service mystack_alpine
出力は期待できそうにありません - 3つのreplicasについては言及されていません。mystackのサービスをリストアップしてみましょう
docker stack services mystack
期待される出力 .
ID NAME MODE REPLICAS IMAGE PORTS
pv2ebn95au9j mystack_alpine replicated 3/3 alpine:3.8
要求された3つのレプリカが不足しています。成功しました。
実行中のコンテナをリストアップしてみましょう。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
80de65e6e0d3 alpine:3.8 "sleep 600" 9 seconds ago Up 6 seconds mystack_alpine.2.51hlsv3s7ky5zr02fprjaxi59
440548cfcc7d alpine:3.8 "sleep 600" 9 seconds ago Up 6 seconds mystack_alpine.1.za68nt6704xobu2cxbz7x7p3l
19564317375f alpine:3.8 "sleep 600" 9 seconds ago Up 7 seconds mystack_alpine.3.1ut387z38e2hrlmahalp7hfsa
予想通りです。3つのコンテナが稼働しています。
サーバの作業負荷を調査してみました。
top - 09:45:33 up 2:02, 2 users, load average: 0.00, 0.01, 0.05
Tasks: 133 total, 1 running, 132 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.2 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 985.219 total, 472.004 free, 171.848 used, 341.367 buff/cache
MiB Swap: 1499.996 total, 1499.996 free, 0.000 used. 639.379 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
939 root 20 0 950.7m 105.9m 29.2m S 0.7 10.8 1:19.36 dockerd
946 root 20 0 424.8m 29.1m 12.1m S 2.9 0:14.14 docker-containe
5082 root 20 0 7.2m 2.7m 2.0m S 0.3 docker-containe
4950 root 20 0 7.2m 2.6m 2.0m S 0.3 docker-containe
5075 root 20 0 7.2m 2.4m 1.9m S 0.2 docker-containe
3つの小さなコンテナはそれぞれ約2.5MBのRAMを使用しています。
これで、隔離された環境で動作する3つのフルAlpine Linuxディストロが、それぞれ2.5MBのRAMサイズで動作するようになりました。これは素晴らしいことです。
これを3つの独立した仮想マシンと比較してみてください。それぞれの仮想マシンは、存在するだけで50MBのオーバーヘッドを必要とします。さらに、それぞれに数百 MB のディスクスペースが必要になります。
各コンテナは約300msで起動しますが、これはVMでは不可能です。
#Deploy: resources: reservations cpu ( オーバープロビジョニング )
reservations: cpu config settingsを使ってCPU容量を確保しています。
cpuをオーバープロビジョニングして、Dockerが指示に従うかどうかを確認してみましょう。
docker-compose.ymlに以下を追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
replicas: 6
resources:
reservations:
cpus: '0.5'
私のサーバには 2 つのコアがあるので、2 つの CPU が利用可能です。
この設定では、6 * .5 = 3CPUをプロビジョニングしようとしています。
この設定を編集して、あなたの小さなノートパソコンや、あなたの雇い主であるスーパーサーバーで失敗するようにしなければなりません。
既存のスタックを削除してみましょう。
docker stack rm mystack
展開してみましょう。
docker stack deploy -c docker-compose.yml mystack
期待されない出力 .
Creating service mystack_alpine
failed to create service mystack_alpine: Error response from daemon: network mystack_default not found
時々上記のようなことが起こりますが、エラーが出なくなるまでデプロイを再実行してください。
デプロイの結果を調査してください。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a8861c79e3e8 alpine:3.8 "sleep 600" 40 seconds ago Up 37 seconds mystack_alpine.6.pgtvnbpxpy4ony26pmp8ekdv1
3d2a0b8e52e9 alpine:3.8 "sleep 600" 40 seconds ago Up 37 seconds mystack_alpine.5.j52dwbe7qqx0nn5nhanp742n4
5c2674b7fa36 alpine:3.8 "sleep 600" 40 seconds ago Up 37 seconds mystack_alpine.1.bb1ocs3zkz730rp9bpf6s9jux
f984a8d52393 alpine:3.8 "sleep 600" 40 seconds ago Up 38 seconds mystack_alpine.4.mr5ktkei9pn1dzhkggq2e48o9
4つのコンテナがリストアップされています。4 * .5 = 2CPUを使用していることになります。
mystackにある全てのサービスをリストアップする。
docker stack services mystack
ID NAME MODE REPLICAS IMAGE PORTS
7030g8ila28h mystack_alpine replicated 4/6 alpine:3.8
6つのコンテナのうち4つだけがプロビジョニングされました。Dockerはプロビジョニングするcpusを使い果たしました。
重要: これは存在するものだけをreservationすることができます。
#Deploy: resources: reservations: RAM( オーバープロビジョニング )
RAMをオーバープロビジョニングしてみましょう。(この機能はこのチュートリアルの後半で正しく使用します。)
docker-compose.yml に以下を追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
replicas: 6
resources:
memory: 2000M
私のサーバーには1GBのラムがあります。
この設定では、私は6 * 2 = 12 MBをプロビジョニングしようとしています。
前と同じように: この設定を編集して、あなたの小さなノートパソコンやモンスターの雇用主のスーパーサーバーで失敗するようにする必要があります。
既存のスタックを削除してみましょう。
docker stack rm mystack
展開してみましょう。
docker stack deploy -c docker-compose.yml mystack
実行中のstack servicesを一覧表示します。
docker stack services mystack
期待される出力 .
ID NAME MODE REPLICAS IMAGE PORTS
l7yr2m5k6edf mystack_alpine replicated 0/6 alpine:3.8
デプロイされたサービスはゼロ。Dockerは、指定された予約RAMの50%を使用して1つのコンテナをデプロイすることさえしません。これは正しく想定しています - RAMの予約を指定した場合、コンテナが正常に動作するためにはその最小値を必要とします。したがって、予約が不可能な場合、コンテナは起動しません。
ここまでで、リソースの制限が守られることを見てきました。
どのように動作するかを確認するために、妥当な制限を定義してみましょう。
#Deploy: resources: limits: cpu
以下のアルパインサービスは、20M以下のメモリと0.50(50%)以下の利用可能な処理時間(CPU)に制約されています。
docker-compose.ymlに以下を追加します。
nano docker-compose.yml
version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
replicas: 1
resources:
limits:
cpus: '0.5'
memory: 20M
ここから先はreplicasが1つしか必要ないことに注意してください。
docker stack rm mystack
スタックを展開します。
docker stack deploy -c docker-compose.yml mystack
docker ps -a
期待される出力 .
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11b8e8c2838b alpine:3.8 "sleep 600" 3 seconds ago Up 1 second mystack_alpine.1.qsamffjd1vg0137off9xinyzg
コンテナが動いています。これを入力して、CPU速度をベンチマークしてみましょう。
docker exec -it mystack_alpine.1.qsamffjd1vg0137off9xinyzg /bin/sh
コンテナ / # プロンプトに表示されているコマンドを入力します。
/ # time dd if=/dev/urandom bs=1M count=2 | md5sum
2+0 records in
2+0 records out
real 0m 0.57s
user 0m 0.00s
sys 0m 0.28s
064be3476682daf856bb32fa00d29e2e -
/ # exit
ベンチマークの説明:
1、time: 経過時間を測定します。
2、dd if=/dev/urandom bs=1M count=2: 1 MB のランダム性を bs (ブロックサイズ) を 2 回コピーする。
3、md5sum: md5ハッシュを計算する (CPUに負荷を与える)
CPU 制限値 0.5 のベンチタイムがありますが、これを比較できなければ何の意味もありません。
そこで、docker-compose.yml で cpu limit を 0.25 に変更してみましょう。
cpus: '0.25'
その後、シェルで実行します。
docker stack rm mystack
docker stack deploy -c docker-compose.yml mystack
docker ps -a # to get our container name
docker exec -it mystack_alpine.1.cbaakbi027ue0c1rtj0z463qz /bin/sh
ベンマークを再実行します。
/ # time dd if=/dev/urandom bs=1M count=2 | md5sum
2+0 records in
2+0 records out
real 0m 1.27s
user 0m 0.00s6d9b25e860ebef038daa165ae491c965 -
sys 0m 0.30s
/ # time dd if=/dev/urandom bs=1M count=2 | md5sum
2+0 records in
2+0 records out
real 0m 1.33s
ed29ebf0ef70923f9b980c65495767eb -
user 0m 0.00s
sys 0m 0.33s
/ # exit
結果は理にかなっています。 - 約50%の速度低下 - 利用可能なCPUパワーが50%減少しています。
そこで、docker-compose.ymlでCPU制限を1.00に変更してみましょう。
cpus: '1.00'
シェルで実行します。
docker stack rm mystack
docker stack deploy -c docker-compose.yml mystack
docker ps -a
docker exec -it your-container-name /bin/sh
表示されているコマンドを入力します。
/ # time dd if=/dev/urandom bs=1M count=2 | md5sum
2+0 records in
2+0 records out
real 0m 0.25s
user 0m 0.00s
sys 0m 0.24s
facbf070f7328db3321ddffca3c4239e -
/ # time dd if=/dev/urandom bs=1M count=2 | md5sum
2+0 records in
2+0 records out
616ba74d54b8a176f559f41b224bc3a3 -real 0m 0.29s
user 0m 0.00s
sys 0m 0.28s
/ # exit
非常に高速なランタイム:100%のCPU制限は25%のCPUパワーよりも4倍速い
これで、コンテナごとのCPUパワーを制限することが期待通りに動作することを体験していただけたと思います。
本番用のサーバーが 1 台しかない場合、この知識を使って、CPU を消費するバッチプロセスを他の作業と同じサーバーで実行することができます - バッチプロセスの CPU を厳しく制限するだけです。
#Resources: limits: memory
この設定オプションは、コンテナの最大 RAM 使用量を制限します。
docker-compose.yml に次のように追加します。
nano docker-compose.yml
Version: "3.7"
services:
alpine:
image: alpine:3.8
command: sleep 600
deploy:
replicas: 1
resources:
limits:
cpus: '1.00'
memory: 4M
実行します。
docker stack rm mystack
docker stack deploy -c docker-compose.yml mystack
docker ps -a
期待される出力 .
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2e0105ce94fd alpine:3.8 "sleep 600" 3 seconds ago Up 1 second mystack_alpine.1.ykn9fdmeaudp4ezar7ev19111
これで、メモリ制限が4MBのコンテナが稼働していることになります。
典型的な好奇心旺盛なDocker管理者になって、8MBの/dev/shm RAMを使用した場合にどうなるか見てみましょう。
docker exec -it mystack_alpine.1.ykn9fdmeaudp4ezar7ev19111 /bin/sh
表示されているようにコマンドを入力します。
/ # df -h
Filesystem Size Used Available Use% Mounted on
/dev/mapper/docker-253:1-388628-c88293aae6b79e197118527c00d64fee14aec2acfb49e5f1ec95bc6af6bd874b
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.2G 43% /etc/resolv.conf
/dev/mapper/centos00-root
12.6G 5.5G 7.2G 43% /etc/hostname
/dev/mapper/centos00-root
12.6G 5.5G 7.2G 43% /etc/hosts
shm 64.0M 0 64.0M 0% /dev/shm
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
/ # dd if=/dev/zero of=/dev/shm/fill bs=1M count=4
4+0 records in
4+0 records out
/ # df -h
Filesystem Size Used Available Use% Mounted on
/dev/mapper/docker-253:1-388628-c88293aae6b79e197118527c00d64fee14aec2acfb49e5f1ec95bc6af6bd874b
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.2G 43% /etc/resolv.conf
/dev/mapper/centos00-root
12.6G 5.5G 7.2G 43% /etc/hostname
/dev/mapper/centos00-root
12.6G 5.5G 7.2G 43% /etc/hosts
shm 64.0M 4.0M 60.0M 6% /dev/shm
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
/ # dd if=/dev/zero of=/dev/shm/fill bs=1M count=8
Killed
/ # df -h
Filesystem Size Used Available Use% Mounted on
/dev/mapper/docker-253:1-388628-c88293aae6b79e197118527c00d64fee14aec2acfb49e5f1ec95bc6af6bd874b
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.2G 43% /etc/resolv.conf
/dev/mapper/centos00-root
12.6G 5.5G 7.2G 43% /etc/hostname
/dev/mapper/centos00-root
12.6G 5.5G 7.2G 43% /etc/hosts
shm 64.0M 5.4M 58.6M 9% /dev/shm
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
/ # exit
上で起こったことの説明。
最初に df -h を実行して /dev/shm のサイズと使用量を調べます。
shm 64.0M 0 64.0M 0% /dev/shm
そして、/dev/shmに4MBを追加します。
dd if=/dev/zero of=/dev/shm/fill bs=1M count=4
使用方法を再確認してください - 4Mを参照してください。
shm 64.0M 4.0M 60.0M 6% /dev/shm
そして、/dev/shm に 8MB を追加して、以前の内容を上書きします。
dd if=/dev/zero of=/dev/shm/fill bs=1M count=8
Killed
で、このコマンドは強制終了されます。
dev/shm の使用状況を再度確認してください。
shm 64.0M 5.4M 58.6M 9% /dev/shm
コンテナがRAMを使い果たす前に4MBを少し使いました。
結論:Dockerのdocker-composeのメモリ制限が適用されます。
デフォルトではコンテナはRAMの使用量が制限されていません。そのため、このリソース制限を利用して、暴走したコンテナによってRAMが完全に消費されるのを防ぎましょう。
20MB、50MB、100MBのいずれも240GBを消費させるよりは良いでしょう。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ