20200722のdockerに関する記事は12件です。

Dockerでubuntuイメージを取得してきてコンテナ起動する

https://hub.docker.com/_/ubuntu を起動する時のコマンドメモ。
ふとlinuxコマンドを動かしたくなった時にさっと使えるようにメモです。

イメージの取得

docker pull ubuntu

コンテナをバックグラウンドで起動

docker run --name <container_name> -it -d <image_name> /bin/bash
# 例
docker run --name ubuntu -it -d ubuntu /bin/bash

シェルに入る

docker exec -it <container_name> /bin/bash
# 例
docker exec -it ubuntu /bin/bash

おまけ

コンテナ名をつけ忘れたり間違えてしまったら

docker rename でコンテナ名を変更できる。

docker rename <current_name> <new_name>

manを使いたい

シェル内からman読もうと思ったらミニマムな構成とのことでそのままだと使えなかった(コンテナってこういうものだよね…)

root@10b70c6ce5aa:/# man mount
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, including manpages, you can run the 'unminimize'
command. You will still need to ensure the 'man-db' package is installed.

unminimize 叩いてみた

root@10b70c6ce5aa:/# unminimize
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
<snip>

2回くらい[y/n]聞かれるので Y 押す

リトライ

root@10b70c6ce5aa:/# man mount
bash: /usr/bin/man: No such file or directory

そもそもいなかった(コンテナってこういうものd)

更新&インストール(いつもの)

root@10b70c6ce5aa:/# apt update
root@10b70c6ce5aa:/# apt install -y man

パッケージ一覧確認

root@10b70c6ce5aa:/# dpkg -l | grep man
<snip>
ii  man-db                  2.9.1-1                 amd64        tools for reading manual pages
<snip>

man-db が増えた

root@10b70c6ce5aa:/# man mount

今度はman見れるようになりました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

flaskアプリをdockerfileを使用しherokuへデプロイ

今回は完成しているフラスクアプリをdockerfileから動かしherokuでデプロイするまでを記述します。
ネットを探してもあまりいい記事が見つからずあまり普段はほとんど見ることのない公式のドキュメントを見て実行することにしました。
heroku公式ドキュメント

Dockerfile

FROM ubuntu:latest

RUN apt-get update
RUN apt-get install python3 python3-pip -y

COPY . /home
WORKDIR /home

RUN pip3 install -r requirements.txt
RUN pip3 install email_validator

RUN ls /home

ENV FLASK_APP app.py
RUN echo $FLASK_APP

RUN flask db init
RUN flask db migrate
RUN flask db upgrade
RUN ls /home

CMD flask run -h 0.0.0.0 -p $PORT

herokuにdockerとしてデプロイする時に重要なのは下の行です。
CMD flask run -h 0.0.0.0 -p $PORT
$PORTについてはheroku側でうまくやってくれるらしいです。

herokuへデプロイ作業

$ mkdir project
$ cd project
$ git clone <自分で作成したdockerfileが置いてあるリポジトリ>
$ heroku login
$ heroku create
$ heroku container:push web
$ heroku container:release web
$ heroku open

<>の中以外はそのまま入力しました。

修正してまたデプロイするとき

$ heroku container:push web
$ heroku container:release web
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Depends_on、Volumes、Init Docker-composeオプション - Docker Composeのための実践演習その3

このチュートリアルでは、Alibaba Cloud上でコンテナを扱う際にDocker Composeを使用して実践的な経験を積むことに焦点を当てています。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

depends_on

depends_onはサービス間の依存関係を宣言します。

depends_on docker-compose upでは、依存関係のある順にサービスを起動します。

依存関係にあるサービスは、メインサービスが起動する前に最初に起動します。

見ての通り、依存関係はランダムな順番で開始されます。また、docker-compose はメインサービスを起動する前に依存関係の実行を待つことはありません。

これを実際に見てみましょう。

docker-compose.yml に以下を追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

command: sleep 600

depends_on:

- service-2

- service-3

- service-4

container_name: main-container

service-2:

image: alpine:3.8

container_name: service-2

command: sleep 600

service-3:

image: alpine:3.8

container_name: service-3

command: sleep 600

service-4:

image: alpine:3.8

container_name: service-4

command: sleep 600

依存関係はきちんと番号順に宣言されていることに注意してください。

このdocker-composeファイルを以下のようにして起動してみましょう。

docker-compose up -d -t 0

期待される出力 .

Creating service-3 ... done

Creating service-4 ... done

Creating service-2 ... done

Recreating compose-tuts_alpine_1 ... done

依存関係がランダムな順番で始まっていることに注意してください。メインサービスは最後に開始されますが、上記の出力には明確には表示されていません。

docker-compose ファイルに小さな編集を加えて (スリープ時間の編集など)、docker-compose をやり直すと、これらのサービスが毎回異なるシーケンスで作成されていることがわかります。試してみてください。

イベントのシーケンスをより明確に見るために、すべてのサービスをシャットダウンしてdocker-compose upをやり直してみましょう。

docker-compose down -t 0

期待される出力 .

Stopping main-container ... done

Stopping service-4  ... done

Stopping service-3  ... done

Stopping service-2  ... done

Removing main-container ... done

Removing service-4  ... done

Removing service-3  ... done

Removing service-2  … done

ネットワークcompose-tuts_defaultの削除
メインコンテナが最初に停止し、次に依存関係が停止することに注意してください。

ここで実行します。

docker-compose up -d -t 0

期待される出力 .

Creating network "compose-tuts_default" with the default driver

Creating service-3 ... done

Creating service-2 ... done

Creating service-4 ... done

Creating main-container ... done

最後に作成されたメインコンテナが明確に表示されます。

メインコンテナが起動する前に依存サービスをREADYにしておく必要がある場合は、 https://docs.docker.com/compose/startup-order/ を勉強する必要があります。

volumes

volumesは、名前付きvolumesのマウントに使用されます。

これを面白くするために、先ほどの例の4つのサービスを再利用します。

4 つのサービスはすべて demo-data-volume という名前付きvolumesを使用します。これはまだ存在しません。

docker-compose.ymlに以下を追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

command: sleep 600

depends_on:

- service-2

- service-3

- service-4

container_name: main-container

service-2:

image: alpine:3.8

container_name: service-2

command: sleep 600

volumes:

- demo-data-volume:/root/dir1/dir2

service-3:

image: alpine:3.8

container_name: service-3

command: sleep 600

volumes:

- demo-data-volume:/root/dira/dirb

service-4:

image: alpine:3.8

container_name: service-4

command: sleep 600

volumes:

- demo-data-volume:/root/1/2/3/4

volumes:

demo-data-volume:

一番下の右側:これがトップレベルのボリュームキーです(Dockerのドキュメントでは名前が付けられています)。

トップレベルのキーはdocker-composeファイルの左端から始まります。

トップレベルのキーはdemo-data-volumeを定義しています。

実行時には

docker-compose up -d -t 0

demo-data-volumeが作成されます(存在しない場合)。

期待される出力は以下の通りです。

Creating network "compose-tuts_default" with the default driver

Creating volume "compose-tuts_demo-data-volume" with default driver

Creating service-2 ... done

Creating service-4 ... done

Creating service-3 ... done

Creating main-container ... done

2行目の注意点 compose-tuts_demo-data-volume "をデフォルトドライバで作成します。

実行します。

docker volume ls

期待される出力 .

DRIVER  VOLUME NAME

local  compose-tuts_demo-data-volume

これが名前付きvolumesです。この名前は、カレントディレクトリと docker-compose ファイルで指定したボリューム名を連結したものです。

docker-compose ファイルでは、この名前付きボリュームを 3 つのサービスの異なるマウントポイントで使用するように定義しました。

service-2:

volumes:

- demo-data-volume:/root/dir1/dir2

service-3:

volumes:

- demo-data-volume:/root/dira/dirb

service-4:

volumes:

- demo-data-volume:/root/1/2/3/4

ここでは、これら3つのサービスがすべて同じ名前のvolumesにアクセスできることを確認します。

service-2 を入力して、名前付きvolumesで作業してみましょう。

docker exec -it service-2 /bin/sh

ls はパスが存在することを示し、echo は myoutfile を作成します。そして終了します。

/ # ls /root/dir1

dir2

/ # echo from service 2 > /root/dir1/dir2/myoutfile

/ # exit

service-3に入って、名前のついたvolumesを調べてみましょう。

docker exec -it service-3 /bin/sh

ls はファイルが存在することを確認します。

/ # ls /root/dira/dirb

myoutfile

/ # cat /root/dira/dirb/myoutfile

from service 2

/ # exit

service-3では、volumesは/root/dira/dirbにマウントされていることに注意してください。

service-3:

volumes:

- demo-data-volume:/root/dira/dirb

サービス4では、volumesは/root/1/2/3/4にマウントされていることに注意してください。

service-4:

volumes:

- demo-data-volume:/root/1/2/3/4

ファイルがそこで利用可能であることを確認するために、service-4を入力します。

docker exec -it service-4 /bin/sh

期待される出力 .

/ # cat /root/1/2/3/4/myoutfile

from service 2

/ # exit

私たちの名前のついたボリュームは、この3つのコンテナの中で読み書きすることができます。これらのコンテナを停止しても存在し続けます。

