Slide 1

Slide 1 text

開運研修 2019 Docker Neco 池添 明宏 1

Slide 2

Slide 2 text

目次 ▌はじめに ▌コンテナの仕組み ▌Dockerベストプラクティス ⚫ Dockerfile編 ⚫ アプリケーション編 ▌演習 2

Slide 3

Slide 3 text

はじめに 3

Slide 4

Slide 4 text

コンテナとDocker ▌コンテナとは ⚫ アプリケーションごとに隔離された環境を提供する仮想化 の仕組み ▌Dockerとは ⚫ もっとも代表的なコンテナ実行ソフトウェア ⚫ コンテナを実行するソフトウェアだけでなく、コンテナイ メージの作成やイメージを共有する仕組みなどのエコシス テムも提供する 4

Slide 5

Slide 5 text

サイボウズでのコンテナ事情 ▌開発 ⚫ いくつかの開発チームでは開発環境としてDockerを利用 ▌テスト ⚫ CircleCIやJenkinsの実行環境としてDockerを利用 → 詳しくは開運研修「CI/CD」で ▌運用 ⚫ YakumoやNecoでは、ほとんどのソフトウェアをKubernetes 上でコンテナとして動作させている → 詳しくは開運研修「Kubernetesを使った開発入門」で 5

Slide 6

Slide 6 text

Necoで開発しているコンテナ ▌レジストリ ⚫ https://quay.io/organization/ cybozu ▌Dockerfile ⚫ https://github.com/cybozu/u buntu-base/ ⚫ https://github.com/cybozu/n eco-containers 6

Slide 7

Slide 7 text

コンテナ利用のメリット ▌Batteries included, but removable ▌Build once, Run anywhere ▌アプリケーションの動作環境を丸ごとパッケージにまとめて、ひと つのファイルとして扱うことができる。 ▌開発・テスト・本番でソフトウェアの実行環境のギャップを小さく することができる。「手元で動いたのに!?」が減らせる。 ▌VMと比較して軽量であるため扱いやすく、リソースの利用効率も 高くなる。 7

Slide 8

Slide 8 text

コンテナの仕組み 8

Slide 9

Slide 9 text

VMとコンテナの違い Hardware Hypervisor VM VM OS プロセス プロセス OS プロセス プロセス Hardware Linux コンテナ コンテナ ファイル プロセス ファイル プロセス VM: ・仮想的なサーバを用意し、その上にOSを セットアップ。 ・イメージサイズが大きい。 ・起動が遅い(OSの起動時間)。 ・ホストと異なるOSを動かすことができる。 コンテナ: ・Linuxカーネルの機能を利用してプロセス を隔離。 ・イメージサイズが比較的小さい。 ・起動が速い(通常のプロセスと同等)。 ・ホストとカーネルを共有。 ファイル ファイル 9

Slide 10

Slide 10 text

コンテナを実現するための技術要素 ▌Linux namespace ⚫ プロセスに対して、PID空間、ネットワーク空間、ユーザー空間、 ホスト名などのリソースを分離することができる。 ▌cgroups ⚫ CPUやメモリなどのリソースを制限・隔離することができる。 ⚫ 開運研修「LinuxサーバのCPUやメモリリソースの管理につい て」で詳しく解説。 ▌Linux capability ⚫ 特権ポートへのアクセスやiptablesへのアクセス権などの権限を 制御することができる。 10

Slide 11

Slide 11 text

Host Computer Dockerの構成 Container Image Dockerfile Docker Container Runtime Container Registry Container Container Container Container Image Container Image docker build docker run docker push docker pull 11

Slide 12

Slide 12 text

Dockerの構成要素 ▌ Dockerfile ⚫ Container Imageの作成手順を記述したファイル ▌ Container Image ⚫ コンテナの実行に必要なファイルなどをまとめたアーカイブファイル ▌ Container ⚫ 実際に実行されているコンテナ ▌ Docker Container Runtime ⚫ コンテナを実行するソフトウェア ▌ Container Registry ⚫ Container Imageを共有するためのサービス ⚫ Docker Hub, Quay.io, GCR(Google Container Registry)など 12

Slide 13

Slide 13 text

