Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Docker入門

Avatar for Cybozu Cybozu
July 06, 2025
14

 Docker入門

Avatar for Cybozu

Cybozu

July 06, 2025
Tweet

Transcript

  1. 自己紹介 ▌高良 真穂 (たから まほ) ⚫ 前職を定年退職して、 2023年4月サイボウズに入社 ▌所属 クラウド基盤本部

    Necoインフラチーム ⚫ Neco基盤の運用や開発業務に従事 ▌趣味 ⚫ 犬と散歩、薔薇を育てること、ドライブ他いろいろ 4 著書 韓国語翻訳版
  2. マイPCにWordPressを起動してみよう! 7 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共通) docker101¥lesson-1に変更後のファイルがあります。
  3. WordPressを起動するための compose.yaml 8 MySQL(MariaDB)のコンテナ をDocker Hubからプルして 起動 データ領域と認証情報をコン テナへ与える Composeファイルのリファレンス

    https://docs.docker.com/compose/reference/ WordPressのWeb 公開ポート番号は 8080へ変更する。 WordPressのコンテナを Docker Hubからプルして起動 接続先のMySQLのホスト名、 認証情報、Webサーバーの ポート番号をコンテナへ設定
  4. コンテナの実行プロセスを体験しよう 17 Virtual Machineなど Linux Bin/libs Apps Docker Engine docker

    run hello-world Bin/libs Apps https://hub.docker.com/_/hello-world/ コンテナ実行のコマンド イメージを ダウンロード hello-worldリポジトリ ① ② ③ ④メッセージ表示 macOS / Windows11 イメージ イメージを展開 コンテナを起動 Docker Hubレジストリ 〇〇リポジトリ
  5. Dockerの主な構成要素 ▌ Dockerクライアント ⚫ docker run/build/push などで、コマンドでDockerエンジンとユーザーを繋ぐUI ▌ Dockerエンジン(デーモン) ⚫

    イメージ、コンテナ、ネットワーク、ボリュームなどDocker オブジェクトを管理 ▌ レジストリ ⚫ 内部に複数のリポジトリが存在、各リポジトリはタグで区別されたイメージが格納 ▌ イメージ ⚫ コンテナを作成するための手順を含む、読み取り専用のテンプレート ▌ コンテナ ⚫ イメージを展開して、実行可能になったオブジェクト 18 出典: https://docs.docker.com/get-started/overview/
  6. よく使うDockerのサブコマンド ▌ run : コンテナの実行 ▌ stop : コンテナの停止 ▌

    rm : コンテナの削除 ▌ ps : コンテナの確認 ▌ inspect : コンテナの詳細情報の取得 ▌ exec : コンテナ上でコマンドの実行 ▌ logs : コンテナのログを確認 ▌ build : コンテナイメージのビルド ▌ images : コンテナイメージの確認 ▌ rmi : コンテナイメージの削除 ▌ container prune : 停止コンテナの削除 ▌ image prune : 未使用イメージの削除 docker helpでコマンドがわかります 20
  7. Webサーバーのコンテナの起動 22 # コンテナの起動 # -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. コンテナに入ってみる (コンテナ内のシェルと対話する) 23 # ubuntu-debugコンテナ上でbashを実行する # -i: STDINをオープンし続ける -t: 擬似端末を割り当てる

    # --rm: コンテナ終了時にコンテナを自動削除 docker run -it --rm ghcr.io/cybozu/ubuntu-debug:24.04.20250425 /bin/bash # いろんなコマンドを叩いて、コンテナ内のプロセスやファイルシステム、 # ネットワークの状態などを確認してみる ls hostname ip a ps aux
  9. ホスト(PC)とのファイル共有 24 # ホスト上で適当なHTMLファイルを作成 mkdir html code 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 # PCのブラウザからNginxをアクセス http://localhost:8080/ docker101¥lesson-2 にファイルがあります。 コンテナを起動した後は、後片付けを忘れないように
  10. コンテナのクリーンナップ(後片付け) ▌ docker ps -a で実行中と終了したコンテナをリスト ▌ 不要になったコンテナは docker rm

    、または docker container prune で削除 25 $ 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コマンドが動かなくなる。その時は以下の要領で整理する。 26 $ 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. コンテナのライフサイクルとコマンドの関係 27 コンテナ イメージ ローカルリポジトリ 実行状態 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. コンテナの基本コマンド まとめ ▌Docker コマンド ⚫ docker [OPTIONS] COMMAND の形式 ⚫

    docker コマンドに困ったら docker help ▌コンテナとイメージの違い ⚫ コンテナは、他から隔離されたプロセスの一種 ⚫ イメージは、コンテナを生成するためのオブジェクト ▌レジストリとリポジトリ ⚫ レジストリは、Docker HubなどURLで区別されるサイト ⚫ リポジトリは、タグで区別されるイメージの保管場所 28
  14. text ▌Dockerfileを元にコンテナのイメージができる コンテナを開発に利用するイメージ 30 OSライブラリ SWパッケージ アプリケーション (実行形式) Dockerエンジン Linux

    OS アプリ・コンテナ Dockerfile コンテナ レジストリ (ベースイメージ取得) ビルド アプリケーション ソースコード or 実行形式 イメージ ローカル リポジトリ GitHub OSS リポジトリ docker build docker run アプリケーションの動作に必要なソフトウェア を揃えて、コンテナにパッケージする
  15. シンプルなDockerfileの例 31 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 docker101¥lesson-3 にファイルがあります。
  16. コンテナのビルドと実行 32 材料となるファイル ビルドの実行 イメージの確認 コンテナの実行 $ 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 / (_) | | | | (_| | |_| |_|¥___|_|_|¥___/ ¥_/¥_/ ¥___/|_| |_|¥__,_|
  17. コンテナイメージの履歴を確認 ▌ 「docker history」は、RUN,COPY等でUnionFSに追加されたレイヤの履歴を表示 ▌ イメージに使われるUnionFSは、複数のファイルシステム のファイルやディレクトリを透過的に 重ねることができる技術。これにより複数のレイヤで、単一のファイルシステムを形成する。 ▌ 同一ファイル名やディレクトリ名は、後から追加されたレイヤが優先される。

    33 $ 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」は、 イメージサイズが大きくなった時に、 原因を調べるのに便利じゃ
  18. 正しいDockerfileを書く必要性 ▌ 転送量を削減するためにイメージにはUnionFSを採用 ⚫ イメージは、複数のレイヤで構成 ⚫ 必要なレイヤのみを転送することで時間の節約 ▌ 大きなコンテナイメージの問題 ⚫

    ストレージ容量、ネットワーク帯域の無駄な消費 ⚫ ビルドやコンテナ起動の時間が長くなる ⚫ 攻撃を受ける表面積(attack surface)が増える ▌ UnionFSで作られたイメージサイズを適正に保つには ⚫ イメージは複数のレイヤが重なって構成 ⚫ レイヤは上書きのみ削除されない(CR-Rと同じ) ⚫ 使われないレイヤで肥大化しないように、保守ではなく作り直し 34
  19. 正しいDockerfileを書くために ▌Dockerfileなどの「ベストプラクティス」を熟読 ▌忙しいから出来ないと感じる人はリントを使うと良い ⚫ Lintまたはlinter は、プログラミング エラー、バグ、スタイル エラー、疑わしい構造を判別す る静的コード分析ツール ▌Hadolint

    の実行例 https://github.com/hadolint/hadolint 35 $ 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の場合
  20. Dockerfileの改善例 (Hadolintで指摘された) ▌ 出来る限り信頼できる最新のベースを選択 ▌ 使用するベースイメージ、パッケージは、バージョンを明記する ▌ RUNでは apt-getを使い、不要なモジュールをインストールしない、マメにキャッシュを消す ▌

    COPY を使用する。単機能で透明性の高いため、一方ADDはエラー扱い ▌ CMDでは、シェル形式ではなく、JSON表記を用いる 36 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表記にする バージョンを指定 非対話型 キャッシュと 作業ファイル を消す
  21. 改善したDockerfileで再ビルド 37 $ 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
  22. ベストプラクティスに従って作成したイメージの例 これによって、イメージのサイズを抑えることに加えて、コード量を減らすことで脆弱性が含まれる 可能性(攻撃の表面積:attack surface)を減らすことができる。 38 $ 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では 半分近くまで減少
  23. Aqua Trivyよる脆弱性検査結果 改善前の検査結果は重要度 Mediumが複数存在,画面に表示できないほど多くの脆弱性を検知、 改善後ではMediumレベルは無く、LowやNegligibleも減少した。 39 改善前 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 <イメージ>:<タグ> # Windowsでは docker run -v /var/run/docker.sock:/var/run/docker.sock --rm aquasec/trivy image --no-progress <イメージ>:<タグ>
  24. 脆弱性検査ツールの紹介 ▌docker scan ⚫ Docker組込みのSnykの脆弱性スキャナ 無料プランで10回/月まで利用可能 ⚫ https://matsuand.github.io/docs.docker.jp.onthefly/engine/scan/ ▌Aqua Trivy

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

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

    タグ付け (docker tag) ⚫ ローカルのイメージ名にレジストリでの別名を付与 ⚫ ユーザー名は予めレジストリに登録しておく、Neco開発用レジストリでは事前登録不要 ▌ プッシュ (docker push) ⚫ レジストリでの別名を指定して実行 45 docker login レジストリ:ポート番号 docker tag イメージ名[:タグ] レジストリ/ユーザー名/リポジトリ名[:タグ] docker push レジストリ/ユーザー名/リポジトリ名[:タグ]
  27. イメージをレジストリに登録する実行例 46 登録イメージはココ *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 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 この部分は 自身の名前で置き 換えてください docker101¥lesson-4 にファイルがあります。
  28. 公式ドキュメントに書かれたベストプラクティス ▌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/ 49 一次情報は難しいけど 確信がある技術知識 になるのじゃ
  29. 「Docker 開発のベスト プラクティス」の要約 イメージが小さいほど、ネットワーク経由でのプルが高速になり、脆弱性にも有利、コ ンテナの開始時に起動が高速になる。 ▌ イメージを小さく保つための方法 ⚫ 「適切なベースイメージ」を選択、「マルチステージビルド」を使用 ⚫

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

    ▌ ワークロード特性でコンテナを分離する。原則「1アプリ/1コンテナ」 ▌ 保守が容易な Dockerfile の作成するために「適切なコマンドを利用」する ▌ 「マルチステージビルド」、「不要なパッケージを入れない」、「レイヤ数を最小にす る」は前頁と共通 51
  31. ベストプラクティスから「マルチステージビルド」を紹介 ▌ これにより、苦労なく大幅に中間レイヤとファイルを削減できる ⚫ ビルド用コンテナとランタイム用コンテナを分割 ⚫ ビルドした実行形式をランタイム用コンテナへコピー 53 # Stage1:

    実行形式のビルド FROM ghcr.io/cybozu/golang:1.22.12.2_noble 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"] docker101¥lesson-5 にファイルがあります。
  32. マルチステージビルドと普通のビルド比較 ▌ マルチステージとシングルステージのDockerfileで、出来たイメージのサイズを比較 ▌ Dockerfile.multiは、ビルド用コンテナとランタイム用コンテナの2つのステージを利用 ▌ Dockerfile.singleは、ビルドしたコンテナを実行用にも利用 54 # Stage1:

    ビルド用コンテナ FROM ghcr.io/cybozu/golang:1.22.12.2_noble 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 ghcr.io/cybozu/golang:1.22.12.2_noble 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
  33. マルチステージビルドの効果の確認2(サイズ) ▌ マルチステージとシングルステージのDockerfileで、出来たイメージのサイズを比較 ▌ マルチステージで出来たイメージ(test:3)は「6.62MB」、シングルステージでビルドした イメージ(test:4)は「1.04GB」の歴然の差が出る。 55 $ 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
  34. マルチステージビルドの効果の確認3(レイヤ) ▌ マルチステージ(test:3)とシングルステージ(test:4)で出来たイメージのレイヤ数を比較 ▌ test:3は3レイヤ、test:4は29レイヤとなり、劇的な削減となっていることが判る。 56 $ 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は実行用に作られたイメージではない。
  35. マルチステージビルドの効果の確認4(脆弱性) ▌ マルチステージとシングルステージで出来たイメージをtrivyで脆弱性を比較 ▌ マルチステージ(test:3)では脆弱性が検知されない。シングルステージ(test:4)では多数を検知 57 $ 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) <以下省略>
  36. Dockerへ影響を与えている資料紹介 ▌The Twelve-factor App ⚫ SaaS Herokuの開発運用者の実践から得たメソドロジー(方法論) ⚫ Kubernetesなど多くのドキュメントからも参照 ⚫

    Docker関連のベストプラクティスも、大きな影響を受けている ▌Brendan Burns, David Oppenheimerらの論文「Design patterns for container-based distributed systems」の要約 ⚫ Kubernetesの開発メンバーが書いた論文、Brendanは後にMicrosoft DEに就任 ⚫ Kubernetesのコンテナの実行単位 Podの有用性を説く ⚫ 単機能のコンテナを複数組み合わせる設計パターンを紹介 60
  37. text コンテナの停止コマンドとシグナル 61 コンテナ SIGTERM SIGKILL コンテナ内部 のプロセス 上位API 下位API

    Docker デーモン docker stop docker kill 終了要求 強制終了 SIGTERMを受信後、 DBアクセスがある場合など データを書き込み後に終了 SIGKILLは、実行中のプログラムを強 制停止する。そのため、終了処理す る猶予を与えない 正常終了 強制終了 Kubernetesで kubectl delete pod を実行した 場合、SIGTERMが送られるが、一定時間内 に停止しない場合は、SIGKILLで強制終了と なる。 終了処理が必要なコンテナの場合、 必ずSIGTERMの受信処理が必要となる。
  38. text 補足 Linux シグナルとは 62 我のお告げに 従うのじゃ! プロセスさん プロセスの神 シグナルを受け取ったプロセスは

    “何らかの動作”を行う必要がある。 しかし、何もしなければ受け取れな いシグナルも多数ある。 終了要求 「SIGTERM」は、プログ ラムの中で「受け取った時の処理 (シグナルハンドラ)」を宣言しな ければならない。 一方「SIGKILL」を受け取ったプロ セスは強制終了を拒否できない。 参 考 1 ) Ubuntu Manual, signal – シ グ ナ ル の 概 要 2 ) シ ェ ル ス ク リ プ ト で シ グ ナ ル ハ ン ド ラ を 書 く 3 ) PHP pcntl_signal — シ グ ナ ル ハ ン ド ラ を 設 定 す る 参考 1)Ubuntu Manual, signal – シグナルの概要 2)シェルスクリプトでシグナルハンドラを書く 3)PHP pcntl_signal — シグナルハンドラを設定する 突然の 御告げだ
  39. text ▌ラッパースクリプトを利用する場合、execで起動する ▌execを入れないケースと入れたケースで比較 コンテナ内のプロセスが確実にシグナルを受信するために 63 $ 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となりシグナルを受信できる
  40. text ▌コンテナをKubernetesで運用する時、全てが必要ではありませんが、考慮があれば問題を回避できます。 ▌詳細は以降の各ページの参考URLで確認してください。 K8sで実行するコンテナが考慮するべきI/F概要 65 ポッド (コンテナ) SIGTERM SIGKILL 環境変数

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

    コンテナが要求トラフィックを受け入れられる状態を検知 ⚫ Startup Probe コンテナアプリケーションの起動が完了したかを認識 ▌コンテナは、必要に応じて、これらのプローブに対応する機能を実装 ▌Kubernetes Docsの参考URL ⚫ Liveness Probe、Readiness ProbeおよびStartup Probeを使用する ⚫ Podのライフサイクル 67
  42. 考慮するべきI/F「終了コード」 ▌終了コードの種類 ⚫ Exit Code = 0 : Kubernetesでは正常終了 ⚫

    Exit Code = 1 : アプリの異常終了 ⚫ 問題判別に役立つExit Codeは参考URLを参照 ▌コンテナ上のアプリは終了コードを管理しなければならない ▌参考URL ⚫ Kubernetes Pod In CrashLoopBackOff State ⚫ Understanding Docker Container Exit Codes 72
  43. 参考情報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 ▌ コンテナ技術入門 - 仮想化との違いを知り、要素技術を触って学ぼう 77
  44. 参考資料 2 (過去に高良が書いたQiitaの関連記事) ▌設計関連 ⚫ Kubernetes導入にあたり知っておきたいコンテナの基礎知識(要約) ⚫ コンテナ・デザイン・パターンの論文要約 ⚫ 12FactorをKubernetesのアプリ開発へ適用するコメント

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

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

    ナランタイムとして開発したが、その後CNCFへ寄贈され た。Red Hat社のOpenShiftで利用される。 OCIが開発するLinuxコンテナを生成するコマンド。OCI には大手IT企業が出資しており、ContainerdやCRI-Oに よって実行される。 ノードのOS コンテナ ランタイム コンテナ オーケストレーター Kubernetes
  47. コンテナランタイムの内部構造 ▌ポッドとコンテナは、最終的にruncコマンド実行 83 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
  48. 業界標準 CRIとOCI 84 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 つの仕様が含ま れています。
  49. runc は、Linux機能を活用するコマンド ▌ 「runc」はOCI仕様 に従って開発されたリファレンス実装 ▌ 以下の表は「runc」がコンテナを実現する3大Linux技術 85 機能名 概

    要 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に複数のコンテナを稼働させ、共存影響を抑えることができる。
  50. 内部構造 Containerd ▌ Docker社からCNCFへ寄贈されたContainerdは様々なモジュールを差し替え可能な構造 86 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上に展開 コンテナとして 隔離プロセスを実行 コンテナの実行要求