他のコンテナ、サービス、スワームはこの名前付きボリュームの使用を許可されています。この名前付きボリュームは、これら3つのサービスとは特にリンクしていません。

この数分間で、あなたはおそらくDockerボリュームの機能の5%未満を探索しました。

https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins には25以上のvolumesプラグインがリストアップされています。

公式ドキュメントは https://docs.docker.com/storage/volumes/https://docs.docker.com/storage/ で読むことができます。

少なくともこれで、名前付きvolumesを実際に使ってみて、その仕組みをある程度理解したことになるでしょう。

幸いなことに、名前付きvolumesは最も理解しやすく、最も柔軟性があり、最も頻繁に使用されています。

restart

restartはdocker-compose upを使ってサービスを起動する際に適用されます。

わかりやすい4つのオプションがあります。

1、restart:"no" ... デフォルト値
2、restart: always
3、restart: on-failure
4、restart:unless-stopped
それらを試してみましょう。

**restartのためのデモ:"no" ... the default value
以下を docker-compose.yml に追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

command: sleep 1

サービスを起動します。

docker-compose up -d -t 0

その状態を確認します。

docker ps -a

sleep 1 は、コンテナをわずか 1 秒後に終了させます。

docker ps -a を何度も実行しても、終了したコンテナは 1 つしか表示されません。予想通り: restart = no はコンテナを再起動しません。

restart のデモ: unless-stop
を使用して、以下を docker-compose.yml に追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

command: sleep 1

restart: unless-stopped

前のコンテナをプルーンして、クリーンなdocker ps -aで作業を行います。

docker container prune -f;docker ps -a

新しいコンテナを起動します。

docker-compose up -d -t 0

その状態を確認します。

docker ps -a

sleep 1 は、コンテナをわずか 1 秒後に終了させます。

このコマンドを繰り返し実行すると、コンテナが継続的に再起動していることがわかります。

docker container stop your-container-id を実行してもコンテナは停止しません。

docker-compose down は数秒以内にコンテナを削除します。

docker-compose up を使ってコンテナを起動した場合は、docker-compose down を使ってコンテナを削除します。

restart: unless-stopped は期待通りに動作します。

restartのデモ: always
を使用して、以下を docker-compose.yml に追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

command: sleep 1

restart: always

新しいコンテナを起動します。

docker-compose up -d -t 0

その状態を確認します。

docker ps -a

sleep 1 は、コンテナをわずか 1 秒後に終了させます。

このコマンドを繰り返し実行すると、コンテナは継続的に再起動します。

docker container stop your-container-id does not stop it.

docker-compose down removes the container within seconds.

docker-compose up を使ってコンテナを起動した場合は、docker-compose down を使ってコンテナをダウンさせます。

restart:alwaysは終了コードがゼロ ( 成功 ) で終了したコンテナを常に再起動します。

Commandを置き換えると

command: sleep 1; exit 1

restart: always は 0 以外の ( 失敗した ) 終了コードで終了するコンテナを再起動することをテストできます。

restart: on-failure のデモ
新しいソフトウェアを学ぶには、ドキュメントを読んで、それを使うことが必要です。

経験値ゼロを意味します。

実験は経験を意味します。

ですから、上記で経験したことに基づいて、再起動のためのテストを設計して実行してください:on-failure

失敗した場合のコンテナの再起動をテストしなければなりません。

また、正常に終了した場合に再起動するかどうかもテストしなければなりません ( exit return code 0 )。

上記のテキストに基づいて、これは最大で5分かかるはずです。

init: true の未設定

https://docs.docker.com/compose/compose-file/#init より

コンテナ内で init を実行して、シグナルを転送したり、プロセスを再生したりします。デフォルトの init を使用するには、init を true に設定します。

コンテナ内のプロセスをクリーンにシャットダウンさせたい場合は、このオプションをtrueに設定することが重要です。

docker container stopを実行した場合、コンテナ内のプロセスはコンテナに転送された正しいシグナルを受信しなければなりません。そうすれば、アプリケーションのシャットダウンサブルーチンは正しくシグナルを受けてクリーンにシャットダウンされます。

コンテナ内で複数のプログラムやスレッドを実行している場合、それらは何らかの全体的な管理者プロセスによって正しく管理されたSTOPシグナルを受信しなければなりません。INIT はそのプロセスです。

以下の説明を実際の例で見てみましょう。

Init は最初に SIGTERM (シグナル 15) を送信し、プロセスがそのシグナルをキャッチしてクリーンシャットダウンルーチンを実行できるようにします。SIGTERM は - シャットダウンしなければならないが、最初にクリーンシャットダウンルーチンを実行することを意味します。

stop_grace_period = 10 seconds default.

stop_grace_period は、SIGKILL (シグナル9) を送信する前に、コンテナがクリーンに終了するのを10秒間待ちます。SIGKILL は直ちにプロセスを終了させます - ファイルが適切に閉じられていない - シャットダウンルーチンは実行されていません。SIGKILL は、ある瞬間にはプロセスが動いていることを意味し、次の瞬間には頭が吹っ飛びます。

init: true を指定した場合のみ、この重要なシグナルがコンテナ内に適切に伝わります。

まとめ : データの破損を防ぎたい場合は init: true を指定してください。

重要: このオプションはバージョン3.7のファイルフォーマットで追加されました。docker-compose.yml の最初の行は version. “3.7”

まず、init設定をしないとSTOPの扱いが悪くなることを確認します。

次に、init: trueを指定して違いを観察することで正しく処理します。

docker-compose.ymlに以下のように追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

新しいコンテナを起動します。

docker-compose up -d -t 0

コンテナの状態を確認し、コンテナIDを取得します。

docker ps -a

docker exec -it your-container-id /bin/sh

それを入力してpsを実行します。

/ # ps

PID  USER  TIME  COMMAND

1 root  0:00 sleep 600

11 root  0:00 /bin/sh

16 root  0:00 ps

/ # exit

PIDプロセス1がinitされていないことに注意してください。

新しいシェルコンソールを開き、docker eventsを実行します。

元のシェルに戻って

docker container stop your-container-id

と表示されると、停止するのに10秒かかることがわかります。

重要: docker イベントのコンソール出力を見てください。

期待される出力 .

2018-11-12T09:51:46.112995194+02:00 container kill b676e3bf51f9f1f99edc531ffa04b0ab164834cb218fe9b78abb65b396782d6a (com.docker.compose.config-hash=c19f3ca3bb22826fee98596d3cb40c4f403f8a51cede518945f5ef37bb989589, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, image=alpine:3.8, name=compose-tuts_alpine_1, signal=15)

2018-11-12T09:51:56.134707392+02:00 container kill b676e3bf51f9f1f99edc531ffa04b0ab164834cb218fe9b78abb65b396782d6a (com.docker.compose.config-hash=c19f3ca3bb22826fee98596d3cb40c4f403f8a51cede518945f5ef37bb989589, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, image=alpine:3.8, name=compose-tuts_alpine_1, signal=9)

2018-11-12T09:51:56.307015745+02:00 container die b676e3bf51f9f1f99edc531ffa04b0ab164834cb218fe9b78abb65b396782d6a (com.docker.compose.config-hash=c19f3ca3bb22826fee98596d3cb40c4f403f8a51cede518945f5ef37bb989589, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, exitCode=137, image=alpine:3.8, name=compose-tuts_alpine_1)

2018-11-12T09:51:56.387969293+02:00 network disconnect 9802e2506ea80e7597f0b018450f86fa0c7dcc045a920702cc0e463aacfda84f (container=b676e3bf51f9f1f99edc531ffa04b0ab164834cb218fe9b78abb65b396782d6a, name=compose-tuts_default, type=bridge)

2018-11-12T09:51:56.454351535+02:00 container stop b676e3bf51f9f1f99edc531ffa04b0ab164834cb218fe9b78abb65b396782d6a (com.docker.compose.config-hash=c19f3ca3bb22826fee98596d3cb40c4f403f8a51cede518945f5ef37bb989589, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, image=alpine:3.8, name=compose-tuts_alpine_1)

最初のイベントはコンテナのSIGTERM - その行の最後にsignal15のテキストを右に送信します。

Dockerはコンテナがまだ適切にシャットダウンされていないと判断します。コンテナはsignal15を無視します。

2行目。KILLシグナルイベントは10秒後に発生します - その行の最後にsignal 9のテキストが表示されます。

Dockerはsignal 9 = KILLでコンテナーを強制終了します。

まとめ: initもなく、秩序あるシャットダウンもできず、killを使わなければなりませんでした。

init: true

では、initがどのように停止を適切に処理するかを観察してみましょう。

次のようにして、docker-compose.ymlに以下を追加します。

nano docker-compose.yml
version: "3.7"

services:

alpine:

image: alpine:3.8

command: sleep 600

init: true

init: trueで新しいコンテナを起動します。

docker-compose up -d -t 0

状態を確認してコンテナIDを取得します。

docker ps -a

docker exec -it your-container-id /bin/sh

それを入力してpsを実行します。

/ # ps

PID  USER  TIME  COMMAND

1 root  0:00 /dev/init -- sleep 600

6 root  0:00 sleep 600