MacやWindows上のDockerは? ▌軽量なLinux VM上でDockerを動かしている ⚫ Docker Desktop for Mac / Windows ⚫ Docker toolbox (legacy) ▌注意点 ⚫ Mac版はホストとコンテナ間で共有する ファイルのアクセスが遅い ⚫ Docker DesktopはWindows Home Editionで動かない (WSL2対応で改善) ⚫ コンテナ向けの実行ファイルはLinux用に ビルドする必要がある macOS Linux VM hyperkit macの プロセス Docker Container Runtime Docker CLI コンテナ コンテナ コンテナ Docker Desktop for Mac のアーキテクチャ 13

Slide 14

Slide 14 text

コンテナオーケストレーションツール ▌複数のコンテナを組み合わせたアプリケーションを実行したり管理 するための仕組み ▌docker-compose ⚫ シングルホスト上で複数のコンテナを組み合わせて実行するた めのツール ▌Kubernetes ⚫ 複数のホスト上にコンテナを適切にスケジューリングしたり、 コンテナの自動復旧やアップグレードなど様々な管理をおこ なってくれる。 ⚫ デファクトスタンダード 14

Slide 15

Slide 15 text

ハンズオン1 Dockerに触れてみる 15

Slide 16

Slide 16 text

準備 ▌Dockerのセットアップ ⚫ Docker Desktop for Macを使いたい人 ⚫ https://docs.docker.com/docker-for-mac/install/ ⚫ VMを立ててやってみたい人 ⚫ https://www.virtualbox.org/wiki/Downloads ⚫ https://www.vagrantup.com/ ▌サンプルファイルの取得 ⚫ git clone https://github.com/zoetrope/training- docker.git 16

Slide 17

Slide 17 text

ハンズオンの内容 ▌コンテナイメージの取得 ▌コンテナの起動 ▌コンテナに入ってみる ▌ホストとのファイル共有 17

Slide 18

Slide 18 text

よく使うDockerコマンド ▌ run : コンテナの実行 ▌ stop : コンテナの停止 ▌ rm : コンテナの削除 ▌ ps : コンテナの確認 ▌ container prune : 停止しているコンテナの削除 ▌ inspect : コンテナの詳細情報の取得 ▌ exec : コンテナ上でコマンドの実行 ▌ logs : コンテナのログを確認 ▌ build : コンテナイメージのビルド ▌ images : コンテナイメージの確認 ▌ rmi : コンテナイメージの削除 ▌ image prune : 未使用コンテナイメージの削除 詳しくは docker --help 18

Slide 19

Slide 19 text

コンテナイメージの取得 # ローカルのコンテナイメージの表示 docker images # Docker Hubからコンテナイメージを取得する docker pull nginx:latest # 再度、ローカルのコンテナイメージの表示 docker images 19

Slide 20

Slide 20 text

コンテナの起動 # コンテナの起動 # -d: バックグラウンドで起動 # --name: コンテナに名前をつける(省略した場合は自動で名前がつく) # -p 8080:80: コンテナの80番ポートをホストの8080番ポートにバインド docker run -d --name mynginx -p 8080:80 nginx:latest # 起動しているコンテナの確認 # コンテナの停止・削除 docker ps docker stop mynginx curl localhost:8080 docker rm mynginx docker logs mynginx 20

Slide 21

Slide 21 text

コンテナに入ってみる # ubuntu-debugコンテナ上でbashを実行する # -i: STDINをオープンし続ける -t: 擬似端末を割り当てる # --rm: コンテナ終了時にコンテナを自動削除 docker run -it --rm quay.io/cybozu/ubuntu-debug:18.04 /bin/bash # いろんなコマンドを叩いて、コンテナ内のプロセスやファイルシステム、 # ネットワークの状態などを確認してみる ls hostname ip a ps aux 21

Slide 22

Slide 22 text

ホストとのファイル共有 # 適当なHTMLファイルを作成 cd /path/to/html touch index.html # ホストの/path/to/htmlをコンテナの/usr/share/nginx/htmlにバインド docker run -d --name mynginx -p 8080:80 \ -v /path/to/html:/usr/share/nginx/html \ nginx:latest curl localhost:8080 22

Slide 23

Slide 23 text

Dockerベストプラクティス Dockerfile編 23

Slide 24

Slide 24 text

