$30 off During Our Annual Pro Sale. View Details »

Docker入門2024

Cybozu
July 26, 2024
490

 Docker入門2024

Cybozu

July 26, 2024
Tweet

Transcript

  1. マイPCにWordPressを起動してみよう︕ 6 git clone https://github.com/docker/awesome-compose cd awesome-compose/wordpress-mysql #ポート番号を変更 code compose.yaml

    # WordPressを起動 docker compose up -d • GitHub から git clone して、compose.yamlを編集して、WordPressを起動できる。 • このような Docker の機能は、開発環境をチームへ配布したり、開発の成果物をコンテ ナで共有するなど、いろいろな作業に適⽤可能。 起動までの⼿順 (Mac, Windows, Linux共通)
  2. WordPressを起動するための compose.yaml 7 MySQL(MariaDB)のコンテナ をDocker Hubからプルして 起動 データ領域と認証情報をコン テナへ与える Composeファイルのリファレンス

    https://docs.docker.com/compose/reference/ WordPressのWeb 公開ポート番号は 8080へ変更する。 WordPressのコンテナを Docker Hubからプルして起動 接続先のMySQLのホスト名、 認証情報、Webサーバーの ポート番号をコンテナへ設定
  3. 第⼀部 まとめ (コンテナの利⽤価値) ▌どうしてIT業界とサイボウズはコンテナに注⽬するのか︖ l OSS中⼼の開発スタイルに必要 (OSSの進化対応) l 継続的なアップデート (CICDの実践)

    l 安⼼と安全な⾼セキュリティなITサービス (脆弱性対応) ▌コンテナを利⽤することで、どのように進化するのか︖ l マイクロサービスアーキテクチャの推進 l 他社よりも早く、あらゆるニーズに答える、柔軟なサービス提供 14
  4. Dockerの主な構成要素 ▌ Dockerクライアント l docker run/build/push などで、コマンドでDockerエンジンとユーザーを繋ぐUI ▌ Dockerエンジン(デーモン) l

    イメージ、コンテナ、ネットワーク、ボリュームなどDocker オブジェクトを管理 ▌ レジストリ l イメージが格納され共有に利⽤、パブリックと組織内プライベートがある ▌ イメージ l コンテナを作成するための⼿順を含む、読み取り専⽤のテンプレート ▌ コンテナ l イメージの実⾏可能なインスタンス 16 出典: https://docs.docker.com/get-started/overview/
  5. コンテナの実⾏プロセスを体験しよう 17 Virtual Machine Linux Bin/libs Apps Docker Engine docker

    run hello-world Bin/libs Apps https://hub.docker.com/_/hello-world/ コマンド実⾏ イメージを ダウンロード Docker Hub 公式リポジトリ hello-world ① ② ③ ④メッセージ表⽰ macOS / Windows11 イメージ コンテナを⽣成して プロセスを実⾏
  6. よく使うDockerのサブコマンド ▌ run : コンテナの実⾏ ▌ stop : コンテナの停⽌ ▌

    rm : コンテナの削除 ▌ ps : コンテナの確認 ▌ inspect : コンテナの詳細情報の取得 ▌ exec : コンテナ上でコマンドの実⾏ ▌ logs : コンテナのログを確認 ▌ build : コンテナイメージのビルド ▌ images : コンテナイメージの確認 ▌ rmi : コンテナイメージの削除 ▌ container prune : 停⽌コンテナの削除 ▌ image prune : 未使⽤イメージの削除 詳しくは docker <COMMAND> --help 19
  7. Webサーバーのコンテナの起動 21 # コンテナの起動 # -d: バックグラウンドで起動 # --name: コンテナに名前をつける(省略した場合は⾃動で名前がつく)

    # -p 8080:80: コンテナの80番ポートをホストの8080番ポートにバインド docker run -d --name mynginx -p 8080:80 nginx # 起動しているコンテナの確認 # コンテナの停⽌・削除 docker ps docker stop mynginx curl http://localhost:8080 docker rm mynginx docker logs mynginx
  8. コンテナに⼊ってみる (コンテナ内のシェルと対話する) 22 # ubuntu-debugコンテナ上でbashを実⾏する # -i: STDINをオープンし続ける -t: 擬似端末を割り当てる

    # --rm: コンテナ終了時にコンテナを⾃動削除 docker run -it --rm quay.io/cybozu/ubuntu-debug:22.04 /bin/bash # いろんなコマンドを叩いて、コンテナ内のプロセスやファイルシステム、 # ネットワークの状態などを確認してみる ls hostname ip a ps aux
  9. ホストとのファイル共有 23 # ホスト上で適当なHTMLファイルを作成 mkdir html touch . /html/index.html pwd

    # 絶対パスを取得 # ホストのhtmlをコンテナの/usr/share/nginx/htmlにバインド docker run -d --name mynginx -p 8080:80 ¥ -v <絶対パス>/html:/usr/share/nginx/html ¥ nginx:latest curl localhost:8080
  10. コンテナのクリーンナップ(後⽚付け) ▌ docker ps -a で実⾏中と終了したコンテナをリスト ▌ 不要になったコンテナは docker rm

    、または docker container prune で削除 24 $ docker ps –a # 終了コンテナも含めた全コンテナをリスト CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES dd5c68f55488 nginx:latest “/docker-entrypoint.…” About a minute ago Up About a minute mynginx 5dacebd03bfa hello-world "/hello" 6 minutes ago Exited (0) 6 minutes ago jolly_hypatia $ docker stop mynginx # コンテナ停⽌ mynginx $ docker rm mynginx # コンテナ削除 mynginx $ docker container prune # 不要コンテナの削除 WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y Deleted Containers: dd5c68f55488aabbf69bf6c3cccdd7bf8341b311104c6137a478c54cb10ec6a6 5dacebd03bfaec641e0ac229ac39ea70a9bd5f5794da64b3dd5e50d80e1ca233 Total reclaimed space: 1.093kB
  11. コンテナのクリーンナップ(後⽚付け つづき) ▌ コンテナとイメージを削除しても、ボリュームとビルドキャッシュが残って、領域が⼀ 杯になると dockerコマンドが動かなくなる。その時は以下の要領で整理する。 25 $ docker system

    df # Dockerデーモンが使っているストレージ量を表⽰ TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 5 1 1.254GB 1.254GB (99%) Containers 1 0 0B 0B Local Volumes 2 0 191.4MB 191.4MB (100%) Build Cache 12 0 132B 132B $ docker system prune –a # 不要なデータを削除 WARNING! This will remove: - all stopped containers - all networks not used by at least one container - all images without at least one container associated to them - all build cache <以下省略> # 不要ボリュームの削除 $ docker volume ls $ docker volume prune $ docker volume rm wordpress-mysql_db_data
  12. コンテナのライフサイクルとコマンドの関係 26 コンテナ イメージ ローカルリポジトリ 実⾏状態 docker run docker commit

    コンテナ 停止状態 docker kill docker stop コンテナ 終了/強制停⽌ docker start (テンプレート) (実⾏中) (停⽌中) コンテナ削除 docker rm イメージ削除 docker rmi docker ps 実⾏中コンテナリスト docker ps -a 停⽌状態を含むコンテナ イメージ レジストリサービス docker pull docker run docker images イメージリスト表⽰ (テンプレート) docker push docker logs ログ表⽰ Docker Hub、quay.io、ghcr.io プライベートレジストリ コンテナ実⾏
  13. text ▌Dockerfileを元にコンテナのイメージができる コンテナを開発に利⽤するイメージ 27 OSライブラリ SWパッケージ アプリケーション (実⾏形式) Dockerエンジン Linux

    OS アプリ・コンテナ Dockerfile コンテナ レジストリ (ベースイメージ取得) ビルド アプリケーション ソースコード イメージ ローカル リポジトリ GitHub OSS リポジトリ docker build docker run アプリケーションの動作に必要なソフトウェア を揃えて、コンテナにパッケージする
  14. シンプルなDockerfileの例 28 FROM ubuntu:xenial-20190222 RUN apt update && apt install

    figlet ADD ./message /message CMD cat /message | figlet Hello World ファイル名 Dockerfile.simple ファイル名 message (注意)このDockerfile.simpleは、真似してはいけない例です。 なぜ︖真似を勧めないのかこれから⾒ていきます。 FROM ベースイメージを指定(付け加える⼟台となるOS) RUN コンテナ上でコマンドを実⾏して、アプリやパッケージを追加 (figletコマンドを追加) ADD ファイルやディレクトリをコピー(ファイル messageをコンテナへコピー) CMD コンテナの起動時に実⾏するコマンド (messageファイルをfigletの標準⼊⼒へインプット) 各命令( FROM,RUN,ADD/COPY,CMD)は、レイヤーを作成する。 参考: Docker公式ドキュメント Dockerfile reference
  15. コンテナのビルドと実⾏ 29 材料となるファイル ビルドの実⾏ イメージの確認 コンテナの実⾏ $ ls Dockerfile.simple message

    $ docker build -t test:1 . -f Dockerfile.simple [+] Building 15.1s (8/8) FINISHED => [internal] load .dockerignore => => transferring context: 2B <中略> => exporting to image => => exporting layers => => writing image sha256:6e1121ad0bf42c17e53c21227e2f20e95086 => => naming to docker.io/library/test:1 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE test 1 6e1121ad0bf4 7 seconds ago 150MB $ docker run test:1 _ _ _ _ __ __ _ _ | | | | ___| | | ___ ¥ ¥ / /__ _ __| | __| | | |_| |/ _ ¥ | |/ _ ¥ ¥ ¥ /¥ / / _ ¥| '__| |/ _` | | _ | __/ | | (_) | ¥ V V / (_) | | | | (_| | |_| |_|¥___|_|_|¥___/ ¥_/¥_/ ¥___/|_| |_|¥__,_|
  16. コンテナイメージの履歴を確認 ▌ 「docker history」は、RUN,COPY等でUnionFSに追加されたレイヤーの履歴を表⽰ ▌ イメージに使われるUnionFSは、複数のファイルシステム のファイルやディレクトリを透過的に 重ねることができる技術。これにより複数のレイヤーで、単⼀のファイルシステムを形成する。 ▌ 同⼀ファイル名やディレクトリ名は、後から追加されたレイヤーが優先される。

    30 $ docker history test:1 IMAGE CREATED CREATED BY SIZE 6e1121ad0bf4 21 minutes ago CMD ["/bin/sh" "-c" "cat /message | figlet"] 0B <missing> 21 minutes ago ADD ./message /message # buildkit 12B <missing> 21 minutes ago RUN /bin/sh -c apt update && apt install fig… 32.4MB <missing> 4 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 4 years ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B <missing> 4 years ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B <missing> 4 years ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B <missing> 4 years ago /bin/sh -c #(nop) ADD file:c02de920036d851cc… 118MB FROMの ベースイメージ Dockerfileで 追加した層 コマンド「docker history」は、 イメージサイズが⼤きくなった時に、 原因を調べるのに便利じゃ
  17. 正しいDockerfileを書くために ▌Dockerfileなどの「ベストプラクティス」を熟読 ▌忙しいから出来ないと感じる⼈はリントを使うと良い l Lintまたはlinter は、プログラミング エラー、バグ、スタイル エラー、疑わしい構造を判別す る静的コード分析ツール ▌Hadolint

    の実⾏例 https://github.com/hadolint/hadolint 32 $ docker run --rm -i hadolint/hadolint < Dockerfile.simple -:2 DL3027 warning: Do not use apt as it is meant to be a end-user tool, use apt-get or apt-cache instead -:3 DL3020 error: Use COPY instead of ADD for files and folders -:4 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT arguments Hadolintは「Dockerfile 作成のベスト プラクティス」のルールを適⽤してレポートする PS C:¥Users¥takara¥temp¥docker101¥lesson-3> cat .¥Dockerfile.simple | docker run --rm -i hadolint/hadolint Windowsの場合
  18. Dockerfileの改善例 (Hadolintで指摘された) ▌ 出来る限り信頼できる最新のベースを選択 ▌ 使⽤するベースイメージ、パッケージは、バージョンを明記する ▌ RUNでは apt-getを使い、不要なモジュールをインストールしない、マメにキャッシュを消す ▌

    COPY を使⽤する。単機能で透明性の⾼いため、⼀⽅ADDはエラー扱い ▌ CMDでは、シェル形式ではなく、JSON表記を⽤いる 33 FROM ubuntu:22.04 RUN apt-get update && apt-get install --no-install-recommends -y figlet=2.2.5-3 ¥ && apt-get clean ¥ && rm -rf /var/lib/apt/lists/* COPY ./message /message CMD ["cat","/message", "|", "figlet"] 最新latestではなくタグでバージョンを指定 apt-getの使⽤が推奨 依存関係だけをインストール ADDを使わない JSON表記にする バージョンを指定 ⾮対話型 キャッシュと 作業ファイル を消す
  19. 改善したDockerfileで再ビルド 34 $ docker build -t test:2 -f Dockerfile .

    [+] Building 1.3s (9/9) FINISHED => [internal] load .dockerignore => => transferring context: 2B => [internal] load build definition from Dockerfile => => transferring dockerfile: 254B => [internal] load metadata for docker.io/library/ubuntu:22.04 => [auth] library/ubuntu:pull token for registry-1.docker.io => [1/3] FROM docker.io/library/ubuntu:22.04@sha256:dfd64a3b4296d8c9b62aa3309 984f8620b98d87e47492599ee20739e8eb54fbf => [internal] load build context => => transferring context: 28B => CACHED [2/3] RUN apt-get update && apt-get install --no-install-recommends -y figlet=2.2.5-3 && apt-get clean && rm -rf /var/lib/apt/lists/* => CACHED [3/3] COPY ./message /message => exporting to image => => exporting layers => => writing image sha256:aa78b505a57cf265ab3ccd99e4ab6f144e9fef20866bcbb644 e6a6c17b83576d => => naming to docker.io/library/test:2
  20. ベストプラクティスに従って作成したイメージの例 これによって、イメージのサイズを抑えることに加えて、コード量を減らすことで脆弱性が含まれる 可能性(攻撃の表⾯積︓attack surface)を減らすことができる。 35 $ docker images REPOSITORY TAG

    IMAGE ID CREATED SIZE test 2 568b4400e3f7 3 hours ago 79.4MB test 1 6e1121ad0bf4 4 hours ago 150MB $ docker history test:2 IMAGE CREATED CREATED BY SIZE 568b4400e3f7 3 seconds ago CMD ["cat" "/message" "|" "figlet"] 0B <missing> 3 seconds ago COPY ./message /message # buildkit 12B <missing> 3 seconds ago RUN /bin/sh -c apt-get update && apt-get ins… 1.56MB <missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 7 weeks ago /bin/sh -c #(nop) ADD file:c8ef6447752cab254… 77.8MB <missing> 7 weeks ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B <missing> 7 weeks ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B <missing> 7 weeks ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B <missing> 7 weeks ago /bin/sh -c #(nop) ARG RELEASE 0B 32.4 → 1.56へ減少 118 → 77.8へ減少 改善後のtest:2では 半分近くまで減少
  21. Aqua Trivyよる脆弱性検査結果 改善前の検査結果は重要度 Mediumが複数存在,画⾯に表⽰できないほど多くの脆弱性を検知、 改善後ではMediumレベルは無く、LowやNegligibleも減少した。 36 改善前 test:1 改善後 test:2

    Anchore grypeコンテナの実⾏⽅法 検査結果 Total: 79 ,LOW: 40, MEDIUM: 39 検査 Total: 15 , LOW: 15 # trivy 脆弱性スキャンをコンテナで実⾏する⽅法 docker run -v /var/run/docker.sock:/var/run/docker.sock ¥ --rm aquasec/trivy image --no-progress <イメージ>:<タグ>
  22. 脆弱性検査ツールの紹介 ▌docker scan l Docker組込みのSnykの脆弱性スキャナ 無料プランで10回/⽉まで利⽤可能 l https://matsuand.github.io/docs.docker.jp.onthefly/engine/scan/ ▌Aqua Trivy

    l 脆弱性と設定ミスのスキャナー OSSプロジェクト l https://www.aquasec.com/products/trivy/ 他にも⾊々な脆弱性検査のサービスやOSSがあるので、探してみてください。 38 参考資料 Qiita コンテナ・セキュリティ⼊⾨ 脆弱性
  23. text ▌レジストリサービスのリポジトリにpushすることで、他開発者と共有 開発したコンテナを共有する 40 OSライブラリ SWパッケージ アプリケーション (実⾏形式) Dockerエンジン Linux

    OS アプリ・コンテナ Dockerfile コンテナ レジストリ ビルド アプリケーション ソースコード イメージ ローカル リポジトリ GitHub OSS リポジトリ docker build アプリケーションの動作に必要なソフトウェア を揃えて、コンテナにパッケージする docker push
  24. レジストリ登録⼿順 ▌ ログイン (docker login) l レジストリにログインする。⼀度ログインしておけばログアウトするまで維持される l Neco開発⽤レジストリはログインしなくても利⽤可能(外部と切り離された環境のため) ▌

    タグ付け (docker tag) l ローカルのイメージ名にレジストリでの別名を付与 l ユーザー名は予めレジストリに登録しておく、Neco開発⽤レジストリでは事前登録不要 ▌ プッシュ (docker push) l レジストリでの別名を指定して実⾏ 41 docker login レジストリ:ポート番号 docker tag イメージ名[:タグ] レジストリ/ユーザー名/リポジトリ名[:タグ] docker push レジストリ/ユーザー名/リポジトリ名[:タグ]
  25. イメージをレジストリに登録する実⾏例 42 登録イメージはココ *1 Neco 開発⽤プライベートレジストリ $ docker images REPOSITORY

    TAG IMAGE ID CREATED SIZE test 2 aa78b505a57c 21 minutes ago 79.4MB test 1 d7a4d820c31c 21 minutes ago 150MB # タグ付け (参考URL*1) $ docker tag test:2 registry-local.registry.stage0.cybozu-ne.co/takara/test:2 # レジストリへのプッシュ $ docker push registry-local.registry.stage0.cybozu-ne.co/takara/test:2 The push refers to repository [registry-local.registry.stage0.cybozu-ne.co/takara/test] adc8b1715e64: Layer already exists d66f12a09500: Pushed b8a36d10656a: Pushed 2: digest: sha256:660a9a34b90a26fb8f576083ac81e09bf44514c8b4e40a810f3f430301cea179 size: 946 # 登録の確認 (参考URL*2) $ curl -s https://registry-local.registry.stage0.cybozu-ne.co/v2/takara/test/tags/list {"name":"takara/test","tags":["2"]} *2 HTTP API V2 Docker Registry HTTP API V2 参考URL この部分は ⾃⾝の名前で置き 換えてください
  26. 公式ドキュメントに書かれたベストプラクティス ▌Docker 開発のベスト プラクティス • https://docs.docker.com/develop/dev-best-practices/ ▌Dockerfile を作成するためのベスト プラクティス •

    https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ • https://docs.docker.jp/develop/develop-images/dockerfile_best-practices.html ▌セキュリティのベスト プラクティス • https://docs.docker.com/develop/security-best-practices/ 46 ⼀次情報は難しいけど 確信がある技術知識 になるのじゃ
  27. 「Docker 開発のベスト プラクティス」の要約 イメージが⼩さいほど、ネットワーク経由でのプルが⾼速になり、脆弱性にも有利、コ ンテナの開始時に起動が⾼速になる。 ▌ イメージを⼩さく保つための⽅法 l 「適切なベースイメージ」を選択、「マルチステージビルド」を使⽤ l

    共通点が多いイメージは、「ベースイメージを共通化」する。共通的COPY/RUNは前の⽅へ l 「タグを活⽤」する (バージョン,⽬的,安定性など、世代や派⽣関係などを意味づけ) ▌ データの永続化 l コンテナにアプリの「データを保存しない」 l 「構成ファイル」や「機密情報」をコンテナに「保存しない」 ▌ テストとデプロイにCI/CDを使⽤ l ソースへの変更やプル リクエストを作成したりする時は「CI/CDパイプライン」を使⽤ 47
  28. 「Dockerfile を作成するためのベスト プラクティス」の要約 Dockerは、Dockerfileから、順番にコマンドを読んで、イメージを⾃動でビルドする。そこに記述 されたFROM, COPY/ADD, RUN, CMDによって、イメージに読み取り専⽤レイヤーが追加される。 ▌ 「コンテナは⼀時的な存在」であり、変更が必要な時は廃棄して再ビルド

    ▌ ワークロード特性でコンテナを分離する。原則「1アプリ/1コンテナ」 ▌ 保守が容易な Dockerfile の作成するために「適切なコマンドを利⽤」する ▌ 「マルチステージビルド」、「不要なパッケージを⼊れない」、「レイヤー数を最⼩に する」は前⾴と共通 48
  29. Dockerへ影響を与えている資料紹介 ▌The Twelve-factor App l SaaS Herokuの開発運⽤者の実践から得たメソドロジー(⽅法論) l Kubernetesなど多くのドキュメントからも参照 l

    Docker関連のベストプラクティスも、⼤きな影響を受けている ▌Brendan Burns, David Oppenheimerらの論⽂「Design patterns for container-based distributed systems」の要約 l Kubernetesの開発メンバーが書いた論⽂、Brendanは後にMicrosoft DEに就任 l Kubernetesのコンテナの実⾏単位 Podの有⽤性を説く l 単機能のコンテナを複数組み合わせる設計パターンを紹介 50
  30. ベストプラクティスから「マルチステージビルド」を紹介 ▌ これにより、苦労なく⼤幅に中間レイヤーとファイルを削減できる l ビルド⽤コンテナとランタイム⽤コンテナを分割 l ビルドした実⾏形式をランタイム⽤コンテナへコピー 51 # Stage1:

    ビルド⽤コンテナ FROM quay.io/cybozu/golang:1.20.3.1_jammy AS build COPY main.go /work/main.go WORKDIR /work RUN CGO_ENABLED=0 go build -o server ./main.go # アプリをビルド # Stage2: ランタイム⽤コンテナ FROM scratch COPY --from=build /work/server /server # 実⾏形式をstage1からコピー EXPOSE 8000 ENTRYPOINT ["/server"]
  31. マルチステージビルドと普通のビルド⽐較 ▌ マルチステージとシングルステージのDockerfileで、出来たイメージのサイズを⽐較 ▌ Dockerfile.multiは、ビルド⽤コンテナとランタイム⽤コンテナの2つのステージを利⽤ ▌ Dockerfile.singleは、ビルドしたコンテナを実⾏⽤にも利⽤ 52 # Stage1:

    ビルド⽤コンテナ FROM quay.io/cybozu/golang:1.20.3.1_jammy AS build COPY main.go /work/main.go WORKDIR /work RUN CGO_ENABLED=0 go build -o server ./main.go # Stage2: ランタイム⽤コンテナ FROM scratch COPY --from=build /work/server /server EXPOSE 8000 ENTRYPOINT ["/server"] # シングルステージ FROM quay.io/cybozu/golang:1.20.3.1_jammy COPY main.go /app/main.go WORKDIR /app RUN CGO_ENABLED=0 go build -o /app/server main.go EXPOSE 8000 ENTRYPOINT ["/app/server"] Dockerfile.multi (再掲) Dockerfile.single
  32. マルチステージビルドの効果の確認2(サイズ) ▌ マルチステージとシングルステージのDockerfileで、出来たイメージのサイズを⽐較 ▌ マルチステージで出来たイメージ(test:3)は「6.62MB」、シングルステージでビルドした イメージ(test:4)は「1.04GB」の歴然の差が出る。 53 $ docker build

    –t test:3 –f Dockerfile.multi . <中略> $ docker images test:3 REPOSITORY TAG IMAGE ID CREATED SIZE test 3 70b0fcb4564d 8 hours ago 6.62MB $ docker build -t test:4 -f Dockerfile.single . <中略> $ docker images test:4 REPOSITORY TAG IMAGE ID CREATED SIZE test 4 1f915f98d2e1 25 minutes ago 1.04GB
  33. マルチステージビルドの効果の確認3(レイヤー) ▌ マルチステージ(test:3)とシングルステージ(test:4)で出来たイメージのレイヤー数を⽐較 ▌ test:3は3レイヤー、test:4は29レイヤーとなり、劇的な削減となっていることが判る。 54 $ docker history test:3

    IMAGE CREATED CREATED BY SIZE COMMENT 70b0fcb4564d 9 hours ago ENTRYPOINT ["/server"] 0B buildkit.dockerfile.v0 <missing> 9 hours ago EXPOSE map[8000/tcp:{}] 0B buildkit.dockerfile.v0 <missing> 9 hours ago COPY /work/server /server # buildkit 6.62MB buildkit.dockerfile.v0 $ docker history test:4 IMAGE CREATED CREATED BY SIZE 1f915f98d2e1 About an hour ago ENTRYPOINT ["/app/server"] 0B <missing> About an hour ago EXPOSE map[8000/tcp:{}] 0B <missing> About an hour ago RUN /bin/sh -c CGO_ENABLED=0 go build -o /ap… 67.6MB <missing> About an hour ago WORKDIR /app 0B <missing> About an hour ago COPY main.go /app/main.go # buildkit 271B <missing> 4 weeks ago CMD ["/bin/bash"] 0B <missing> 4 weeks ago RUN |2 TARGETARCH=amd64 GO_VERSION=1.20.3 /b… 0B <missing> 4 weeks ago WORKDIR /work 0B <missing> 4 weeks ago RUN |2 TARGETARCH=amd64 GO_VERSION=1.20.3 /b… 57.3MB <以下省略> 注意) quay.io/cybozu/golang:1.20.3.1_jammyは実⾏⽤に作られたイメージではない。
  34. マルチステージビルドの効果の確認4(脆弱性) ▌ マルチステージとシングルステージで出来たイメージをtrivyで脆弱性を⽐較 ▌ マルチステージ(test:3)では脆弱性が検知されない。シングルステージ(test:4)では多数を検知 55 $ docker run -v

    /var/run/docker.sock:/var/run/docker.sock --rm aquasec/trivy image --no-progress test:3 2023-05-08T11:54:43.402Z INFO Need to update DB <中略> 2023-05-08T11:54:47.999Z INFO Number of language-specific files: 0 # 脆弱性の検知なし $ docker run -v /var/run/docker.sock:/var/run/docker.sock --rm aquasec/trivy image --no-progress test:4 2023-05-08T11:51:50.003Z INFO Need to update DB <中略> 2023-05-08T11:52:04.867Z INFO Detecting Ubuntu vulnerabilities... 2023-05-08T11:52:04.870Z INFO Number of language-specific files: 17 2023-05-08T11:52:04.870Z INFO Detecting gobinary vulnerabilities... 2023-05-08T11:52:04.875Z INFO Detecting gomod vulnerabilities... 2023-05-08T11:52:04.879Z INFO Detecting node-pkg vulnerabilities... test:4 (ubuntu 22.04) ===================== Total: 186 (UNKNOWN: 0, LOW: 116, MEDIUM: 67, HIGH: 3, CRITICAL: 0) <以下省略>
  35. text コンテナの停⽌コマンドとシグナル 57 コンテナ SIGTERM SIGKILL コンテナ内部 のプロセス 上位API 下位API

    Docker デーモン docker stop docker kill 終了要求 強制終了 SIGTERMを受信後、 DBアクセスがある場合など データを書き込み後に終了 SIGKILLは、実⾏中のプログラムを強 制停⽌する。そのため、終了処理す る猶予を与えない 正常終了 強制終了 Kubernetesで kubectl delete pod を実⾏した 場合、SIGTERMが送られるが、⼀定時間内 に停⽌しない場合は、SIGKILLで強制終了と なる。 終了処理が必要なコンテナの場合、 必ずSIGTERMの受信処理が必要となる。
  36. text ▌ラッパースクリプトを利⽤する場合、execで起動する ▌execを⼊れないケースと⼊れたケースで⽐較 コンテナ内のプロセスが確実にシグナルを受信するために 58 $ cat wrapper.sh /a.out $

    cat wrapper.sh exec /a.out $ docker exec a5fd91768450 ps -ax PID TTY STAT TIME COMMAND 1 pts/0 Ss+ 0:00 /bin/sh /wrapper.sh 7 pts/0 S+ 0:00 /a.out $ docker exec 056030d1d2e9 ps -ax PID TTY STAT TIME COMMAND 1 pts/0 Ss+ 0:00 /a.out ラッパーシェルに直接コマンドを書いたケース execを⼊れた書いたケース コンテナをビルド&起動後に、プロセスを確認 この場合、シグナルを受けるのはシェル a.out はPID = 1となりシグナルを受信できる
  37. text ▌コンテナをKubernetesで運⽤する時、全てが必要ではありませんが、考慮があれば問題を回避できます。 ▌詳細は以降の各ページの参考URLで確認してください。 K8sで実⾏するコンテナが装備するべき I/F 概要 60 ポッド (コンテナ) SIGTERM

    SIGKILL 環境変数 標準出⼒ コンテナ ログ コンテナ起動 ログ 終了要求 強制終了 永続 データ 標準エラー出⼒ 引数 コンテナ終了 サービス ポート番号 ヘルスチェック 準備チェック 稼働チェック フック 開始イベント 終了イベント 設定 ファイル 終了ステータス 終了コード 成功 = 0 失敗 ゼロ以外 メモリ CPU時間 ネットワーク他I/O メトリックス 起動チェック ボリューム
  38. K8sで実⾏するコンテナが装備するべきI/F 「ヘルスチェック」 ▌Kubernetes には3つのヘルスチェックがある l Liveness Probe デッドロック状態を検知してコンテナを再スタート l Readiness

    Probe コンテナが要求トラフィックを受け⼊れられる状態を検知 l Startup Probe コンテナアプリケーションの起動が完了したかを認識 ▌コンテナは、必要に応じて、これらのプローブに対応する機能を実装 ▌Kubernetes Docsの参考URL l Liveness Probe、Readiness ProbeおよびStartup Probeを使⽤する l Podのライフサイクル 62
  39. K8sで実⾏するコンテナが装備するべきI/F 「コンテナ終了」 ▌Kubernetes でもコンテナの終了要求はシグナルで伝えられる l SIGTERM 終了要求としてコンテナランタイムは各コンテナのメインプロセスに TERMシグナルを送信、猶予時間として30秒が与えられる l SIGKILL

    猶予時間を超過した時はSIGKILLで強制終了 ▌コンテナはSIGTERMを受けて、必要な処理を終えてEXITしなければなら ない。 ▌Kubernetes Docsの参考URL l Podのライフサイクル Podの終了 63
  40. K8sで実⾏するコンテナが装備するべきI/F 「フック」 ▌Kubernetesはコンテナに「ライフサイクルフック」を提供、対応するラ イフサイクルフックが実⾏されたときにハンドラに実装されたコードを 実⾏ l PostStart フックはコンテナが作成された直後に実⾏ l PreStop

    管理イベントが原因でコンテナが終了する直前に呼び出される ▌コンテナは必要に応じて、フックのハンドラを実装 ▌Kubernetes Docsの参考URL l コンテナライフサイクルフック 65
  41. K8sで実⾏するコンテナが装備するべきI/F 「終了ステータス」 ▌終了コードの種類 l Exit Code = 0 : Kubernetesでは正常終了

    l Exit Code = 1 : アプリの異常終了 l 問題判別に役⽴つExit Codeは参考URLを参照 ▌コンテナ上のアプリは終了コードを管理しなければならない ▌参考URL l Kubernetes Pod In CrashLoopBackOff State l Understanding Docker Container Exit Codes 67
  42. K8sで実⾏するコンテナが装備するべきI/F 「メトリックス」 ▌ Kubernetesではクラスタ全体のCPU、メモリ、ファイルシステムなどの使⽤率 をPrometheusで管理 ▌ コンテナのアプリケーションで、資源の消費状況を監視したい場合は、 GrafanaとPrometheusを利⽤ ▌ ポッドのコンテナがメモリ使⽤制限容量より多く使⽤した場合、強制停⽌とな

    り、ステータスにOOMKilled(終了コード137)が記録 ▌ コンテナの資源使⽤量はGrafanaで⾒れるが、メモリ消費量はアプリで管理し なければ、OOMKilled が発⽣することもある ▌ 参考URL l リソースメトリクスパイプライン l コンテナおよびPodへのメモリーリソースの割り当て 69
  43. サイボウズ社内のドキュメント ▌ コンテナイメージの管理 https://github.com/cybozu-private/neco-users-wiki/blob/main/ja/howto_container_image.md ▌ コンテナイメージ運⽤ポリシー https://github.com/cybozu-private/neco-wiki/blob/main/docs/policy_container_image.md ▌ コンテナイメージの管理⽅法 https://github.com/cybozu-private/neco-

    wiki/blob/main/docs/procedure_container_management.md ▌ Containerd Clients https://github.com/cybozu-private/neco-wiki/blob/main/docs/tutorial_containerd_clients.md ▌ Dockerfile Howto https://github.com/cybozu-private/neco-wiki/blob/main/docs/dockerfile.md ▌ Docker Guide http://wiki.dev.cybozu.co.jp/display/DEV/Docker%20Guide 72
  44. 参考情報1 ▌ 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 ▌ コンテナ技術⼊⾨ - 仮想化との違いを知り、要素技術を触って学ぼう 73
  45. 参考資料 2 (過去に⾼良が書いたQiitaの関連記事) ▌設計関連 l Kubernetes導⼊にあたり知っておきたいコンテナの基礎知識(要約) l コンテナ・デザイン・パターンの論⽂要約 l 12FactorをKubernetesのアプリ開発へ適⽤するコメント

    ▌セキュリティ関連 l コンテナ・セキュリティ⼊⾨ 脆弱性 l コンテナ・セキュリティ⼊⾨ と Kubernetes l コンテナ開発のセキュリティとOpenShift特有のガイド 74
  46. コンテナの開発環境 DockerとPodman ▌コンテナを開発するためのソフトウェア 76 Docker社が開発した。3つの機能がある。 ・イメージのビルド(⽣成) ・イメージからの展開とコンテナとして実⾏ ・イメージの共有 他のファミリー製品 compose

    / swarmなどがある。 Red Hat社が買収したCoreOS社が開発 ・Dockerコマンド互換 ・デーモンレス、Dockerではバックエンドの常駐プロセス Dockerd が実⾏を担うが、podmanでは常駐プロセス不要 ・他にファミリー製品 buildahなどがある。
  47. コンテナランタイム (実⾏環境) ▌Kubernetesでコンテナを実⾏するために使⽤されるもの 78 Docker社が開発、Dockerd から分離されCNCFへ寄贈さ れた。多くのクラウドのKubernetesサービスで利⽤され、 デファクト・スタンダードになっている。 Red Hat、IBM、Intel、SUSEが、Kubernetes⽤のコンテ

    ナランタイムとして開発したが、その後CNCFへ寄贈され た。Red Hat社のOpenShiftで利⽤される。 OCIが開発するLinuxコンテナを⽣成するコマンド。OCI には⼤⼿IT企業が出資しており、ContainerdやCRI-Oに よって実⾏される。 ノードのOS コンテナ ランタイム コンテナ オーケストレーター Kubernetes
  48. コンテナランタイムの内部構造 ▌ポッドとコンテナは、最終的にruncコマンド実⾏ 79 Kubelet コンテナ マネージャー コンテナ ランタイム kube-apiserver kubectl

    Container Pod shims CRI OCI準拠 containerd, CRI-O, Dockerd Linuxコンテナでは runc が⼀般的、 Windows コンテナは runhcs.exeとなる。 また、Kataの場合はkata-runtime。 Container Registry Service イメージのプル 上位コンテナ ランタイム 下位コンテナ ランタイム OCI準拠 (常駐プロセス) (コマンド) Kubernetes では containerd-shim OpenShift では ConMan
  49. 業界標準 CRIとOCI 80 CRI OCI CRI (Container Runtime Interface)は、kubelet がさまざまな

    コンテナー ランタイムを使⽤できるようにするプラグイン イン ターフェイスです。通信プロコトルとしてgRPCが使われています。 https://kubernetes.io/docs/concepts/architecture/cri/ https://opencontainers.org/ CCI (Open Container Initiative)は、コンテナのフォーマットなど の業界標準を作成するために設⽴された。この業界標準には、ラン タイム仕様 (runtime-spec)、イメージ仕様 (image-spec)、ディ ストリビューション仕様 (distribution-spec) の 3 つの仕様が含ま れています。
  50. runc は、Linux機能を活⽤するコマンド ▌ 「runc」はOCI仕様 に従って開発されたリファレンス実装 ▌ 以下の表は「runc」がコンテナを実現する3⼤Linux技術 81 機能名 概

    要 UnionFS (オーバーレイファイルシステム) 複数の断⽚的なピースを重ねて⼀つのファイルシステムとして利⽤できるため、オー バーレイファイルシステムとも呼ばれる。コンテナのベースイメージにファイルを重ね て追加する機能は、UnionFSの改良型のOverlay2が推奨されている。 コンテナを更新する場合には、この技術によって差分だけを転送すれば良く、ネット ワークの帯域節約と、コンテナ起動の⾼速化に寄与している。runcはOverlay2などに よって展開されたrootファイルシステムでコンテナを⽣成する。 Linux Namespaces (Linux名前空間) カーネルの名前空間に割り当てられたプロセスは、他の名前空間のプロセスから隔離 される。名前空間には次に挙げる8つのタイプがある。 マウント(mnt)、プロセスID(pid)、ネットワーク(net)、プロセス間通信(ipc)、ドメ インとホスト名(UTS)、ユーザーID(user)、コントロールグループ(cgroup)、時間 (Time)。 これらを組み合わせて、プロセスを他のプロセス群から隔離することで、コンテナを 実現している。コンテナのホストとなるLinuxの/procのファイルにプロセスIDごとに 属する名前空間の情報が集約される。 Linux cgroups (コントロールグループ) コントロールグループ(cgroups)は、Linuxカーネルの機能で、リソースの使⽤制限、 CPU、メモリ、ディスクI/O、ネットワークなどの資源の隔離、使⽤制限、使⽤量計測 を実施する。 この機能により、コンテナのメモリやCPUの使⽤量上限を設定できる。⼀つのLinux OSに複数のコンテナを稼働させ、共存影響を抑えることができる。
  51. 内部構造 Containerd ▌ Docker社からCNCFへ寄贈されたContainerdは様々なモジュールを差し替え可能な構造 82 containerd-shim Runtime runc Google Cloud

    Platform docker IBM Cloud Microsoft Azure Alibaba Cloud AWS Cloud Foundry Rancher CRI Runtime containerd client Kubelet Docker Engine containerd client BuildKit containerd client ctr containerd client CRI API GRPC API Service containerd API Metrics API Core Backend Containerd クライアント runhcs kata Firecracker gVisor v2 shim client Windows / Linux オペレーティングシステム コンテナ プラットフォーム Containerd サーバー gRPC OCI準拠 コンテナ⽣成 コマンド Services Metadata Content Store Snapshotter overlay btrfs Container Registry Service イメージのDL イメージをOS上に展開 コンテナとして 隔離プロセスを実⾏ コンテナの実⾏要求