7 root  0:00 /bin/sh

12 root  0:00 ps

/ # exit

PID 1 は /dev/init を実行していることに注意してください。initはPID 1を実行しています:コンテナ内のすべてのプロセスへのシグナル送信を管理するための唯一の完璧な場所です。

docker eventsコンソールでCTRL-cを押して、イベントのリストが中断されるようにします。

このコンソールで再び docker events を実行します - 今度は INIT で管理されているシャットダウンイベントを観察します。

元のシェルに戻り、docker ps -a でコンテナ ID を取得します。

今実行した場合

docker container stop your-container-id

と表示されると、非常に早く停止することがわかります。

重要: docker イベントのコンソール出力を見てください。

期待される出力 .

2018-11-12T09:50:14.892684432+02:00 container kill 7973ccec4849cf8759821d613e1b4870c68d76f396fefcfb1cd1bf1f7a3bd509 (com.docker.compose.config-hash=8d5184879de73d9f624319983822eafca40959cbe9f91929ff4648ace18acc6a, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, image=alpine:3.8, name=compose-tuts_alpine_1, signal=15)

2018-11-12T09:50:15.019039627+02:00 container die 7973ccec4849cf8759821d613e1b4870c68d76f396fefcfb1cd1bf1f7a3bd509 (com.docker.compose.config-hash=8d5184879de73d9f624319983822eafca40959cbe9f91929ff4648ace18acc6a, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, exitCode=143, image=alpine:3.8, name=compose-tuts_alpine_1)

2018-11-12T09:50:15.104203647+02:00 network disconnect 9802e2506ea80e7597f0b018450f86fa0c7dcc045a920702cc0e463aacfda84f (container=7973ccec4849cf8759821d613e1b4870c68d76f396fefcfb1cd1bf1f7a3bd509, name=compose-tuts_default, type=bridge)

2018-11-12T09:50:15.149018229+02:00 container stop 7973ccec4849cf8759821d613e1b4870c68d76f396fefcfb1cd1bf1f7a3bd509 (com.docker.compose.config-hash=8d5184879de73d9f624319983822eafca40959cbe9f91929ff4648ace18acc6a, com.docker.compose.container-number=1, com.docker.compose.oneoff=False, com.docker.compose.project=compose-tuts, com.docker.compose.service=alpine, com.docker.compose.version=1.22.0, image=alpine:3.8, name=compose-tuts_alpine_1)

最初のイベントはコンテナのSIGTERM - その行の最後にsignal15のテキストを送信します。

Dockerはコンテナが適切にシャットダウンされていると判断します。コンテナはsignal15を適切に処理する。( コンテナの処理はsignal15をキャッチし、クリーンシャットダウンルーチンを呼び出します。)

コンテナのダイイベントは100ミリ秒後に発生します。

NO signal 9 = KILLが送信されました。

まとめ: init、高速な秩序あるシャットダウン、KILLは使用されません。

要するに、init: trueを使用することを強くお勧めします。これは簡単で高速で、破損したデータの手間を省くことができます。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コンテナサービスを使ったDockerコンテナクラスタの作成方法

このチュートリアルでは、Alibaba Cloudコンテナサービスを使ってDockerコンテナクラスタを作成する方法を紹介します。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

アリババクラウドのコンテナサービスとは?

Alibaba Cloud's Container Serviceは、スケーラブルで高性能なコンテナ管理サービスで、Docker SwarmまたはKubernetesのいずれかを使用してコンテナ化されたアプリケーションのライフサイクルをオーケストレーションして管理することができます。

Alibaba Cloudのコンテナサービスは、継続的インテグレーションを含む複数のアプリケーションリリース方法を提供し、マイクロサービスアーキテクチャもサポートしています。Alibaba Cloudの仮想化、ストレージ、ネットワーク、セキュリティサービスと統合されたコンテナクラスタのUI設定を簡素化することで、Alibaba Cloudのコンテナサービスは、コンテナ化されたアプリケーション環境の実行、管理、監視に最適なクラウド環境となっています。

Docker Swarmとは?

Dockerはオープンソースの仮想化管理ツールで、コンテナ内でアプリケーションやシステムを開発、デプロイ、管理、監視することができます。このプロセスはコンテナ化と呼ばれています。Docker Swarmは、複数のスケーラブルなDockerコンテナ上で動作するシステムや環境のためのクラスタリング、スケジューリング、オーケストレーションツールです。

Dockerコンテナは、コード、ランタイム、ライブラリ、環境変数、設定ファイルなど、アプリケーション全体の実行に必要なすべてを含む実行可能パッケージであるDockerイメージを実行することで起動します。コンテナはDockerイメージのランタイムインスタンスです。

同じインスタンス上で複数のコンテナを同時に実行したり、インスタンスのクラスタスウォームを実行したりすることができ、コンテナはオペレーティングシステムのハイパーバイザーの代わりにDockerによって管理されます。これにより、1つ以上のクラスタノードに問題が発生した場合の冗長性とフェイルオーバーを提供します。

Dockerは軽量で効率的で、複数のアプリケーションで構築された最も複雑なシステムを管理することができます。ローカルでDockerコンテナを構築し、クラウドにデプロイして、必要な場所でスケールアップ、スケールダウンして実行することができます。

Dockerは、単一のECSインスタンス上で簡単にセットアップ、インストール、実行できます。業界レベルのアプリケーションやシステムを実行する大規模なコンテナ化環境には、信頼性と拡張性に優れたオーケストレーションと監視システムが必要です。Alibaba Cloudのコンテナサービスは、システム管理者やDevOpsチームに、大規模なコンテナ化環境を管理するために必要なクラスタ化アーキテクチャを提供します。

クラスタを作成する必要がある理由

Alibaba Cloudのコンテナサービスで実行中のDockerコンテナのスイートをインストールする前に、コンテナ化されたシステムを実装するためのAlibaba Cloud Container Service Docker Swarmクラスタを準備して利用できるようにしておく必要があります。

このチュートリアルでは、そのようなクラスタを構築するための予備的なステップを説明します。次のチュートリアルでは、Alibaba Cloudのコンテナサービスを使ってDocker SwarmクラスタにDockerイメージを実装する方法を紹介します。

前提条件

Alibaba Cloudアカウントが必要です。アカウントをお持ちでない場合は、無料トライアルのページにアクセスして、Alibaba Cloud New User Free Trialで300ドル相当のAlibaba Cloud製品にアクセスして遊んでみましょう。

それでは、始めましょう。

クラスタの作成

まず、商品ページに向かい、コンテナサービスをクリックします。

image.png

Container Serviceコンソールページに到着します。

Create Clusterをクリックする前に、Container Service Swarmオプションが選択されていることを確認してください。

image.png

クラスタにユニークな名前をつけ、RegionとZoneを選択してください。

image.png

クラスタのVPCの詳細とIPの初期CIDRブロック範囲を確認します。

image.png

既存のECSインスタンスをクラスタに追加することも、新しいインスタンスを作成することもできます。このチュートリアルでは、クラスタ用に4つの小さなインスタンスを作成してみましょう。

必要に応じてデータストレージを追加してください - しかし、各ECSインスタンスには最低限のストレージが付属しています。

image.png

OSはUbuntuかCentosのどちらかを選択できます。

安全にアクセスするためのキーペアを設定したり、必要に応じてインスタンスにアクセスするためのルートパスワードを設定したりすることができます。

image.png

オプションのチェックを外してパブリックIPアドレス(EIP)を設定したままにしておき、インスタンスにもクラウド監視プラグインをインストールします。

クラスタにはServer Load Balancerが自動的に作成されるように設定されています。

image.png

必要に応じて、クラスタ上で事前に設定した Relation Database Service (RDS) インスタンスを選択することができ、クラスタ作成プロセスでは、Virtual Private Cloud (VPC) 上の関連するプロトコルタイプのセキュリティグループが設定されます。

image.png

設定の詳細に問題がなければ、ページの上部にある「作成」をクリックします。

image.png

作成をクリックすると、クラスタ構成の詳細をまとめたページが表示され、確認を求められます。

クラスタ構成が必要に応じて適切であることを確認したら、[OK]をクリックします。

image.png

リクエストが送信されました。クラスタの作成中にレポートログが表示されます。

image.png

必要なサービスがまだ起動していないという警告に気づいた場合は、先に進みましょう。

image.png

クラスタが作成されると、画面上に確認画面が表示されます。

クラスタ一覧に戻るをクリックします。

image.png

クラスタリストには、利用可能なクラスタと実行中のクラスタが表示されます。

image.png

ここで、Overviewをクリックすると、クラスタのグラフィカルな表示が表示されます。

image.png

Nodes をクリックすると、クラスタを構成するパブリックおよびプライベートIPアドレス、ステータス、その他の設定情報を含む ECS インスタンスのリストが表示されます。

image.png

この例のアプリケーション、サービス、コンテナのセクションには、デフォルトのビルドシステムのアプリケーションとサービス、インスタンスごとに自動的に含まれる7つのコンテナの情報がリストアップされています。

これで、先ほど作成したAlibaba Cloud Container Serviceクラスタ上にDocker Swarmコンテナ化システムをセットアップする準備が整いました。

まとめ