Dockerfileの書き方 FROM quay.io/cybozu/ubuntu:18.04 COPY ./myapp /work/myapp WORKDIR /work/myapp RUN make && make install ENV PATH /usr/local/bin CMD [“myapp”, “--opt=hoge”] ベースとなるコンテナイメージを指定 docker build時に実行する操作を記述する COPY: ホストからコンテナにファイルを コピー WORKDIR: ワーキングディレクトリの指定 RUN: 任意のコマンドの実行 docker run時に実行されるコマンドや 環境変数などを指定 24

Slide 25

Slide 25 text

Dockerfileのベストプラクティス ▌公式ドキュメント ⚫ https://docs.docker.com/develop/develop- images/dockerfile_best-practices 25

Slide 26

Slide 26 text

Dockerfileのベストプラクティス ▌野良コンテナイメージは使わない ▌コンテナイメージはできるだけ小さく ▌コマンドを正しく使う ▌タグを正しく使う ▌Lintツールを使う 26

Slide 27

Slide 27 text

野良コンテナイメージは使わない ▌野良のコンテナイメージには脆弱性や悪意のあるコードが含ま れている可能性がある。 ▌Neco推奨のベースコンテナイメージを利用しよう。 ▌Docker Official Imagesは比較的安全 ▌どれを使うにしてもよく調査する。 27

Slide 28

Slide 28 text

Necoのベースコンテナイメージ ▌3ヶ月ごとの定期更新と、緊急性のある脆弱性が見つかった場合は即座に 対応をおこなっている。 ▌quay.io/cybozu/ubuntu:18.04 ⚫ 必要最小限のコンテナ ▌quay.io/cybozu/ubuntu-dev:18.04 ⚫ 開発に必要なパッケージを追加 ▌quay.io/cybozu/ubuntu-debug:18.04 ⚫ デバッグに必要なパッケージを追加 ▌quay.io/cybozu/golang:1.12-bionic ⚫ Go言語の開発環境を追加 28

Slide 29

Slide 29 text

コンテナイメージはできるだけ小さく ▌コンテナのイメージサイズが大きくなると、ディスク容量を圧 迫したり、イメージのダウンロードに時間がかかってしまう。 ▌コンテナイメージを小さくする方法 ⚫ レイヤーを意識する ⚫ multi-stage buildを使う ⚫ 小さなコンテナイメージを使う 29

Slide 30

Slide 30 text

コンテナイメージ レイヤーを意識する FROM quay.io/cybozu/ubuntu:18.04 RUN hostname > hostname.txt RUN date > date.txt RUN cat hostname.txt date.txt > id.txt RUN rm hostname.txt date.txt ubuntuイメージのファイル hostname.txtの追加 date.txtの追加 id.txtの追加 hostname.txtとdate.txtの削除 RUNやCOPYを実行するたびに、read-onlyなレイヤーが 積み重なっていく。 不要な中間ファイルをレイヤーに含めると、コンテナイメージ のサイズが無駄に大きくなってしまう。 30

Slide 31

Slide 31 text

RUNコマンドは1行で書く、不要なファイルは削除 ▌ただし、RUNの記述を頑 張ると可読性が低下して しまう。 ▌後述するmulti-stage buildを使うのであれば、 あまり気にする必要はな い。 FROM quay.io/cybozu/ubuntu:18.04 RUN hostname > hostname.txt && \ date > date.txt && \ cat hostname.txt date.txt > id.txt && \ rm hostname.txt date.txt 31

Slide 32

Slide 32 text

multi-stage build ▌ ひとつのDockerfileを複数のス テージに分けて記述することがで きる。 ▌ ビルド用コンテナで生成したファ イルを実行用コンテナにコピー。 ▌ 最終ステージのみがイメージとし て保存される。 ▌ ビルドに必要なツールや中間ファ イルなどが実行用コンテナに含ま れないため、イメージサイズを小 さくできる! # Stage1: build from source FROM quay.io/cybozu/golang:1.12-bionic AS build COPY ./src /work/src WORKDIR /work/src RUN go install ./... # Stage2: setup runtime container FROM quay.io/cybozu/ubuntu:18.04 COPY --from=build /go/bin / ENTRYPOINT [“/myapp”] 32

Slide 33

Slide 33 text