最初に、Alibaba Cloud Container Serviceのアプリケーション環境を動かすためのクラスタを構築するとお伝えしましたが、今回のチュートリアルではDocker Swarmクラスタになります。今後のチュートリアルでは、コンテナサービスのKubernetesオプション用のクラスタも構築する予定です。

続いて、Alibaba Cloudのコンテナサービス製品について簡単に説明し、その高性能、スケーラビリティ、使いやすいコンソールが、コンテナ化されたアプリケーション環境をAlibaba Cloudの膨大な製品やサービスと統合するのに最適な方法であることを説明しました。

チュートリアルの最初の部分では、Docker Swarmクラスタを構築して、実行中のアプリケーションを構成するDockerコンテナを選択してDocker Swarmアプリケーションを構築することを説明しました。

最後に、Alibaba Cloud Container ServiceのDocker Swarmクラスタを構築するプロセスをステップバイステップで説明し、設定オプションを説明しながら進めていきます。

次のチュートリアルでは、Alibaba Cloudのコンテナサービスを使ってDocker Swarmクラスタ上に実行中のアプリケーション環境を構築する方法を紹介します。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerコンテナのクリーンアップの実務経験

このチュートリアルでは、Alibaba Cloud上のDockerコンテナのクリーンアップを実践的に体験できます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

準備

このチュートリアルに従うには、Dockerが既にインストールされているAlibaba Cloud Elastic Compute Service (ECS)サーバーが必要です。方法がわからない場合は、このチュートリアルを参考にしてください。

コンテナのクリーンアップについて学ぶために、クリーンアップするコンテナがいくつか必要です。

まず、https://hub.docker.com/ からいくつかのイメージが必要です。

このチュートリアルでは、画像の中に何が入っているかは全く問題ではありません。このチュートリアルを完全に理解するためには、Nginx、Redis、Alpineの経験は必要ありません。

Redisはオープンソースのインメモリデータ構造ストアで、データベースやデータキャッシュとして使用されています。ほとんどのプログラミング言語は、メモリ内のデータにほぼ瞬時にアクセスすることで、プログラムを高速化するために使用することができます。

NGINXは無料でオープンソースの高性能HTTPサーバーです。

Alpine Linuxは5MBのLinuxディストリビューションで、dockerユーザーに非常に人気があります。

Alpine Linuxは、dockerアプリケーションのベースイメージとして使用されています。これは、アプリを実行するための小さなLinux環境を提供します。

シェルプロンプトで次のように入力して、これらの4つのイメージをコンピュータにダウンロードしてください。

docker pull hello-world:latest
docker pull nginx:mainline-alpine
docker pull redis:alpine
docker pull alpine:3.8

docker pulコマンドはレジストリからDockerイメージをダウンロードします。docker レジストリには Docker イメージのコレクションが含まれています。

デフォルトでは、docker pull コマンドは Docker Hub: https://hub.docker.com/ から docker イメージをプル/ダウンロードします。

Dockerイメージは、実行中のコンテナを作成するために使用されます。Docker イメージには、特定のアプリケーションを実行するために必要なすべてのソフトウェアが含まれています。例えば、ダウンロードしたnginx:mainline-alpineイメージには、コンテナ内でNginxを実行するために必要なすべてのソフトウェアが含まれています。

docker pull nginx:mainline-alpineでは、nginx:mainline-alpineはプル/ダウンロードしたいイメージの名前です。画像名はnginxです。

mainline-alpineはタグです。タグは同じイメージの異なるバージョンを区別するために使われます。例えば、Docker Hubのリポジトリにはnginx:centos、nginx:ubuntu、nginx:debian8、nginx:debian9のイメージがあります。どのイメージをダウンロードするかを正確に指定するためにタグを使用しています。

docker pull alpine:3.8の場合、3.8タグはバージョン番号を表しています。

実行します。

docker ps -a

期待される出力。

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

新鮮なdockerインストールサーバーでこれを実行している場合は、実行中のコンテナがありません。

混乱させて、いくつかのコンテナを作成して片付けてみましょう。以下のコマンドを入力します。

docker run --name nginx -d  nginx:mainline-alpine
docker run --name redis -d  redis:alpine
docker run -d hello-world
docker run -d hello-world
docker run -d hello-world

docker runは、以前にダウンロードした静的イメージを実行コンテナに変えてくれます。

コンテナとは、dockerイメージのランタイム版のことです。コンテナには、実行中のプロセスを含む完全な実行環境だけでなく、Dockerイメージのすべてのソフトウェアが含まれています。

このチュートリアルではnginxやredisの機能は必要ありません。必要なのは、多様なコンテナの興味深いリストだけです。そうすれば、コンテナを選択的に停止したり削除したりする方法をよりよく学ぶことができます。

nginx と redis を停止してみましょう。hello-world コンテナはメッセージを表示して終了するだけです。すでに停止しているので、停止させる必要はありません。

docker stop nginx
docker stop redis

このコマンドを入力して、すべてのコンテナを一覧表示します。

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED              STATUS                          PORTS               NAMES

97f95b11260e        hello-world             "/hello"                 57 seconds ago       Exited (0) 44 seconds ago                           determined_payne
91f69bd08bf8        hello-world             "/hello"                 About a minute ago   Exited (0) About a minute ago                       xenodochial_wiles
6f7b53de6ad7        hello-world             "/hello"                 About a minute ago   Exited (0) About a minute ago                       pedantic_bartik
62919b9e6d84        redis:alpine            "docker-entrypoint.s?   About a minute ago   Exited (0) 3 seconds ago                            redis
49ca281f8a0c        nginx:mainline-alpine   "nginx -g 'daemon of?   2 minutes ago        Exited (0) 14 seconds ago                           nginx
The CONTAINER IDs you get when you run these commands on your computer will be different.

現在、5つのコンテナが停止しています。

使用できません。

docker container prune

このコマンドは停止している全てのコンテナをプルーニング/削除します。ここでは、まだ nginx と redis のログを見たいと仮定します。そのため、hello-world コンテナだけを慎重にプルーニングしなければなりません。

hello-world コンテナだけのリストを作成してみましょう。実行します。

docker ps -a | grep "hello-world"

grep は、hello-world というテキストを含む出力行のみを選択します。

grep はほとんどの Linux ディストリビューションに搭載されている Linux シェルユーティリティです。40年前に書かれました。

grep is used to search plain-text input for lines that match its search expression.

The __ docker ps -a __ lists all containers, the pipe symbol | sends this list to grep.   __  grep "hello-world" __ searches for the text __ hello-word __. grep only outputs the list of containers __ containing hello-word. __

Grep stands for: g/re/p (__g__lobally search a __re__gular expression and __p__rint)

In __ docker ps -a | grep "hello-world" __ grep searched the list of containers output by docker ps, and prints only the lines containing hello-world.

grep searches the input files for lines containing a match to a given pattern list. When it finds a match in a line, it copies the line to standard output (by default), or whatever other sort of output you have requested with options.

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED              STATUS                          PORTS               NAMES

97f95b11260e        hello-world             "/hello"                 About a minute ago   Exited (0) About a minute ago                       determined_payne
91f69bd08bf8        hello-world             "/hello"                 2 minutes ago        Exited (0) About a minute ago                       xenodochial_wiles
6f7b53de6ad7        hello-world             "/hello"                 2 minutes ago        Exited (0) 2 minutes ago                            pedantic_bartik

完璧です。プルーニングしたいコンテナのリストが必要です。

代わりに実行することもできます。

docker ps -a | egrep --invert-match "redis|nginx"

-invert-matchはマッチングを反転させ、マッチングしていない行のみを選択します。-v は --invert-match のショートカットです。

"redis|nginx "は、redisまたはnginxを含むテキストのみを選択する正規表現です。ここで、パイプ記号の|は、「または」を意味します。

ここで、egrepは、redisとnginxを含むテキストを除いた出力行のみを選択します。

ここではegrepを使用しています: このgrepは拡張正規表現をサポートしています。この場合、"redis|nginx "は拡張正規表現をサポートしています。

docker container __ rm __ = docker container __ remove __ / delete / prune

docker container rmのフォーマットは以下の通りです。

docker container rm [OPTIONS] CONTAINER [CONTAINER...]

docker コンテナ rm に渡すコンテナ ID のリストが必要です。

コンテナIDは出力の最初のフィールド番号です。 awk '{print $1}' は、渡された最初のフィールドだけを出力します。

AWKはテキスト処理のために設計されたプログラミング言語です。テキストデータを抽出したりフィルタリングしたりするのに使われます。ほとんどのLinuxディストリビューションにインストールされています。

AWKは1970年に作成されました。AWKの名前は作者のAlfred Aho, Peter Weinberger, Brian Kernighanの名字に由来しています。

awkとgrepはどちらもテキストをフィルタリングします。grepは入力された列を選択的に印刷することができません。これは awk だけが持っている機能です。そのため、grepとawkを使う必要があります。

awk '{print $1}' は、渡された最初のフィールドだけを表示します。 awk のデフォルトでは、フィールドは空白文字で区切られていると仮定しています。awk '{print $1}' __を使用すると、ここではコンテナのIDを表示しますが、これはdocker ps -aの出力の最初のフィールド/列です。

実行します。

docker ps -a | grep "hello-world" | awk '{print $1}'

期待される出力


97f95b11260e
91f69bd08bf8
6f7b53de6ad7

3つのhello-worldコンテナをすべて削除してみましょう。以下のコマンドのいずれかを選択して実行します。

docker ps -a | grep "hello-world" | awk '{print $1}' | __ xargs docker container rm __

或いは

docker ps -a | egrep -v "redis|nginx"  | awk '{print $1}' | __ xargs docker container rm __

xargs docker container rmはコンテナIDを一つずつ受信して削除します。

期待される出力


97f95b11260e
91f69bd08bf8
6f7b53de6ad7

完璧です。 docker container rmには削除したコンテナIDが表示されています。

実行します。

docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                     PORTS               NAMES

62919b9e6d84        redis:alpine            "docker-entrypoint.s?   4 minutes ago       Exited (0) 2 minutes ago                       redis
49ca281f8a0c        nginx:mainline-alpine   "nginx -g 'daemon of?   4 minutes ago       Exited (0) 2 minutes ago                       nginx

redis と nginx はまだ存在しています。

redis と nginx のログを調べて、それらのコンテナも削除できるようにしておきましょう。
dockerのログはコンテナのログを表示します。

docker logs redis

1:C 03 Oct 06:40:25.554 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 03 Oct 06:40:25.559 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 03 Oct 06:40:25.559 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 03 Oct 06:40:25.613 * Running mode=standalone, port=6379.
1:M 03 Oct 06:40:25.614 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 03 Oct 06:40:25.614 # Server initialized
1:M 03 Oct 06:40:25.614 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:M 03 Oct 06:40:25.615 * Ready to accept connections
1:signal-handler (1538548914) Received SIGTERM scheduling shutdown...
1:M 03 Oct 06:41:54.159 # User requested shutdown...
1:M 03 Oct 06:41:54.195 * Saving the final RDB snapshot before exiting.
1:M 03 Oct 06:41:54.233 * DB saved on disk
1:M 03 Oct 06:41:54.233 # Redis is now ready to exit, bye bye...

実行します。

docker logs nginx

何も表示されません。nginxコンテナも何も使っていませんでした。

ログの調査完了しました。これで全てのコンテナを削除することができます。

実行します。

docker container prune -f
Deleted Containers:
62919b9e6d844d6720301dd8be7d0dfb58defb593fe8e9fa1ea0984b7aa92baa
49ca281f8a0cdc3adaddd222a654c4e61b17861f3a20dd9b584d0073466c722d
Total reclaimed space: 0B

2つのコンテナIDが表示されています。これらのコンテナも削除されました。

実行します。

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                     PORTS               NAMES

予想通り、コンテナの稼働も停止もありません。

概要

まず、コンテナを削除するには、必要なテキストだけを grepping してから awk でコンテナ ID だけを選択する方法を学びました。

次にコンテナIDをxargs docker container rmに渡すと、渡されたコンテナが削除されます。

docker ps -a | grep "hello-world" | awk '{print $1}' | xargs docker container rm

代用します:

docker ps -a | egrep -v "redis|nginx"  | awk '{print $1}' | xargs docker container rm

Docker Container Pruneを使用してコンテナーを削除

docker run -d hello-world

さらに2回実行して、3つのコンテナをクリーンアップするようにします。

docker run hello-world ; docker run hello-world

実行します。

docker container ls

実行中のコンテナしか表示されないので、何も表示されません。

実行します。

docker container ls -a

-aは全てのコンテナを表示します。

期待される出力

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES

60cc61444c0b        hello-world         "/hello"            45 seconds ago       Exited (0) 37 seconds ago                           pensive_albattani
e820b8032706        hello-world         "/hello"            About a minute ago   Exited (0) 51 seconds ago                           silly_lovelace
7e959fd100d0        hello-world         "/hello"            About a minute ago   Exited (0) About a minute ago                       fervent_kilby

docker container prune コマンドは停止しているコンテナをすべて削除します。

コマンド docker container prune --force は停止しているコンテナをすべて削除しますが、確認のためのプロンプトは表示されません。

実行します。

docker container prune -f

期待される出力

 Deleted Containers:
60cc61444c0b90c7f2b0ada1546c3913a93676bbb0ba0dfb1c9329268222df6d
e820b803270681be048b511d676af56e28778e92ef783a536a4272f7d9648bd6
7e959fd100d0a72311f25987a0d0b6d1960283f2b164e56c538baddad83e8446

総埋立面積:0B

3つのコンテナを削除しました。prune オプションの -f は --force のショートカットです。

ラベルを使ったコンテナのプルーニング

ラベルは、関連するコンテナをグループ化するためにdockerで使用されます。そして、ラベルの値に基づいてそれを選択することで、コンテナを選択的に処理することができます。

コマンド docker container prune は、ラベルをフィルターとして使用したコンテナの削除をサポートしています。

現在サポートされているフィルタは以下の通りです。

until () - 指定されたタイムスタンプより前に作成されたコンテナのみを削除します。

label - 指定したラベルが付いている(label!=...の場合は付いていない)コンテナのみを削除します。

今回はラベルを使って3つのコンテナを作成してみましょう。

以下の3つのコマンドを実行します。

docker run -d --label hello-1 hello-world
docker run -d --label hello-2 hello-world
docker run -d --label hello-3 hello-world

docker ps -a コマンドはラベルを表示しません。ラベルを表示するには --format オプションを使う必要があります。

完全な --format のリファレンスは

https://docs.docker.com/engine/reference/commandline/ps/#formatting

実行します。

docker ps -a --format 'table {{.Image}}\t{{.Labels}}\t{{.Command}}\t{{.Status}}'

期待される出力

IMAGE               LABELS              COMMAND             STATUS
hello-world         hello-3=            "/hello"            Exited (0) 1 minutes ago
hello-world         hello-2=            "/hello"            Exited (0) 1 minutes ago
hello-world         hello-1=            "/hello"            Exited (0) 1 minutes ago

実行してhello-1コンテナだけを選択的にpruneしてみましょう。

docker container prune --force --filter "label=hello-1”

期待される出力


Deleted Containers:
1aa4c41c7a5b164edb4bb08cec4ec8c9769fb3e7dc311c825321fc7f87989ea9
Total reclaimed space: 0B

コマンドを再実行します。

docker ps -a --format 'table {{.Image}}\t{{.Labels}}\t{{.Command}}\t{{.Status}}'
IMAGE               LABELS              COMMAND             STATUS
hello-world         hello-3=            "/hello"            Exited (0) 4 minutes ago
hello-world         hello-2=            "/hello"            Exited (0) 4 minutes ago

これで残りのコンテナは2つになりました。

この2つのコンテナを実行してプルーニングしてみましょう。

docker container prune -f

実行します。

docker ps -a

期待される出力

IMAGE               LABELS              COMMAND             STATUS

すべてのコンテナをプルーニングしました。ラベルは、特定のラベルで1つのコンテナを選択的にプルーニングするのに便利です。

複数のコンテナが同じラベルを共有している場合には、複数のコンテナをプルーニング
するのと同じように便利です。

Docker ps フィルタリングのリファレンス

https://docs.docker.com/engine/reference/commandline/ps/#filtering より

name:::コンテナ名

label::: キーまたはキーと値のペアを表す任意の文字列。または = のように表現される。

ancestor:::: 指定された画像を共有するコンテナをancestorとしてフィルタリングします。

volume:::指定されたボリュームまたはバインドマウントをマウントした実行中のコンテナをフィルタリングします。

network:::指定されたネットワークに接続されているコンテナをフィルタリングします。

publish or expose::: を実行しているコンテナをフィルタリングします。指定されたポートを公開または公開するコンテナをフィルタリングします。port[/protocol]で表現されます。

これら3つのコンテナは同じ祖先イメージを共有しています。hello-word:latest__は、このコマンド一つで簡単にプルーニングすることができました。

docker container prune --force --filter __ "ancestor=hello-word:latest" __

これら3つのコンテナが同じネットワークを使用している場合、例えば mytestnetwork__ のように、このコマンド一つで簡単にプルーニングできました。

docker container prune --force --filter __ "network=mytestnetwork" __

終了ステータスを使用したコンテナのプルーニング

終了ステータスは、終了したコンテナ内のプロセスの成功ステータスを表します。

終了ステータスが0の場合、通常は成功を意味します(オペレーティングシステムやプログラミング言語では、終了ステータス0=成功)。

終了ステータスの特定の数値は、特定のプログラミング言語やプログラムで定義された値を持っています。例えば、404はNginxとApacheのウェブサーバでウェブページが見つからないことを意味します。

以下の123と9の終了ステータスは、単に乱数であり、異なる終了ステータスを持つコンテナをクリーンアップする方法を示すために使用されています。

以下のコマンドを実行して、4つの異なる終了ステータスコードを持つ5つのコンテナを作成します。

docker run -d alpine:3.8 /bin/sh -c 'exit 123'
docker run -d alpine:3.8 /bin/sh -c 'exit 9'
docker run -d alpine:3.8
docker run --name nginx -d  nginx:mainline-alpine
docker run --name redis -d  redis:alpine