小さなコンテナイメージをベースにする イメージ名 サイズ 特徴 scratch 0B • からっぽのイメージ。libcもshellも入ってない。 • Go言語などでシングル実行可能なバイナリを作れば、イメージサイズは 非常に小さくなり、OS依存の脆弱性も含まないためセキュア。 busybox 1.2MB • Linuxのユーティリティをシングルバイナリで提供。 • scratch同様、シングル実行バイナリのベースとして使われる。 Alpine Linux 5.6MB • 軽量なLinuxディストリビューション。 • ハマりどころも多いので利用には注意が必要。(Necoでは利用禁止) distroless 16.9MB~ • 実行に必要なものだけを持つイメージ。multi-stage buildと組み合わせて 使いやすい。 • Java, Python, Node.js用などランタイムごとにイメージが用意されてい る。 cybozu/ubuntu 103MB • Necoチームが管理しているベースイメージ。 33

Slide 34

Slide 34 text

.dockerignore ▌COPYやADDコマンドを利用 しなくても、Dockerfileと同じ ディレクトリにあるファイル は、Dockerデーモンに転送さ れる。 ▌ビルドに不要なファイル は .dockerignore に指定して おこう。 # 除外するディレクトリや # ファイルのパターンを列挙 .git/ logs/* node_modules/ ./README.md 34

Slide 35

Slide 35 text

コマンドを正しく使う ▌ADDとCOPY ⚫ ADDとCOPYはほとんど同じだが、ADDはファイルの展開 とかインターネットからファイルを取得とか、予期せぬ動 きをする場合がある。普通はCOPYを使えば十分。 ▌ENTRYPOINTとCMD ⚫ コンテナ起動時に実行するコマンドが限定されている場合 はENTRYPOINTを使う。 ⚫ 色々なコマンドを実行して使うコンテナはCMDを使う。 35

Slide 36

Slide 36 text

タグを正しく使う ▌Dockerイメージのタグは、容易に更新できてしまう。 ⚫ 自分たちで作っていないコンテナイメージのタグ付けルールを 理解しておくこと。 ⚫ 自分たちで作っているコンテナイメージのタグ付けルールを しっかりと決めておく。 ▌Necoチームでのタグ運用ルール ⚫ レジストリにあげるイメージは必ず固定タグをつける。固定タ グは変更しない。 ⚫ 利便性のためにブランチのようなタグをつけても良い。 36

Slide 37

Slide 37 text

Lintツールを使う ▌hadolint ⚫ https://github.com/hadolint/hadolint ⚫ Dockerfileの静的解析ツール 37

Slide 38

Slide 38 text

ハンズオン2 Dockerfileを書いてみる 38

Slide 39

Slide 39 text

ハンズオンの内容 ▌docker buildしてみる ▌multi-stage buildを使ってみる ▌hadolintでチェックしてみる 39

Slide 40

Slide 40 text

コンテナイメージのビルド方法 ▌Dockerfileのあるディレクトリで以下のコマンドを実行 docker build -t myapp:v1.0.0 . Dockerfileのあるディレクトリパスを指定 コンテナイメージのタグを指定 コンテナイメージの名前を指定 40

Slide 41

Slide 41 text

サンプル ▌training-docker/02_dockerfile/helloworld ⚫ ubuntuにnode.jsをインストールして、簡単なHTTPサーバ を起動するコンテナ ▌training-docker/02_dockerfile/multi_stage ⚫ multi-stage buildのサンプル ⚫ stage 1: Goの開発環境でプログラムをビルド ⚫ stage 2: 空のイメージに実行ファイルだけをコピー 41

Slide 42

Slide 42 text

コンテナイメージをビルドして動かしてみる # Dockerfileのあるディレクトリに移動してビルド docker build -t hello:v1 . # Lintツールでチェックしてみる docker run --rm -i hadolint/hadolint /bin/hadolint - < Dockerfile # 確認 docker images docker history hello:v1 # 起動してみる docker run --r -d --name hello -p 3000:3000 hello:v1 curl localhost:3000 42

Slide 43

Slide 43 text

Dockerベストプラクティス アプリケーション編 43

Slide 44

Slide 44 text

コンテナアプリケーションのベストプラクティス ▌コンテナはステートレスにする ▌ひとつのコンテナにはひとつの役割 ▌正しくログを出す ▌シグナルを処理する ▌ヘルスチェックの仕組みを用意する ▌柔軟なアプリケーション設定 44