以下を実行して、コンテナの一覧とステータスの終了コードを表示します。

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED              STATUS                            PORTS               NAMES

9d4163879e17        redis:alpine            "docker-entrypoint.s?   13 seconds ago       Up 3 seconds                      6379/tcp            redis
2754c6805252        nginx:mainline-alpine   "nginx -g 'daemon of?   26 seconds ago       Up 15 seconds                     80/tcp              nginx
ef02229f40da        alpine:3.8              "/bin/sh"                42 seconds ago       Exited (0) 30 seconds ago                             epic_nobel
857cf388b70c        alpine:3.8              "/bin/sh -c 'exit 9'"    59 seconds ago       Exited (9) 46 seconds ago                             peaceful_torvalds
8b084d95a2fb        alpine:3.8              "/bin/sh -c 'exit 12?   About a minute ago   Exited (123) About a minute ago                       pedantic_mirzakhani

nginxとredisが実行されていますが、まだ終了コードはありません。

では実行してみましょう。

docker ps -a --filter status=exited

期待される出力

CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                            PORTS               NAMES

ef02229f40da        alpine:3.8          "/bin/sh"                About a minute ago   Exited (0) About a minute ago                         epic_nobel
857cf388b70c        alpine:3.8          "/bin/sh -c 'exit 9'"    About a minute ago   Exited (9) About a minute ago                         peaceful_torvalds
8b084d95a2fb        alpine:3.8          "/bin/sh -c 'exit 12?   2 minutes ago        Exited (123) About a minute ago                       pedantic_mirzakhani

--filter status=exitedを指定してから、3つの終了したコンテナだけが表示されました。

docker ps -a --filter 'exited=0’

期待される出力

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES

ef02229f40da        alpine:3.8          "/bin/sh"           About a minute ago   Exited (0) About a minute ago                       epic_nobel

終了したコンテナは1つだけ表示されます。

実行します。

docker ps -a --filter 'exited=123’

期待される出力

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS               NAMES

8b084d95a2fb        alpine:3.8          "/bin/sh -c 'exit 12?   2 minutes ago       Exited (123) 2 minutes ago                       pedantic_mirzakhani

終了したコンテナが1つだけ表示されています:exited status = 123

終了ステータス=0のコンテナを削除してみましょう。

docker ps -a --filter 'exited=0' | awk '{print $1}' | xargs docker container rm

実行します。

ef02229f40da
Error: No such container: CONTAINER

実行します。

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                       PORTS               NAMES

9d4163879e17        redis:alpine            "docker-entrypoint.s?   4 minutes ago       Up 3 minutes                 6379/tcp            redis
2754c6805252        nginx:mainline-alpine   "nginx -g 'daemon of?   4 minutes ago       Up 4 minutes                 80/tcp              nginx
857cf388b70c        alpine:3.8              "/bin/sh -c 'exit 9'"    4 minutes ago       Exited (9) 4 minutes ago                         peaceful_torvalds
8b084d95a2fb        alpine:3.8              "/bin/sh -c 'exit 12?   5 minutes ago       Exited (123) 4 minutes ago                       pedantic_mirzakhani

exited=0 コンテナの削除に成功しました。

なぜエラーが出るのか:
Error: そのようなコンテナはありません。: CONTAINER

実行してみてください。

docker ps -a --filter 'exited=9' | awk '{print $1}’

期待される出力

CONTAINER
857cf388b70c

そのCONTAINERヘッダーが問題です。xargs docker container rm にはコンテナ ID のリストだけを渡すべきです。

問題を修正するには、grep: grep -v CONTAINERを使ってCONTAINERヘッダの行を削除してください。

-v は --invert-match のショートカットです。

実行します。

docker ps -a --filter 'exited=9' | awk '{print $1}' | grep -v CONTAINER

期待される出力

857cf388b70c

Success: CONTAINER ヘッダー行が表示されていません。

この2行は同じ結果になっています。

docker ps -a --filter 'exited=9' | awk '{print $1}' | grep -v CONTAINER

ここでは、docker psは、9つのステータスコードコンテナを終了したフィルタリング、awkは最初のフィールドを表示し、grepは、CONTAINERの単語を除外して行を選択します。

代わりに:

docker ps -a --filter 'exited=9' | grep -v CONTAINER | awk '{print $1}'

ここでは、docker psは9つのステータスコードコンテナをフィルタリングし、grepはCONTAINERという単語を除いた行を選択し、awkは最初のフィールドを表示します。

一般的には、最初にgrepで選択を行い、最後のステップとしてawkで必要なカラムだけを表示します。論理的には、grepで選択し、最後にawkで結果を表示するという流れの方が良いでしょう。

ステータス9が終了したコンテナを、エラーメッセージを表示させずに削除してみましょう。

実行:

docker ps -a --filter 'exited=9' | awk '{print $1}' | grep -v CONTAINER | xargs docker container rm

期待される出力

857cf388b70c

Success: コンテナが削除され、エラーは表示されません。

ステータス123が終了したコンテナを、エラーメッセージが表示されないように削除してみましょう。

実行:

docker ps -a --filter 'exited=123' | awk '{print $1}' | grep -v CONTAINER | xargs docker container rm

期待される出力

8b084d95a2fb

Success: コンテナが削除され、エラーは表示されません。

実行します。

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES

9d4163879e17        redis:alpine            "docker-entrypoint.s?   10 minutes ago      Up 10 minutes       6379/tcp            redis
2754c6805252        nginx:mainline-alpine   "nginx -g 'daemon of?   10 minutes ago      Up 10 minutes       80/tcp              nginx

nginxとredisだけがまだ動いています。

ステータスのコンテナを削除:作成済み

コンテナが作成された状態で終わってしまうことがあります。これは、コンテナが何かのエラーで実行中の状態に入れなくなったときに起こります。

ここでは、起動時のランフェーズで意図的にエラーを発生させて、作成状態のコンテナを作成してみましょう。

実行:

docker run -d alpine:3.8  <span class=error>  zxgarbagez  </span>

期待される出力

cc00b62dcb5078fed6d9e3fc48a9e5e7a9f3ef11d6722073781c3f5054696889
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \" <span class=error> zxgarbagez </span>\": executable file not found in $PATH": unknown.

実行:

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES

cc00b62dcb50        alpine:3.8              "zxgarbagez"             28 seconds ago      Created                                 zealous_colden
9d4163879e17        redis:alpine            "docker-entrypoint.s?   17 minutes ago      Up 17 minutes       6379/tcp            redis
2754c6805252        nginx:mainline-alpine   "nginx -g 'daemon of?   17 minutes ago      Up 17 minutes       80/tcp              nginx

zxgarbagezのエラーで作成された状態になってしまいます。

このように作成されたコンテナだけをリストアップしてみましょう。

docker ps --filter status=created

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES

cc00b62dcb50        alpine:3.8              "zxgarbagez"             28 seconds ago      Created                                 zealous_colden

status=created にあるコンテナをすべて削除してみましょう。

実行:

docker ps --filter status=created | awk '{print $1}' | grep -v CONTAINER | xargs docker container rm

期待される出力

cc00b62dcb50

削除されたときに表示されるコンテナの名前。

実行します。

docker ps -a

期待される出力

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES

9d4163879e17        redis:alpine            "docker-entrypoint.s?   17 minutes ago      Up 17 minutes       6379/tcp            redis
2754c6805252        nginx:mainline-alpine   "nginx -g 'daemon of?   17 minutes ago      Up 17 minutes       80/tcp              nginx

nginxとredisだけがまだ動いています。

ステータスでコンテナを削除します:一時停止

このセクションでは、コンテナを一時停止してから削除を試みます。

Dockerはコンテナ内の全てのプロセスを凍結/一時停止するためにcgroupsフリーザー機能を使用します。

cgroups フリーザー機能を使うと、コンテナ内のプロセスは気づかず、フリーズコマンドを防ぐことも無視することもできません。

実行:

docker run -d --name testme alpine:3.8 /bin/sh -c 'sleep 10m'

小さな alpine Linux ディストリビューションを使ってコンテナを起動します。/bin/sh コマンド ( /bin/bash の小型版) を使用しています。sleep コマンド (何もしない) を 10 分間実行します。これで、一時停止できるコンテナが起動しました。

実行:

docker pause testme

期待される出力

testme
docker pause showed the name of the container it just paused: testme

実行:

docker ps -a

期待される出力

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS               NAMES

637489e9b88d        alpine:3.8          "/bin/sh -c 'sleep 1?   14 seconds ago      Up 6 seconds (Paused)                            testme

一時停止状態になっていることに注意してください。

以下のコマンドを実行すると、同じ出力リストが得られます。

docker ps --filter status=paused

このコンテナを削除してみましょう。実行してみます。

docker ps --filter status=paused | awk '{print $1}' | grep -v CONTAINER | xargs docker container rm

期待される出力

Error response from daemon: You cannot remove a paused container 637489e9b88d5704b9e677ff26199a9fec41644d4310732943cab0a2c8b0d4a6. Unpause and then stop the container before attempting removal or force remove

出力を読んでみてください。実行してコンテナを停止してみましょう。

docker stop testme

期待される出力

testme

ttme が停止したことを示します。