Slide 45

Slide 45 text

コンテナはステートレスにする ▌コンテナ内でアプリケーションを更新したり、ファイルを保存 したりしない。 ▌なぜ? ⚫ 状態を保持すると、いつでもどこでも同じ構成であること が保証できなくなる。 ⚫ 状態を保持していなければ、コンテナをいつでも再起動し たり更新したりできる。 45

Slide 46

Slide 46 text

ステートレスにするには ▌コンテナの更新方法 ⚫ 動いているコンテナに入って更新するのではなく、Dockerfileを 更新する。 ⚫ Dockerfileを更新すると、実行されているコンテナが更新される ようなCI/CDの仕組みを構築しておくとよい。 ▌データを永続化したい場合は、Docker や Kubernetes のVolume 機能を利用する。 ▌docker run に --read-only オプションを指定しよう。(Volume以 外への書き込みを禁止する) 46

Slide 47

Slide 47 text

Volumeの使い方 # volumeを作成する docker volume create vol1 docker volume ls # volumeをマウントしてコンテナを起動 docker run -it --name ubuntu -v vol1:/mnt/data quay.io/cybozu/ubutun:18.04 bash > touch /mnt/data/hoge.txt # コンテナを削除、もう一度コンテナを立ち上げ直してファイルの存在を確認 docker rm ubuntu docker run -it --name ubuntu -v vol1:/mnt/data quay.io/cybozu/ubutun:18.04 bash > ls /mnt/data 47

Slide 48

Slide 48 text

ひとつのコンテナにはひとつの役割 コンテナ App サーバ 全文検索 エンジン データ ベース コンテナ App サーバ コンテナ 全文検索 エンジン コンテナ データ ベース ▌コンテナは役割ごとに分割する。 ▌なぜ? ⚫ コンテナイメージが再利用しやすく なる ⚫ スケールさせやすくなる ⚫ メンテナンスしやすくなる ⚫ エラー時の復旧 ⚫ バージョンアップ わるい例 よい例 48

Slide 49

Slide 49 text

docker-compose ▌docker-composeを利用すると、 複数のコンテナの起動を管理で きる。 ▌起動・停止 ⚫ docker-compose up ⚫ docker-compose down ▌03_application/compose参照 49 version: '3' services: etcd: container_name: etcd image: quay.io/cybozu/etcd:3.3 ports: - 2379 volumes: - etcd-data:/var/lib/etcd todo: container_name: todo image: todo:v1 ports: - 9000:9000 volumes: etcd-data:

Slide 50

Slide 50 text

正しくログを出そう ▌ファイルではなく、標準出力 or 標準エラー出力にログを出す。 ▌ログのローテーションや転送は、アプリケーション側では考え なくてよい。(DockerやKubernetesが用意しているログの仕 組みに任せる) 50

Slide 51

Slide 51 text

シグナルを処理しよう ▌docker stop コマンドを実行した場合や、Kubernetes がコン テナを終了させるときに、コンテナに SIGTERM シグナルが飛 んでくる。 ▌シグナルを処理して、アプリケーションを正しく終了させる。 ⚫ Graceful Shutdown: 新規のリクエストは受け付けず、現 在処理中のリクエストを正常に処理してから、プログラム を終了させる。 ⚫ ライブラリやWebサーバーの機能として提供されているこ とも多い。 51

Slide 52

Slide 52 text

ヘルスチェックの仕組みを用意する ▌コンテナが正しく動作しているかどうか確認するための手段を 用意しておこう。 ▌ヘルスチェック用のWeb APIを用意するのが一般的。 ▌DockerのHEALTCHECK機能や、Kubernetesのliveness probe機能を利用して、コンテナの死活監視がおこなえる。 52

Slide 53

Slide 53 text

エラーが起きたら終了させよう ▌データベースに接続できなかったり、設定ファイルが間違って いるなど、アプリケーションが自力では解決できないエラーが 発生した場合は、プロセスをエラー終了させる。 ▌コンテナがエラー終了すると、Kubernetesが復旧を試みたり、 監視システムがエラーを検知して通知を飛ばすことができる。 ▌エラーが発生しているのにプロセスを動かし続けると、障害の 検出や復旧が遅れる原因になるので注意。 53

Slide 54

Slide 54 text

柔軟なアプリケーション設定 ▌アプリケーションの設定は、環境変数、コマンドラインオプ ション、設定ファイルなどで外部から変更できるようにして おく。 # ホストにある設定ファイルをコンテナに渡して実行する例 docker run \ -v /path/to/your.conf:/etc/your.conf \ myapp:latest /bin/myapp --config=/etc/your.conf 54

Slide 55

Slide 55 text

コンテナアプリケーションを安全に動かす ▌最新のDockerを利用する ▌docker.socketファイルの扱いに注意 ⚫ docker.socketへのアクセスは root 権限に等しい ▌rootユーザーやprivilegedで実行しない ⚫ --cap-drop=allを指定して、 必要なcapabilityを個別に指定する ▌ホストへのアクセスは最小限に ▌秘密情報をコンテナイメージに含めない ▌コンテナイメージの脆弱性チェック ⚫ Quay.ioの脆弱性チェック機能 → 55

Slide 56

Slide 56 text

サンプル ▌training-docker/03_application/bestpractice ⚫ アプリケーションログとアクセスログをSTDERRに出す ⚫ SIGTERMを受けるとGraceful Shutdownする ⚫ ヘルスチェック用のAPIを持つ ⚫ ポート番号を環境変数で設定可能 56

Slide 57

Slide 57 text

演習 57

Slide 58

Slide 58 text

演習課題 ▌任意のアプリケーションをDockerで動かしてみてください ⚫ 例: 開運研修「Webアプリケーション基礎」で作成した Webアプリなど。 ⚫ コンテナのベースイメージは quay.io/cybozu/ubuntu:18.04 を利用してください。 ⚫ 本研修で紹介したプラクティスを取り入れてみてください。 58

Slide 59

Slide 59 text

おまけ (時間があれば) 59

Slide 60

Slide 60 text

いろいろなコンテナランタイム ▌Docker以外にもいろいろなコンテナ技術がある。 ▌gVisor, kata-container, Nabla containerなどなど。 ⚫ コンテナとVMの境目が曖昧になってきている ▌コンテナ関連の仕様はOCI(Open Container Initiative)で標準 化されているので、これまでのコンテナイメージも同じように 使える。 60

Slide 61

Slide 61 text

BuildKit ▌次世代のコンテナイメージビルドツール ▌実験的な機能なのでまだ動作が不安定 ▌ビルドのスピードが大幅向上 61

Slide 62

Slide 62 text

体系立てられたDockerコマンド ▌dockerコマンドが複雑になりすぎたので再編成 ⚫ docker container ⚫ docker ps -> docker container ls ⚫ docker run -> docker container run ⚫ docker image ⚫ docker images -> docker image ls ⚫ docker rmi -> docker image rm ⚫ docker build -> docker image build ▌でも短い方が便利なので使い続けてしまう・・・ 62

Slide 63

Slide 63 text

複数種類のログを出力したい ▌ひとつのアプリケーションで、エラーログ、監査ログ、アクセ スログなど複数のログを出したい場合がある。 ▌アプリケーションではログをファイルに出力する。 ▌ログの出力先はvolumeにする。 ▌volumeのファイルを読み取り、その内容を標準出力に出すコ ンテナをログの種類分だけ用意する。 ▌サイドカーコンテナパターンと呼ばれたりする。 63

Slide 64

Slide 64 text

Container Deep Dive ▌nsenterコマンドを使ってコンテナのnamespaceに入ってみ よう。 ▌コンテナイメージをばらして、レイヤー構造の様子を見てみよ う。 ▌iptabelsやip route, brctlコマンドを使って、コンテナネット ワークの実現方法を見てみよう。 64

Slide 65

Slide 65 text

参考情報 ▌ Docker: Up & Running, 2nd Edition ▌ 分散システムデザインパターン ▌ Software Design 2019年6月号 「IT業界ビギナーのためのDocker+k8s入門講座」 ▌ Dockerfileを改善するためのBest Practice 2019年版 ▌ Dockerfileを書くためのベストプラクティス解説編 ▌ Base Image Journey 2018 ▌ Best practices for building containers ▌ Best Practices for Operating Containers ▌ The Twelve-Factor App ▌ コンテナ技術入門 - 仮想化との違いを知り、要素技術を触って学ぼう 65