一時停止したいコンテナが複数ある場合は、以下のようにして一気に停止させることができます。

docker ps --filter status=paused | awk '{print $1}' | grep -v CONTAINER | xargs docker container stop

これで一時停止状態のすべてのコンテナが停止します。

これでうまくいったかどうか調べてみましょう。
実行:

docker ps --filter status=stopped

期待される出力

Error response from daemon: Invalid filter 'status=stopped’

明らかに停止状態はありません。コンテナを停止すると終了状態になります。

コンテナの有効な状態の一覧: created, restarting, running, removing, paused, exited, or dead

今度は正しい状態である exited を使って、それがうまくいったかどうかを調べてみましょう。実行してみましょう。

docker ps --filter status=exited

期待される出力

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                            PORTS               NAMES

3e8fb9e2c41d        alpine:3.8          "/bin/sh -c 'sleep 1?   3 minutes ago       Exited (137) About a minute ago                       testme

成功しました。これが現在終了しているコンテナのリストです。このコンテナIDのリストをdocker container rmに渡して、これらのコンテナを削除してみましょう。実行します。

docker ps --filter status=exited | awk '{print $1}' | grep -v CONTAINER | xargs docker container rm

期待される出力

3e8fb9e2c41d

成功しました これで、1つだけ終了したコンテナが削除されました。自分で docker ps -a を実行すると、このコンテナがリストに表示されなくなりました。

一時停止していたコンテナは、一時停止した場所で再開できるようになりました。停止しているコンテナは、停止した場所で再起動することはできません。コンテナを再起動すると、最初から始まります。

まとめ: 一時停止したコンテナのプルーニング/削除はできない - 一時停止を解除してからコンテナを停止する必要がある。

終了時にコンテナを削除する

すでに、hello world のコンテナは手動で削除・プルーニングしなければならないことがわかりました。

コンテナを --rm オプションで実行すると、コンテナが終了したときに自動的に削除されます。

これで実践的な体験をしてみましょう。そうすると、便利な --rm オプションを必ず使うことになるでしょう。

以下の3つのコマンドを実行して、3つのhello worldコンテナを作成します。

docker run -d --rm hello-world
docker run -d --rm hello-world
docker run -d --rm hello-world

を使ってコンテナの一覧を確認してみましょう。

docker ps -a

期待される出力。

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

終了したhello worldコンテナが表示されていません。rmはこれら3つのコンテナが終了すると自動的に削除します。クリーンアップの必要はありません。

これらのbash aliasesを定義してください。2つ目のaliasを使ってクイックテストを行うことができ、後のクリーンアップの手間を省くことができます。

alias dr='docker run'

alias drrm='docker run --rm'

bash のエイリアスは長いシェルコマンドの短縮版です。その目的は、長いコマンドを入力しないようにすることです。

チュートリアルのクリーンアップ

このチュートリアルはここまでです。

以下のコマンドを実行して、使用しなくなった画像をすべて削除してください。

docker image rm hello-world:latest
docker image rm nginx:mainline-alpine
docker image rm redis:alpine
docker image rm alpine:3.8

Dockerの全体的なクリーンアップ

もしかしたら、あなたの開発用 docker サーバーは混乱しているかもしれません。

すべてのコンテナを停止すべきかもしれません。

そんなときは、以下のような方法ですぐに実行できます。

docker stop $(docker ps -a -q) #stop ALL containers
docker ps -a -q builds a list of all container IDs - running and exited.

これらのIDをdocker stopに渡します。

すべてのコンテナが停止します。既に終了したコンテナに対してはエラーは表示されません。

すべてのコンテナを削除するには、次のように実行します。

docker rm -f $(docker ps -a -q) # remove ALL containers

概要

これで、あなたの仕事にコンテナクリーンアップコマンドを適用して実験することができるようになりました。

安全のためのヒント: 常にコマンドを実行して、選択されたコンテナのリストを表示するようにしてください。その後、docker container rm を実行して、実際にコンテナを削除してください。

grep, awk, xargs はこのチュートリアルで幅広く使われています。これらのツールに慣れていない場合は、チュートリアルを読む価値があることがわかります。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

重要なDocker-composeの設定 - Docker Composeのための実践的な演習その2

このチュートリアルでは、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

( 前節からの続きで、重要な見出しを追加しました )

https://docs.docker.com/engine/reference/commandline/run/#configure-namespaced-kernel-parameters-sysctls-at-runtime より

重要:

すべての 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ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker 上の Redash のログのサイズを調べる

Redash を動かしているサーバのディスクが枯渇してきたので、ログが圧迫している可能性を考えたが、Docker で動かしていたので、どこにログがあるのか不明だった。
docker inspect を使うと、ログの場所がわかる、ということなので、作ったワンライナーが下記。
調べても意外と出てこなかったので、備忘録として残す。

docker container ls --format "{{.Names}}" | xargs -tn1 -I{} sh -c "sudo ls -lh \$(docker inspect --format='{{.LogPath}}' {})"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.jsのdockerコンテナでホットリロードされないときの解決法

解決法

プロジェクトルートにnext.config.jsを作成する

next.config.js
module.exports = {
  webpackDevMiddleware: config => {
    config.watchOptions = {
      poll: 800,
      aggregateTimeout: 300,
    }
    return config
  },
}

実行環境

  • win10
  • docker-machine

ソースコード

.
├─ .next
├─ node_modules
├─ pages
│  └─ index.js
├─ docker-compose.yml
├─ Dockerfile
└─ package.json
docker-compose.yml
version: '3.3'

volumes:
  node_modules:

services:
  app:
    build: .
    container_name: next
    ports:
      - '80:3000'
    restart: always
    volumes:
      - '.:/app'
      - 'node_modules:/app/node_modules'
    tty: true
    stdin_open: true
# Dockerfile
FROM node:12

WORKDIR /app

COPY ./package*.json ./

CMD bash -c "npm install && npm run dev"
package.json
{
  "name": "nextjs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "next": "^9.4.4",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
  }
}
pages/index.js
const Index = () => (
  <div>
    <p>Hello Next.js</p>
  </div>
)

export default Index
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

node+nodemonのdockerコンテナ

node + nodemon の開発用コンテナを作成した。実行環境はwin10とdocker-machine

.
├── app.js
├── docker-compose.yml
├── Dockerfile
├── package-lock.json
├── package.json
└── node_modules
#Dockerfile

FROM node:12

WORKDIR /app

# ホストのpackage.jsonとpackage-lock.jsonを
# コンテナの/appにコピー
COPY ./package*.json ./

CMD bash -c "npm install && npm run dev"
docker-compose.yml
version: '3.3'

volumes:
  node_modules:

services:
  app:
    build: .
    container_name: node
    ports:
      - '80:8081'
    restart: always
    volumes:
      # ホストのdocker-compose.ymlがあるディレクトリを
      # コンテナの/appマウントする
      - '.:/app'
      # ただしnode_modulesだけ除外するためnode-mudulesボリュームを
      # コンテナの/app/node_modulesにマウントする
      # コンテナ内でnpm install してもホストのnode_modulesは空のまま
      - 'node_modules:/app/node_modules'
    # 下2行はdocker run コマンドの-itオプションに相当する
    # 無いとコンテナが停止してしまう
    tty: true
    stdin_open: true
package.json
{
  "name": "hoge",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node ./app.js",
    "dev": "nodemon -L ./app.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.4"
  },
  "author": "",
  "license": "ISC"
}

以下のようにしてDockerfileでnpm startするとnodemonは機能しなかった。startキーではダメ。さらに-Lオプションが必要。

 "scripts": {
    "start": "nodemon ./app.js"
  }

起動コマンドなど

コンテナ起動

docker-compose up -d

node_modulesボリュームは自動で作成される。project_node_modulesという名前になる。docker-machineのIPアドレスでブラウザからnodeサーバーにアクセスできる

nodemonが機能してることを確認する

docker-compose logs -f

または

docker logs node -f

コンテナ削除

docker-compose down --rmi all

--rmi all でイメージも削除される

node_modulesボリュームを削除

docker volue rm project_node_modules

ボリューム名を確認

docker volume ls

docker-machineのIPを調べる

docker-machine ls

または

docker-machine ip
docker-machine ip default
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでNodedock + NUXTの開発環境を作る

目的

  1. NodedockでDockerの開発環境つくる
  2. 新規にNUXTプロジェクトを作る
  3. ブラウザで表示する

ちなみに、経緯としては
久しぶりにMacでyarnでnuxtを新規にcreateして…いつもの流れで構築すると、バージョン周りでyarnコマンドがエラー吐きまくって解決に時間かけるのも煩わしかったので、dockerでサクッと作れないかなと思い立ったのが経緯。

バージョン

Host

  • macOS Catalina 10.x
  • git version 2.24
  • Docker version 19.03
  • docker-compose version 1.25

Guest

  • create-nuxt-app 3.1.0
  • node 10.20.1
  • yarn 1.22.4

参考サイト

Nodedock 公式サイト
Nuxt.js 公式サイト

NodedockでDockerの開発環境つくる

作業用ディレクトリ作成

mkdir sample-project

cd sample-project

NodedockをCloneする

git clone https://github.com/nodedock/nodedock.git

.envを作成

cd nodedock

cp env-example .env

.envを編集

- NODE_VERSION=10.7.0
- NGINX_HOST_HTTP_PORT=80
+ NODE_VERSION=10.20.1
+ NGINX_HOST_HTTP_PORT=38080

nginxの設定追加

cp nginx/sites/app.conf.example nginx/sites/app.conf
-    server_name app.test;
-    root /var/www/app;
+    server_name node.test
+    root /var/www/<project name>;

hosts設定追加

vi /etc/hosts

127.0.0.1       node.test

docker起動

docker-compose up -d nginx mysql

# 再ビルドする場合
docker-compose build --no-cache nginx mysql
docker-compose up -d nginx mysql

workspaceにログイン

docker-compose exec workspace bash

バージョン確認
※執筆時点のバージョンです

root@xxxxx:/var/www# node -v
v10.20.1

root@xxxxx:/var/www# yarn -v
1.22.4

root@xxxxx:/var/www# npm -v
6.14.4

新規にNUXTプロジェクトを作る

workspaceにログイン
※ログイン済の場合はスキップ

docker-compose exec workspace bash

yarnでnuxtプロジェクトを新規作成
※npmの場合は公式サイトを参照

yarn create nuxt-app nuxt-project

各設問について

下記記事で詳しく解説しています
Nuxt.jsで多言語化デビューしよう!

Project name ... プロジェクト名 ※未入力でEnterした場合は()内の名称になる
Programming language ... 言語選択。動的型付けならJavascript、静的型付けならTypescript
Package manager ... パッケージ管理ツール選択。NPMかYarn(Yarn推奨)
UI framework ... UIフレームワーク選択。後から追加可能。
Nuxt.js modules ... モジュール選択。
Linting tools ... 静的解析ツール選択。
Testing framework ... テストフレームワーク選択。
Rendering mode ... レンダリングモード選択。
Deployment target ... デプロイ対象。サーバーサイドならServer、サーバーレスならStatic
Development tools ... デプロイツール。

参考までに。
サーバーサイドのアプリケーションを作りたいので今回の設定はこんな感じ。

✨  Generating Nuxt.js project in nuxt-project
? Project name: nuxt-project
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: None
? Nuxt.js modules: 
? Linting tools: ESLint
? Testing framework: Jest
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: 

下記が表示されればインストール完了

?  Successfully created project nuxt-project

アプリケーション起動

cd <project name>

nuxt build

nuxt start

下記URLにアクセス
page/index.vueの内容が表示されていればOK

http://localhost:3000/

【余談】
記事振り返ってみたら、hosts追加したのに使ってなかったです。。
ドキュメントルートで読み込まれるファイルが見当たらなかったので、今度時間作ってちゃんと仕組み理解して更新します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerのデータの”保存”する仕組みについて理解した話

1. はじめに

dockerやdocker-composeを使って、チームで使うサービス(re:dash)を運用したら、
バージョンアップとかガンガンできるだろうし、バックアップもリストアも自由自在ヒャッハーできるしょ!
と思って使いはじめたが、やりたいことができずきハマった、データ保存先について整理した記事です。

”保存”に特化しているため、dockerがほかの仮想マシンと比較してどうかなどの、メリットとデメリットなどを記載はしません。だって面倒くry。

この記事を読むと、dockerのデータを”保存”しているのか、イメージを理解できようになります(たぶん)。

2. dockerがデータを"保存"するモノとは

データを”保存"する「イメージ」「ボリューム」「コンテナ」の概念について、まとめます。
概念が違うものなので、並べることが適切ではないかもしれませんが、保存を理解するためには必要なので、並べて書きます。

※ Dockerfile, docker-compose.yml と記載したものは設定ファイル名の例です。
 実際には変更が可能なため、正しくありませんが便宜的に上記表現で記載しています。

2.1 イメージ

Dockerfileで定義された、「docker image」で管理される領域、またはDocker Hubなどのサービス可能に登録されたものです。
どのような構成、何をインストールしておくか、といったことを”保存”できます。

2.2 ボリューム

データを"保存"するデータ領域のことを指します。ボリュームといっても、コンテナ内部(Dockerfile volumeコマンドなど)と外部マウント(docker run -v xxx:yyyy)の2つのことが混同されて記述されている記事があるため、注意が必要です。

外部マウントのボリュームは、dockerサービス内で定義されたボリューム(docker volume createや他のコンテナのボリュームなど)と、dockerのホストのデータ領域の、いずれかを指定することができます。

簡単な図にまとめると、以下のようなイメージです。
docker-volume.png
※注意 正確にはボリュームをマウントする指示をせずに実行した場合には、dockerのvolumesに実体が作られ、--rmオプションなどがついてると自答削除できるので、図ではわかりやすさのため、コンテナ内にあるように歪曲して記載しています。

2.3 コンテナ

イメージに対して「docker run」を実行して作られる、コンテナとよばれるインスタンスのことを指します。
このインスタンスには、起動中、停止中の状態をもち、docker start, docker stopなどで、開始、停止をコントロールできます。
起動中の場合に、イメージで作ったサービスが利用できるようになります。

起動時に、マウントする先を明示的におこなっていない場合、コンテナで作成されたボリュームは、起動したコンテナが削除されるまで”保存”できます。その状態で、うっかり、「docker rm コンテナ」としてしまうと、
保存されたデータが削除され、泣くことができます。

3 データの保存先について(考察)

サービスとして提供するのであれば、dockerのボリューム領域(docker volume createで作った領域)か、ホストのデータ領域を使うのが賢明だと思います。

ただし、dockder for windows (desktop 2.3.0.3, engine 19.03.8, compose 1.25.5)では、
ボリュームに対して権限を設定しようとするとうまくいかない不具合があるため、アプリによっては、dockerのボリューム領域を使う必要があります(postgresの公式イメージのdataフォルダなど)。

そのため、現状でバックアップまで考えた運用については、ホスト領域とdockerのボリューム領域をマウントして、コピーするだけの仮想コンテナを作ってあげるなど工夫が必要そうです。
※ 実はそれでも権限周りはいけてなく、現状ではlinuxの上に構築するほうが無難です。

4 おわりに

dockerについて勉強をはじめて、1か月たたない初心者なので、もし間違いがあったら、指摘をお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

dockerで作るnuxt.jsの開発環境

環境

docker desktop for windows(wsl2)

実装

Dockerfile

FROM node:12.18.2-alpine

RUN apk update && \
    npm install -g npm && \
    npm install -g create-nuxt-app

ENV HOST 0.0.0.0
EXPOSE 3000

node.jsの最新安定板のコンテナイメージでnpmの更新とcreate-nuxt-appをインストールしています。それからホスト側からアクセスできるようにします。

docker-compose.yml

version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    working_dir: "/usr/local/src"
    volumes:
      - ".:/usr/local/src"
      - node_modules_volume:/usr/local/src/first-app/node_modules
    tty: true
volumes:
  node_modules_volume:

Dockerfileと同じディレクトリ内に配置して使います。
ポートフォワーディングとデータ永続化、コンテナの起動を維持するためのtty: trueだけを記述したシンプルな構成です。あとは、node_module用にVolumeを作成します。これがあるのと無いのとでは実行速度に天と地の差がありました。

ビルド&起動

$ docker-compose build
$ docker-compose up

すると、dockerのダッシュボードから確認できるようになるので、cliからコンテナの中に入ります。

アプリケーション作成

/usr/local/src # npx create-nuxt-app first-app

create-nuxt-app v3.1.0
✨  Generating Nuxt.js project in first-app
? Project name: first-app
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: Axios, Progressive Web App (PWA)
? Linting tools: ESLint, Prettier, Lint staged files, StyleLint
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: jsconfig.json (Recommended for VS Code)
.
.
.

?  Successfully created project first-nuxt-app

  To get started:

        cd first-nuxt-app
        yarn dev

  To build & start for production:

        cd first-nuxt-app
        yarn build
        yarn start

  To test:

        cd first-nuxt-app
        yarn test

nuxtの既成レイアウトを使いたい

https://vuetifyjs.com/ja/getting-started/pre-made-layouts/
この中のBaselineが使いたいのでlayouts/default.vueを変更(コピペ)

cd first-nuxt-app
yarn dev

.
.
.
.

  82:10  error    Insert ``                                                                                                                                                                                                                             prettier/prettier

✖ 16 problems (15 errors, 1 warning)
  15 errors and 0 warnings potentially fixable with the `--fix` option.

詳しいことはわかりませんがprettierがエラーをだした。下記コマンド実行後サーバー再起動。
https://stackoverflow.com/questions/52571675/nuxt-js-module-error-from-node-modules-eslint-loader-index-js

npx prettier --write "**/*.{vue,js}"

nuxt-page.png
よし!

ホットリロード

サーバー再起動するが面倒なのでホットリロードの設定をつけます。
nuxt-config.jsにて

module.exports = {
  ...
    watchers: {
       webpack: {
           poll: true
       }
    }
 Waiting for file changes                                                                                    15:57:50
ℹ Memory usage: 472 MB (RSS: 595 MB)                                                                          15:57:50
ℹ Listening on: http://172.21.0.2:3000/

動きました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む