- 第4回スコープ・学習目標・今ここマップ
- Docker Registry v2 とは何か — OCI Distribution Spec
- レジストリアーキテクチャ(k8s-registry VM + registry:2 コンテナ)
- HTTP vs HTTPS の選択 + Insecure Registry 設定
- イメージタグ戦略 — latest の罠とセマンティックバージョニング
- docker tag / docker push / docker pull の仕組み
- Trivy v0.70.0 の概要とインストール
- Trivy スキャンの実行と結果の読み方
- やってみよう ① k8s-registry に registry:2 コンテナを起動
- やってみよう ② fanclub-backend を 0.2.0 にタグ付け → push → pull 確認
- やってみよう ③ Trivy スキャン(HIGH/CRITICAL のみ表示・JSON 出力)
- 現場ヒヤリハット
- 今回のまとめ + 理解度チェック
- シリーズ一覧
第4回スコープ・学習目標・今ここマップ
動作確認バージョン: Docker CE 29.4.3 / containerd 2.2.3 / runc 1.3.5 / Docker Registry registry:2(v2.8.x)/ Trivy v0.70.0 / AlmaLinux 10.1(kernel 6.12.0-124.55.3.el10_1)/ k8s-ops + k8s-registry 2 VM 連携(2026-05-09 時点・k8s-ops + k8s-registry 実機検証済・SP_vol1-pre-05 + SP_registry-clean 起点)
本回は Kubernetes 実践教科書 第1巻(CKAD 対応・全 19 回)の第4回です。第1部「コンテナと Docker」全 4 回の最終回として、自分でビルドしたイメージを「外」に出す ステップを扱います。
Docker Registry(registry:2)の構築、イメージタグ戦略(latest の罠とセマンティックバージョニング・Git ハッシュ・ダイジェスト)、docker tag / docker push / docker pull の仕組み、Trivy v0.70.0 でのコンテナイメージ脆弱性スキャンまでを通して扱います。
CKAD D1(Application Design and Build・配点 20 %)の Competency 1.1「Define, build and modify container images」のうち 「modify container images」 の核心に直結する回です。
第3回からの継承状態確認(SP_vol1-pre-05 + SP_registry-clean 状態・第3回完走スナップショット + k8s-registry 事前準備済みを起点として演習を開始):
- k8s-ops(192.168.1.122・AlmaLinux 10.1)に Docker CE 29.4.3 と
fanclub-backend:0.1.0イメージが残存している - k8s-ops の
/etc/docker/daemon.jsonは未作成(第4回でinsecure-registries設定を新規作成する) - k8s-registry(192.168.1.123)に Docker CE 29.4.3 が導入済みで、
registry:2イメージは pull 済み(コンテナは未起動) - k8s-registry の alma-proxy 経由通信設定(
/etc/systemd/system/docker.service.d/proxy.conf)は事前準備済み - k8s-ops に Trivy は 未インストール(第4回で GitHub Releases から RPM を直接インストールする)
k8s-registry 側の Docker CE インストール手順自体は第1回の k8s-ops インストール手順と同一のため、本記事では再掲せずに「導入済み」前提で進めます。第4回のテーマである レジストリ運用・タグ戦略・脆弱性スキャン に紙面を集中させる構成です。
今ここマップ(第1巻 19 回中の現在位置):
第1部 コンテナとDocker
第1回: コンテナ技術概念 + Docker環境準備 [完了]
第2回: Docker基本操作 [完了]
第3回: Dockerfile + マルチステージビルド + JDK 25/Payara Micro [完了]
★ 第4回: コンテナレジストリ + イメージタグ戦略 + Trivy スキャン ← 今ここ(第1部最終回)
第2部 Kubernetes基礎(第5〜6回)
第3部 アプリリソース(第7〜11回)
第4部 ワークロード戦略(第12〜14回)
第5部 セキュリティ基礎(第15〜16回)
第6部 パッケージ管理 + HTTPS公開(第17〜19回)
第4回を終えると、以下を習得した状態になります。
- Docker Registry(registry:2)を Volume マウント付きで構築し、HTTP(insecure registry)経由でイメージを push / pull できる
/etc/docker/daemon.jsonのinsecure-registries設定の意味と適用範囲(k8s-ops 側のみ必要・k8s-registry 側は不要)を説明できる- イメージタグ戦略(
latestの罠・SemVer・Git ハッシュ・イメージダイジェスト)を説明し、本番運用でlatestを避ける理由を述べられる docker tagが新イメージを作らず参照名を追加するだけであること(CKAD 頻出論点)を確認できる- Trivy v0.70.0 で
fanclub-backend:0.2.0の脆弱性をスキャンし、HIGH / CRITICAL のみフィルタしたうえで JSON 形式で保存できる
模擬アプリ進捗(第4回終了時点):
第3回: [Backend(Java)] ← Dockerfile を書いた(v0.1.0) [完了]
第4回: [Backend → k8s-registry] ← レジストリに push した(v0.2.0) ← 今ここ
第7回: [Backend(Pod)] ← K8s に初めて載せる(v0.2.0 を使用)
Docker Registry v2 とは何か — OCI Distribution Spec
コンテナイメージの保管・配信を担うコンポーネントを レジストリ(Registry) と呼びます。Docker Hub は代表的なパブリックレジストリで、第2回で nginx:1.27-alpine や hello-world を pull した接続先です。
企業内では外部への依存を減らし、ネットワーク帯域を節約し、アクセス制御を行うために プライベートレジストリ を自前で構築します。本シリーズの k8s-registry VM がその役割を担います。
OCI Distribution Specification:
- OCI(Open Container Initiative)が策定した、レジストリ HTTP API の業界標準仕様
- Docker Registry HTTP API V2 プロトコルをベースに OCI が標準化した
registry:2はこの仕様の参照実装で、CNCF Distribution プロジェクトとして開発されている- Docker Hub・AWS ECR・GitHub Container Registry(ghcr.io)・Harbor もすべてこの仕様に準拠している
主要レジストリの位置づけ:
| レジストリ | 用途 | 特徴 |
|---|---|---|
| Docker Hub | パブリック共有・学習 | 無料枠あり・pull レート制限あり |
registry:2 | 軽量プライベートレジストリ | シンプル・認証なしも可・本シリーズ採用 |
| Harbor | 本番向けプライベートレジストリ | スキャン統合・RBAC・UI・複数サービス構成で重い |
| AWS ECR / GCR / ghcr.io | クラウド / CI / CD 用 | イミュータブルタグ対応・有料 |
本シリーズで registry:2 を採用する理由は、k8s-registry VM(2 vCPU / 4 GB / 50 GB)で軽量に動作し、設定がシンプルで、第4回の学習目的(push / pull の基本・タグ戦略・スキャン)に集中できるためです。
Harbor は OCI 準拠の本番向けレジストリでスキャン統合・RBAC・レプリケーション・UI を内蔵しますが、PostgreSQL / Redis / Core / Jobservice など複数サービスを含む複雑なセットアップが必要で、第1部のスコープを超えます。
商用 / 本番向けレジストリは概念紹介にとどめ、本記事では registry:2 の HTTP 構成で push / pull / スキャンを完走します。
なお Docker Registry の最新版は v3.1.1 系で、Docker Hub には registry:3 タグも存在しますが、本シリーズは registry:2(v2 系最終版 v2.8.3)を採用します。第4回の学習目的に対して機能差は影響しません。
レジストリアーキテクチャ(k8s-registry VM + registry:2 コンテナ)
第4回の検証環境の全体像を整理します。2 つの VM(k8s-ops と k8s-registry)が External Switch(192.168.1.0/24)で接続される構成 で、k8s-ops 側がイメージビルド + push / pull の主体、k8s-registry 側が registry:2 コンテナを稼働させる側に分離されています。

各コンポーネントの役割:
| コンポーネント | 稼働 VM | 役割 |
|---|---|---|
| Docker CE | k8s-registry | registry:2 コンテナを稼働させる基盤 |
registry:2 コンテナ | k8s-registry | OCI Distribution Spec 準拠でイメージを保存・配信する |
Volume /var/lib/registry | k8s-registry のホスト側永続 Volume → コンテナにマウント | イメージレイヤーとメタデータを保存(コンテナ削除でデータが消えない設計) |
| Docker CE + insecure-registries 設定 | k8s-ops | k8s-registry への HTTP push / pull を許可 |
| fanclub-backend:0.2.0 タグ | k8s-ops(push 元)→ k8s-registry(保存先) | 第3回で作成した Backend イメージをレジストリ URL 付きでタグ付けして push |
insecure-registries 設定は k8s-ops 側のみ必要です。k8s-registry 自身は registry:2 コンテナを稼働させるだけで、自分自身の registry に対して push / pull を行う場面がないためです。
registry-1.docker.io など外部レジストリへの接続(registry:2 イメージの pull 等)は alma-proxy 経由で完結しており、proxy 設定(/etc/systemd/system/docker.service.d/proxy.conf)は事前準備済みです。
両方の VM に insecure-registries を設定する手順は本シリーズでは採用しません(k8s-registry 側の設定は不要)。
第7回以降では、kind クラスタ内の Workload Node(containerd ランタイム)も同じ k8s-registry を pull 元として使用します。
kind ノードの containerd は Docker デーモンとは別プロセス・別設定ファイルで動作するため、kind 起動時に containerdConfigPatches で insecure registry を設定する手順を第5回で扱います(後述 H2-12 ヒヤリハット事例 1 参照)。
HTTP vs HTTPS の選択 + Insecure Registry 設定
本シリーズの第4回では、TLS を使用しない HTTP(insecure registry)構成 を採用します。設計判断の理由は以下の通りです。
- TLS 証明書管理(自己署名・Let’s Encrypt・cert-manager)は第18回 Gateway API + cert-manager で本格的に扱う
- 内部ネットワーク(192.168.1.0/24)に閉じた検証環境では HTTP で動作確認を優先する
- 第4回のテーマ(push / pull・タグ戦略・脆弱性スキャン)に学習を集中させる
- 「HTTPS が当たり前の本番では絶対に行わない構成」を新卒読者が体験することで、第18回の TLS 必要性の理解が深まる教育的対比になる
本番環境では HTTPS 必須です。本構成は開発・学習用に限定し、第18回以降は cert-manager 経由の TLS を扱います。
/etc/docker/daemon.json の設定(k8s-ops のみ):
{
"insecure-registries": ["192.168.1.123:5000"]
}
変更後は sudo systemctl restart docker が必要です。SP_vol1-pre-05 時点で /etc/docker/daemon.json は未作成のため、後述 H2-9 ステップ 5 では sudo tee で 新規作成 する形で設定します(既存 JSON への追記ではなく、ファイルそのものを新規作成)。
Docker の insecure registry 通信動作:
- まず HTTPS(TLS)接続を試みる
- HTTPS が利用できるが証明書が無効 → 証明書エラーを無視して接続する
- HTTPS が利用できない → HTTP にフォールバックする
本シリーズの構成(registry:2 は HTTP のみ起動)では 3 番目の HTTP フォールバックが適用されます。insecure-registries リストに含まれていないアドレスに対しては、Docker は HTTPS が成立しなければ接続を拒否します。これが「insecure-registries を明示的に列挙する」設計になっている理由です。
本セクションでは設定の意味を確認しました。実際にコマンドを実行して反映する手順は H2-9(やってみよう ①)ステップ 5 で扱います。
イメージタグ戦略 — latest の罠とセマンティックバージョニング
第4回の最重要テーマです。CKAD D1 Competency 1.1 の「modify container images」の核心であり、現場で最も頻繁に観察されるアンチパターンである latest タグ を正面から扱います。

latest タグの問題(アンチパターン)
docker pull nginx:latest で取得されるイメージは、いつ実行しても同じとは限りません。latest タグは ミュータブル(可変) であり、push 権限を持つ誰かが docker push nginx:latest で上書きするたびに中身が変わります。
| 問題点 | 内容 |
|---|---|
| 再現不可能 | 同じ latest タグでも時期によって異なるイメージが取得される |
| 変更検知困難 | レジストリ側で更新されても pull する側は気づかない |
| ロールバック不可 | 「先週の latest」が何だったか記録が残らない |
| K8s での事故 | imagePullPolicy: Always 設定下で kubectl rollout restart しただけで意図せずバージョンアップが発生する |
| CKAD 試験での扱い | 試験問題では通常、バージョンタグ付きイメージを使用する。latest の問題点を理解しているかを問う設問が出題対象 |
本番環境で latest タグを使うと、Pod が再起動した際に意図せず新しいイメージが pull されてしまい、コードを変更していないのに動作が変わるという障害が発生します(後述 H2-12 ヒヤリハット事例 2 で詳述)。
K8s imagePullPolicy のデフォルト動作(CKAD 頻出論点):
image: nginx:latest(:latestタグ指定)→imagePullPolicy省略時のデフォルトはAlways(毎回 pull)image: nginx:1.27.5(バージョンタグ指定)→imagePullPolicy省略時のデフォルトはIfNotPresent(ローカルキャッシュ優先)image: nginx(タグ省略・:latestと等価)→ デフォルトはAlways
つまり :latest 指定は「毎回 pull する」自動挙動とセットになっており、これがヒヤリハット事例 2 で扱う「Pod 再作成時に意図せずバージョンアップ」現象の温床となります。
逆に :0.2.0 のような明示的バージョンタグなら IfNotPresent が効き、Node 上に既に pull 済のイメージが再利用されます(ただし Node が違う場合は新規 pull が必要)。CKAD 試験ではこのデフォルト挙動の対比が単独設問で出題対象です。
セマンティックバージョニング(SemVer)
MAJOR.MINOR.PATCH 形式(例: 0.1.0, 0.2.0, 1.0.0, 1.2.0)でバージョンを管理します。
| 番号 | 意味 | 変化の例 |
|---|---|---|
| MAJOR(先頭) | 後方互換性のない変更 | REST API のパスを変更・レスポンス形式を変更 |
| MINOR(中央) | 後方互換性のある機能追加 | 新しいエンドポイントを追加 |
| PATCH(末尾) | バグ修正・セキュリティ修正 | CVE 対応・ログ出力修正 |
本シリーズでの fanclub-backend のバージョン遷移(app-spec.md §8 より)は以下の通りです。
第3回: fanclub-backend:0.1.0 ← Dockerfile を書いた(k8s-ops ローカルのみ)
第4回: fanclub-backend:0.2.0 ← k8s-registry に push した(今ここ)
第10回: fanclub-backend:0.4.0 ← ConfigMap/Secret で設定外部化
第12回: fanclub-backend:0.5.0 ← Deployment 化 + 3 Probe
第17回: fanclub-backend:1.1.0 ← Helm chart 化
第18回: fanclub-backend:1.2.0 ← HTTPS 公開(第1巻完走時点の最終形)
Git ハッシュタグ
CI / CD パイプラインでは fanclub-backend:abc1234(Git コミットの短縮ハッシュ)形式も利用されます。ビルドされたイメージとソースコードのコミットを 1 対 1 で対応付けられるため、完全なトレーサビリティ が確保できます。
実際には MAJOR.MINOR.PATCH-HASH 形式(例: 0.2.0-abc1234)で SemVer と Git ハッシュを組み合わせる運用も広く行われます。本シリーズでは新卒学習者の認知負荷を抑えるため SemVer のみで進めますが、業務 CI / CD では Git ハッシュ併記が現場標準です。
イメージダイジェスト(sha256)
docker images --digests で各イメージのダイジェスト(256 ビットの SHA-256 ハッシュ)を確認できます。ダイジェストはイメージの内容が変わると必ず変わる 不変な識別子 で、タグとは異なりレジストリ側で書き換えられることはありません。
# ダイジェスト単独(タグなし)
image: 192.168.1.123:5000/fanclub-backend@sha256:3bdcfa296cf6...
# タグ + ダイジェスト併記(読みやすさと不変性を両立・推奨)
image: 192.168.1.123:5000/fanclub-backend:0.2.0@sha256:3bdcfa296cf6...
K8s の Deployment マニフェストで image:tag@sha256:... 形式を指定すると、タグが上書きされても pull されるイメージは固定されます。本番運用ではダイジェスト固定が推奨されます(第15回 RBAC + SecurityContext + Admission Controller 概念 + CRD 利用 SecurityContext 章で再登場)。
第3巻 CKS では Cosign によるイメージ署名検証と組み合わせ、ダイジェスト固定 + 署名検証で「想定したイメージ以外は絶対に動かさない」運用を確立しますが、本シリーズではリンクは張りません(第3巻未公開・404 防止)。
ミュータブルタグ vs イミュータブルタグ
| 種別 | 説明 | 代表例 |
|---|---|---|
| ミュータブルタグ | 同一タグ名で push し直すことで上書き可能 | latest / Docker Registry(registry:2)デフォルト |
| イミュータブルタグ | レジストリ側の機能で同一タグの上書きを禁止 | AWS ECR / Harbor / GitHub Container Registry の設定で有効化 |
registry:2 はデフォルトでイミュータブル機能を持ちません(同じタグで再 push すると上書きされる)。本番運用では Harbor などイミュータブルタグをサポートするレジストリを選択するか、運用ルールで「タグの再利用を禁止する」習慣を徹底します。
本シリーズでは 0.2.0 → 0.4.0 → 0.5.0 … と毎回新しいバージョン番号を採番することで、ミュータブルタグの問題を実質的に回避しています。
Cosign / SBOM の予告
イメージの「内容を保証する」仕組みとして、Cosign(sigstore プロジェクト)によるイメージ署名と、bom による SBOM(Software Bill of Materials)生成があります。
Cosign はイメージのシグネチャを OCI レジストリの隣に .sig タグとして格納し、pull 時に cosign verify で署名を検証します。これらは第3巻 CKS 編で本格実装します(言及のみ・<a> リンクは張らない)。
docker tag / docker push / docker pull の仕組み
タグ付け → push → pull の一連の操作の「中で何が起きているか」を整理します。docker tag が新イメージを作らない 点は CKAD で頻出の論点です。
docker tag の本質
docker tag は 新しいイメージを作成しません。既存イメージのレイヤー群に別の参照名を追加するだけで、実際のレイヤーデータは共有されます。docker images で fanclub-backend:0.1.0 と 192.168.1.123:5000/fanclub-backend:0.2.0 の両方を表示すると Image ID が同一 になることでこの動作を確認できます。
fanclub-backend:0.1.0 ──┐
├── 同じレイヤー群(Image ID 同一)
192.168.1.123:5000/fanclub-backend:0.2.0 ──┘ ← 新しい参照名が追加されただけ
コマンド構文:
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
レジストリ URL を含めた完全修飾形式は <host>:<port>/<repository>:<tag> です。
docker push の動作
docker push はイメージの各レイヤーを順番にアップロードします。レジストリに既存のレイヤーは 「Layer already exists」 として表示され、再アップロードはスキップされます。これはネットワーク帯域とレジストリのストレージ消費を抑える仕組みで、ベースイメージが共通の複数イメージを push する際に効果が大きくなります。
docker pull の動作
同様に、ローカルに既存のレイヤーは 「Already exists」 として表示され、ダウンロードはスキップされます。docker rmi でイメージのタグ参照を削除しても、別のタグから参照されているレイヤーはディスク上に残ります。
K8s との接続(布石)
第7回 Pod + Multi-container パターン以降、K8s の Pod マニフェストでイメージを以下のように指定します。
spec:
containers:
- name: fanclub-backend
image: 192.168.1.123:5000/fanclub-backend:0.2.0
このフォーマット(<registry>/<repository>:<tag>)は第4回で確立する命名規則の直接の応用です。
レジストリ URL を省略して image: fanclub-backend:0.2.0 と書くと、Docker は暗黙にデフォルトレジストリ docker.io/library(Docker Hub)を補完するため、プライベートレジストリのイメージはこの省略形では取得できません。完全修飾 URL の習慣付けが第7回以降のトラブル防止につながります。
Trivy v0.70.0 の概要とインストール
Trivy は Aqua Security が開発したオープンソースの脆弱性スキャナです。コンテナイメージ・ファイルシステム・Git リポジトリ・K8s マニフェスト・IaC ファイルなど幅広いスキャン対象に対応します。
CKAD 試験での扱い:Trivy 自体は CKAD 試験では直接出題されませんが、CKAD D1 (Application Design and Build) の素養として「ビルドしたイメージのセキュリティ品質を検証する」実務スキルは必須です。
第3巻 CKS では trivy k8s によるクラスタ全体スキャン・Cosign 署名検証・SBOM 生成と組み合わせて Trivy を多用するため、第4回時点で基本操作を習得しておくことが Kubestronaut 5 冠への重要な基礎となります。
本シリーズで扱う Trivy の使い方:
- 第4回(本回): コンテナイメージの脆弱性スキャン(
trivy image) - 第3巻 CKS 編: K8s クラスタ全体スキャン(
trivy k8s)・CI / CD 統合・--exit-code 1での自動ゲート
CVE と CVSS の基礎
CVE(Common Vulnerabilities and Exposures) は公開されたセキュリティ脆弱性の識別番号で、CVE-YYYY-NNNNN 形式(例: CVE-2024-12345)で発行されます。CVSS(Common Vulnerability Scoring System) でスコア 0〜10 の数値で重大度を表現します。
| 重大度 | CVSS v3 スコア |
|---|---|
| CRITICAL | 9.0〜10.0 |
| HIGH | 7.0〜8.9 |
| MEDIUM | 4.0〜6.9 |
| LOW | 0.1〜3.9 |
| UNKNOWN | スコア情報なし |
実務では --severity HIGH,CRITICAL で HIGH 以上のみ表示することでノイズを減らし、CI / CD で自動判定しやすくします。
Trivy v0.70.0 のインストール(GitHub Releases から RPM 直接取得)
本シリーズでは environment.md §7 の指針に従い、GitHub Releases から RPM を直接インストール する方式を採用します。alma-proxy whitelist には github.com と objects.githubusercontent.com が登録済みのため、追加設定なしで RPM をダウンロードできます。
get.trivy.dev や aquasecurity.github.io 経由のリポジトリ追加方式も利用可能ですが、whitelist の追加が必要となる可能性があるため避けます。
実行コマンド(k8s-ops 上で実行):
$ sudo -E rpm -ivh https://github.com/aquasecurity/trivy/releases/download/v0.70.0/trivy_0.70.0_Linux-64bit.rpm
実行結果:
https://github.com/aquasecurity/trivy/releases/download/v0.70.0/trivy_0.70.0_Linux-64bit.rpm を取得中です
検証しています... ########################################
準備しています... ########################################
更新中 / インストール中...
trivy-0.70.0-1 ########################################
実行コマンド:
$ trivy --version
実行結果:
Version: 0.70.0
v0.70.0 のリリースノートでパブリック GPG キーが更新されました。RPM 直接インストール方式(rpm -ivh)では署名検証は GPG キャッシュに依存しないため、本シリーズの方式では GPG キー更新の影響を受けません。リポジトリ追加方式を選択する場合は rpm --import で新しい公開鍵を事前にインポートする必要がある点に留意します。
Trivy スキャンの実行と結果の読み方
Trivy の出力フォーマットは table(デフォルト・人間が読みやすい)・json(機械処理向け)・cyclonedx(SBOM)・sarif(GitHub Code Scanning 向け)に対応しています。第4回では table と json を使い分けます。
スキャン結果テーブルの列の意味
| 列 | 内容 |
|---|---|
| Library | 脆弱性が含まれるパッケージ名 |
| Vulnerability ID | CVE 番号 |
| Severity | 重大度(CRITICAL / HIGH / MEDIUM / LOW / UNKNOWN) |
| Installed Version | 現在インストールされているバージョン |
| Fixed Version | 修正済みバージョン(空白は未修正) |
| Title | CVE のタイトル(概要) |
対処方針の考え方
- Fixed Version あり: ベースイメージを更新する、または Dockerfile に
RUN apt-get update && apt-get upgrade -yを追加してパッケージを更新する - Fixed Version なし: 修正版リリースを待つ、または脆弱性の影響範囲を評価してリスク受容を判断する
- 本番運用の原則: CI / CD で自動スキャンし、CRITICAL の検出でビルドを停止する(
--exit-code 1フラグを--severity CRITICALと組み合わせる)
Trivy は初回実行時に脆弱性データベースを ~/.cache/trivy/db/ にダウンロードします。DB は ghcr.io/aquasecurity/trivy-db から取得され、alma-proxy 経由で ghcr.io および pkg-containers.githubusercontent.com は whitelist 登録済みのため追加設定は不要です。
ダウンロードには数十秒〜数分かかり、2 回目以降はキャッシュが利用されて高速になります。
本シリーズではレジストリ側で insecure-registries 設定済みの状態で Trivy スキャンを実行します。
Trivy で HTTP(insecure)レジストリのイメージを直接スキャンする場合は --insecure フラグが必要になるケースがありますが、k8s-ops 側の Docker daemon が insecure-registries を解決できる状態では Trivy も同じ設定を継承する場合があります。
フラグの要否は実機検証で確定します(必要時のみ各コマンドに --insecure を追記)。
第3巻 CKS 編では trivy k8s によるクラスタ全体スキャン・Cosign によるイメージ署名検証・SBOM(bom)生成と合わせて包括的なサプライチェーンセキュリティを扱います(言及のみ・<a> リンクは張らない)。
やってみよう ① k8s-registry に registry:2 コンテナを起動
前提状態:SP_vol1-pre-05 + SP_registry-clean(k8s-ops に Docker CE 29.4.3 と fanclub-backend:0.1.0 残存・k8s-registry に Docker CE 29.4.3 と registry:2 イメージ pull 済み・両 VM の /etc/docker/daemon.json は未作成)
ステップ 1:k8s-registry の前提状態を確認
k8s-registry 側の Docker CE は第1回と同じ手順で導入済み、registry:2 イメージも pull 済みのため、ここでは 確認のみ 実施します。
実行コマンド(k8s-registry 上で実行):
$ docker --version
$ docker images registry
実行結果:
Docker version 29.4.3, build 055a478
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
registry:2 a3d8aaa63ed8 36.5MB 10.3MB
ステップ 2:firewalld でポート 5000/tcp を開放
k8s-ops から k8s-registry の TCP 5000 番ポートへ接続できるよう、firewalld のルールを追加します。
実行コマンド(k8s-registry 上で実行):
$ sudo firewall-cmd --permanent --add-port=5000/tcp
$ sudo firewall-cmd --reload
実行結果:
success
success
ステップ 3:registry:2 コンテナを Volume マウント付きで起動
/var/lib/registry ディレクトリをホスト側に作成し、コンテナの /var/lib/registry にマウントすることで、コンテナを削除しても push したイメージデータが残存する 設計を採用します。これは本番運用でも必須の構成で、-v オプションを省略すると重大な事故につながります(後述 H2-12 ヒヤリハット事例 1 で詳述)。
実行コマンド(k8s-registry 上で実行):
$ sudo mkdir -p /var/lib/registry
$ sudo docker run -d \
--name registry \
--restart=always \
-p 5000:5000 \
-v /var/lib/registry:/var/lib/registry \
registry:2
実行結果:
a28357d4bbc0df199902c323d3523e038669a3f3f59254d749dce0185a6cead4
各オプションの意味:
--name registry:コンテナ名をregistryに固定(docker logs registry等の参照が容易)--restart=always:VM 再起動時にコンテナを自動起動する(運用必須)-p 5000:5000:ホストの TCP 5000 番をコンテナの 5000 番にバインド-v /var/lib/registry:/var/lib/registry:ホスト側/var/lib/registryをコンテナ内/var/lib/registry(registry:2 のデフォルトストレージパス)にマウント
ステップ 4:registry:2 の起動確認
実行コマンド(k8s-registry 上で実行):
$ docker ps
実行結果(抜粋):
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a28357d4bbc0 registry:2 "/entrypoint.sh /etc…" 3 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp, [::]:5000->5000/tcp registry
k8s-registry 自身には insecure-registries 設定は 不要 です(H2-3・H2-4 で説明したとおり、k8s-registry は registry サーバーであり、自分自身に対して push / pull を行う場面がないため)。
ステップ 5:k8s-ops に insecure-registries を新規設定
k8s-ops 側のみ /etc/docker/daemon.json を新規作成し、insecure-registries リストに k8s-registry のアドレスを登録します。SP_vol1-pre-05 時点で daemon.json は未作成のため、sudo tee で新規作成します。
実行コマンド(k8s-ops 上で実行):
$ sudo tee /etc/docker/daemon.json <<'EOF'
{
"insecure-registries": ["192.168.1.123:5000"]
}
EOF
実行結果:
{
"insecure-registries": ["192.168.1.123:5000"]
}
実行コマンド(Docker デーモンを再起動して設定を反映):
$ sudo systemctl restart docker
ステップ 6:k8s-registry への疎通確認(v2 API エンドポイント)
Docker Registry v2 の /v2/ エンドポイントは認証なし設定時に空 JSON を返します(仕様どおり)。空の JSON {} が返れば registry:2 は正常に稼働しています。
実行コマンド(k8s-ops 上で実行):
$ curl http://192.168.1.123:5000/v2/
実行結果:
{}
やってみよう ② fanclub-backend を 0.2.0 にタグ付け → push → pull 確認
前提状態:H2-9 完了後(registry:2 稼働中・k8s-ops の insecure-registries 設定済み・fanclub-backend:0.1.0 イメージが k8s-ops にローカル存在)
ステップ 1:現在のイメージ一覧を確認
実行コマンド(k8s-ops 上で実行):
$ docker images fanclub-backend
実行結果:
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
fanclub-backend:0.1.0 3bdcfa296cf6 657MB 206MB
ステップ 2:レジストリ URL 付きでタグ付け
実行コマンド(k8s-ops 上で実行):
$ docker tag fanclub-backend:0.1.0 192.168.1.123:5000/fanclub-backend:0.2.0
実行結果:
(成功時は出力なし)
実行コマンド(タグ付け後のイメージ一覧を確認):
$ docker images 192.168.1.123:5000/fanclub-backend
実行結果:
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
192.168.1.123:5000/fanclub-backend:0.2.0 3bdcfa296cf6 657MB 206MB
fanclub-backend:0.1.0 3bdcfa296cf6 657MB 206MB
CKAD 重要論点:タグ付けの前後で Image ID が同一 です。fanclub-backend:0.1.0 と 192.168.1.123:5000/fanclub-backend:0.2.0 は同じレイヤー群を共有しており、docker tag は参照名を追加したのみでイメージの複製は行っていません。DISK USAGE と CONTENT SIZE も同一になります。
ステップ 3:レジストリへ push
実行コマンド(k8s-ops 上で実行):
$ docker push 192.168.1.123:5000/fanclub-backend:0.2.0
実行結果(抜粋):
The push refers to repository [192.168.1.123:5000/fanclub-backend]
1c24335ddd46: Pushed
4f4fb700ef54: Pushed
554f95b84947: Pushed
9175fb3b2c6c: Pushed
61893479a6f7: Pushed
11aef3c20eb3: Pushed
5ace8b741561: Pushed
6f5c5aa4e145: Pushed
c77744225e99: Pushed
a56ed0a45c6f: Pushed
...
0.2.0: digest: sha256:3bdcfa296cf6b545aa2878f46b7c41bc5b65b3e05c497f19ae3cec13eb4b24ce size: 856
各レイヤーが順番にアップロードされ、最終行にダイジェスト(sha256:...)と manifest サイズが表示されます。同じレイヤーが既に存在する場合は「Layer already exists」と表示され、再アップロードはスキップされます。
ステップ 4:ローカルのタグを削除して pull 確認
「レジストリから本当に pull できるか」を確認するため、ローカルの 0.2.0 タグを削除してから pull します。
実行コマンド(ローカルの 0.2.0 タグを削除):
$ docker rmi 192.168.1.123:5000/fanclub-backend:0.2.0
実行結果:
Untagged: 192.168.1.123:5000/fanclub-backend:0.2.0
実行コマンド(レジストリから pull):
$ docker pull 192.168.1.123:5000/fanclub-backend:0.2.0
実行結果(抜粋):
0.2.0: Pulling from fanclub-backend
Digest: sha256:3bdcfa296cf6b545aa2878f46b7c41bc5b65b3e05c497f19ae3cec13eb4b24ce
Status: Downloaded newer image for 192.168.1.123:5000/fanclub-backend:0.2.0
192.168.1.123:5000/fanclub-backend:0.2.0
fanclub-backend:0.1.0 として参照される同一レイヤー群がローカルに残っているため、すべて「Already exists」となり実データのダウンロードはほとんど発生しません。これがレイヤー単位の pull / push 効率化の実例です。
ステップ 5:レジストリに格納されたイメージを確認(Catalog API)
Docker Registry v2 には HTTP API が備わっており、格納イメージの一覧を確認できます。
実行コマンド(k8s-ops 上で実行):
$ curl http://192.168.1.123:5000/v2/_catalog
実行結果:
{"repositories":["fanclub-api","fanclub-backend"]}
実行コマンド(タグ一覧を取得):
$ curl http://192.168.1.123:5000/v2/fanclub-backend/tags/list
実行結果:
{"name":"fanclub-backend","tags":["0.2.0"]}
やってみよう ③ Trivy スキャン(HIGH/CRITICAL のみ表示・JSON 出力)
前提状態:H2-10 完了後(k8s-registry に fanclub-backend:0.2.0 が存在・Trivy v0.70.0 が k8s-ops にインストール済み)
ステップ 1:まず全重大度でスキャン(結果の全体像を把握)
実行コマンド(k8s-ops 上で実行):
$ trivy image \
--db-repository ghcr.io/aquasecurity/trivy-db:2 \
--java-db-repository ghcr.io/aquasecurity/trivy-java-db:1 \
192.168.1.123:5000/fanclub-backend:0.2.0
実行結果(抜粋):
2026-05-09T22:42:02+09:00 INFO [vuln] Vulnerability scanning is enabled
2026-05-09T22:42:02+09:00 INFO [secret] Secret scanning is enabled
2026-05-09T22:42:04+09:00 INFO [javadb] Downloading Java DB...
2026-05-09T22:43:33+09:00 INFO Detected OS family="ubuntu" version="26.04"
2026-05-09T22:43:33+09:00 INFO [ubuntu] Detecting vulnerabilities... os_version="26.04" pkg_num=106
2026-05-09T22:43:33+09:00 INFO Number of language-specific files num=2
2026-05-09T22:43:33+09:00 INFO [gobinary] Detecting vulnerabilities...
2026-05-09T22:43:33+09:00 INFO [jar] Detecting vulnerabilities...
Report Summary
┌─────────────────────────────────────────────────────────┬──────────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ 192.168.1.123:5000/fanclub-backend:0.2.0 (ubuntu 26.04) │ ubuntu │ 0 │ - │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ opt/payara/app.war │ jar │ 0 │ - │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ opt/payara/payara-micro.jar │ jar │ 0 │ - │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ usr/bin/pebble │ gobinary │ 0 │ - │
└─────────────────────────────────────────────────────────┴──────────┴─────────────────┴─────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
初回実行時は脆弱性データベースのダウンロードが発生し、数十秒〜数分かかります。ghcr.io/aquasecurity/trivy-db から取得され、alma-proxy 経由で whitelist 既登録のため追加設定は不要です。2 回目以降はキャッシュ(~/.cache/trivy/db/)が利用されて高速になります。
ステップ 2:HIGH/CRITICAL のみフィルタして表示
実行コマンド(k8s-ops 上で実行):
$ trivy image \
--db-repository ghcr.io/aquasecurity/trivy-db:2 \
--java-db-repository ghcr.io/aquasecurity/trivy-java-db:1 \
--severity HIGH,CRITICAL \
192.168.1.123:5000/fanclub-backend:0.2.0
実行結果(抜粋):
Report Summary
┌─────────────────────────────────────────────────────────┬──────────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ 192.168.1.123:5000/fanclub-backend:0.2.0 (ubuntu 26.04) │ ubuntu │ 0 │ - │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ opt/payara/app.war │ jar │ 0 │ - │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ opt/payara/payara-micro.jar │ jar │ 0 │ - │
├─────────────────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
│ usr/bin/pebble │ gobinary │ 0 │ - │
└─────────────────────────────────────────────────────────┴──────────┴─────────────────┴─────────┘
--severity HIGH,CRITICAL を指定すると LOW・MEDIUM・UNKNOWN の脆弱性は出力から除外され、優先度の高い CVE のみに集中できます。CI / CD での自動判定に組み込む際の定番フィルタです。
実機の fanclub-backend:0.2.0 では HIGH/CRITICAL は 0 件(全 4 ターゲット clean)でしたが、これは執筆時点の Trivy DB のスナップショットであり、新たに公表された CVE が将来検出される可能性があります(脆弱性 DB の継続更新が重要)。
ステップ 3:JSON 形式でファイルに保存
実行コマンド(k8s-ops 上で実行):
$ trivy image \
--db-repository ghcr.io/aquasecurity/trivy-db:2 \
--java-db-repository ghcr.io/aquasecurity/trivy-java-db:1 \
--severity HIGH,CRITICAL \
--format json \
--output fanclub-scan-result.json \
192.168.1.123:5000/fanclub-backend:0.2.0
実行コマンド(保存ファイルのサイズを確認):
$ ls -lh fanclub-scan-result.json
実行結果:
-rw-r--r--. 1 developer developer 837K 5月 9 22:43 fanclub-scan-result.json
ステップ 4:JSON の主要フィールドを確認
JSON 内の Results[].Vulnerabilities[] 配列から VulnerabilityID・Severity・Title を抽出して一覧表示します。
実行コマンド(k8s-ops 上で実行):
$ cat fanclub-scan-result.json | python3 -c "import sys, json; d=json.load(sys.stdin); [print(r.get('VulnerabilityID',''), r.get('Severity',''), r.get('Title','')) for res in d.get('Results',[]) for r in res.get('Vulnerabilities',[])]" | head -20
実行結果(抜粋):
(実機の fanclub-backend:0.2.0 では HIGH/CRITICAL の脆弱性は 0 件のため、このコマンドの出力は空になります。LOW/MEDIUM を含めてフィルタを外せば検出される CVE のうち上位 20 件が表示されます。CI/CD で重大脆弱性ゲートを掛ける場合は --severity HIGH,CRITICAL でフィルタした上で出力件数が 0 件であることを成功条件とする運用が一般的です。)
検出された CVE のうち Fixed Version が表示されているもの は、ベースイメージ(eclipse-temurin:25-jre)を新しいパッチバージョンに更新することで修正できます。eclipse-temurin は定期的にセキュリティ更新が提供されるため、CI / CD で定期的にイメージをリビルドする運用が基本です。
Fixed Version が空白 の CVE は修正版リリースを待つか、影響範囲を評価してリスク受容を判断します。
現場ヒヤリハット
事例 1:registry コンテナを再作成したら push 済みのイメージが全部消えた
入社半年の F さんは、k8s-registry の動作確認のために docker run -d --name registry -p 5000:5000 registry:2 という Volume マウントなしの簡易コマンドで registry コンテナを起動していました。
fanclub-backend:0.2.0 を push して動作確認を済ませた後、レジストリの設定変更のため docker rm -f registry でコンテナを削除し、同じコマンドで再作成しました。
再起動後、curl http://192.168.1.123:5000/v2/_catalog を実行すると {"repositories":[]} が返ってきて、push 済みだったはずの fanclub-backend が一覧に存在しません。
あわてて k8s-ops から docker pull 192.168.1.123:5000/fanclub-backend:0.2.0 を試すと manifest unknown エラーで失敗しました。
原因:registry:2 コンテナのデフォルトストレージパス /var/lib/registry はコンテナ内部のファイルシステムであり、Volume マウントなしで起動するとコンテナ削除と同時にイメージデータがすべて消えます。
registry:2 はストレージを永続化する責任をホスト側に委ねる設計のため、-v /var/lib/registry:/var/lib/registry オプションが本番運用では必須です。
第7回以降、kind クラスタの Pod が 192.168.1.123:5000/fanclub-backend:0.2.0 を pull しようとして ImagePullBackOff エラーになる典型原因の一つがこのケースです。レジストリ側でイメージが消失している場合、kind 側のいくら設定を見直してもエラーは解消しません。
対処法:
- registry:2 コンテナは必ず
-v /var/lib/registry:/var/lib/registry付きで起動する(H2-9 ステップ 3 のコマンドを使う) - 本記事 H2-9 の手順に従えばホスト側
/var/lib/registryにイメージが永続化されるため、コンテナを削除しても再起動後に_catalogでイメージが残っていることを確認できる - すでにイメージを失った場合は、k8s-ops で
docker pushをやり直す(k8s-ops 側のローカルキャッシュは生きているため再 push 可能)
事例 2:latest タグで本番障害 — 先週と同じイメージのはずが動作が違う
入社 1 年目の G さんは、本番環境の Deployment マニフェストで image: nginx:latest を指定していました。月曜日の朝、特にデプロイ作業は行っていないにもかかわらず、一部の API エンドポイントで挙動が変わったとサポートチームから報告がありました。
Pod のステータスを確認すると、土日の自動再起動(Node メンテナンスによる退避)で Pod が再作成されたタイミングで imagePullPolicy: Always 設定下に nginx:latest が再 pull され、ベースイメージのマイナーアップデートに引きずられて挙動が変わっていました。
原因:latest タグはミュータブルであり、ベースイメージの提供者(Docker Hub の Nginx 公式メンテナ)が更新すると自動的に内容が変わります。
Docker Hub の公式イメージは定期的にセキュリティ修正やマイナーアップデートが適用されるため、latest を本番で参照していると「コードを変更していないのに動作が変わる」現象が発生します。imagePullPolicy: Always(K8s で :latest 指定時のデフォルト動作)ではこの問題が顕在化しやすくなります。
対処法:
- 本番イメージは必ずバージョンタグ(SemVer)を使用する(例:
nginx:1.27-alpineではなくnginx:1.27.4-alpineのようにパッチまで固定) - Dockerfile の
FROMもeclipse-temurin:25-jreではなくeclipse-temurin:25.0.3_9-jre-nobleのような完全バージョンを指定する - セキュリティ重視ならイメージダイジェスト(
image:tag@sha256:...)を Deployment マニフェストに直接書き込む - CI / CD で Trivy スキャンを組み込み、ベースイメージの脆弱性を定期的に検出してから明示的にバージョンタグを上げる運用に切り替える
本シリーズで fanclub-backend のタグを 0.1.0 → 0.2.0 → 0.4.0 … と毎回採番しているのは、latest タグの罠を避けるためです。第7回 Pod + Multi-container パターン以降の K8s マニフェストでも、latest タグは一切使用しません。
事例 3:trivy image 直後に Forbidden・脆弱性 DB がダウンロードできない
入社 1 年目の H さんは、第4回の演習③で Trivy v0.70.0 をインストール直後に trivy image 192.168.1.123:5000/fanclub-backend:0.2.0 を実行しました。すると以下のエラーで FATAL 終了しました。
2026-05-09T22:40:41+09:00 INFO [vulndb] Downloading artifact... repo="mirror.gcr.io/aquasec/trivy-db:2"
2026-05-09T22:40:41+09:00 FATAL Fatal error run error: init error: DB error: failed to download vulnerability DB:
* Get "https://mirror.gcr.io/v2/": Forbidden
原因:Trivy v0.70.0 のデフォルト脆弱性 DB リポジトリは mirror.gcr.io/aquasec/trivy-db:2(Google Container Registry のミラー)です。
本シリーズの検証環境は alma-proxy(Squid whitelist 方式)を経由しており、whitelist には download.docker.com・registry-1.docker.io・github.com・objects.githubusercontent.com・.ghcr.io 等は登録済みですが、mirror.gcr.io は未登録 でした。proxy が HTTPS 接続を拒否し Forbidden が返ります。
Java アプリ(fanclub-backend は Payara Micro / Java)をスキャンする際は Java DB(mirror.gcr.io/aquasec/trivy-java-db:1)も同様に必要となり、こちらも同じ問題で失敗します。
対処法:
- 選択肢 A(本シリーズ採用・即効性高):Trivy のリポジトリオプションで
ghcr.io/aquasecurity/...系に切り替える。alma-proxy whitelist には.ghcr.ioが登録済みのため動作する。本記事のすべてのtrivy imageコマンドはこの形式(--db-repository ghcr.io/aquasecurity/trivy-db:2 --java-db-repository ghcr.io/aquasecurity/trivy-java-db:1)で記述している。 - 選択肢 B(本番運用向け・恒久対策):alma-proxy(Squid)の whitelist に
mirror.gcr.ioを追加する。複数の閉域網ホストで Trivy を使う場合は proxy 側で対応するのが管理コストが低い。 - 選択肢 C(CLI フラグ常設化):
~/.config/trivy/trivy.yamlにdb: { repository: ghcr.io/aquasecurity/trivy-db:2 } / javadb: { repository: ghcr.io/aquasecurity/trivy-java-db:1 }を記述すると、毎回フラグを書く必要がなくなる。CI / CD ジョブの Docker イメージにこの設定を焼き込んでおくと運用が楽になる。
第3巻 CKS では trivy k8s によるクラスタ全体スキャン・Cosign 署名検証・SBOM 生成と組み合わせて Trivy を多用するため、デフォルトリポジトリの設定方針は早期に確立しておくのが安全です。
本シリーズの第4回〜第3巻 CKS まで、Trivy コマンドはすべて --db-repository ghcr.io/aquasecurity/... の形式で統一します。
今回のまとめ + 理解度チェック
第4回では以下を実施しました。
- k8s-registry(192.168.1.123)に Docker Registry(registry:2)を Volume マウント付きで構築した
- HTTP(insecure registry)構成の設計判断と
/etc/docker/daemon.jsonの新規作成手順(k8s-ops 側のみ)を確認した - k8s-registry 側に
insecure-registries設定が不要であること(自分自身に push / pull しない)を確認した docker tagの本質(参照名の追加のみ・Image ID 同一・レイヤー共有)を確認したdocker push/docker pullのレイヤー単位の転送効率化(Already exists / Layer already exists)を確認した- イメージタグ戦略(
latestの罠・SemVer・Git ハッシュ・イメージダイジェスト・ミュータブル / イミュータブルタグ)を整理した - Trivy v0.70.0 を GitHub Releases から RPM 直接インストール方式で導入し、
fanclub-backend:0.2.0の CVE をスキャンして JSON 形式で保存した
fanclub-api をどう作ってきたか:
第3回: [Backend(Java)] ← Dockerfile を書いた(v0.1.0) [完了]
第4回: [Backend → k8s-registry] ← レジストリに push した(v0.2.0) ← 今ここ
第7回: [Backend(Pod)] ← K8s に初めて載せる(v0.2.0 を使用)
第1部「コンテナと Docker」全 4 回のまとめ:
| 回 | テーマ | 習得内容 |
|---|---|---|
| 第1回 | コンテナ技術概念 + Docker 環境準備 | コンテナの仕組み・Docker CE インストール |
| 第2回 | Docker 基本操作 | コンテナライフサイクル・Volume・bind mount |
| 第3回 | Dockerfile + マルチステージビルド | Dockerfile 記法・JDK 25 / Payara Micro イメージ構築 |
| 第4回 | レジストリ + タグ戦略 + Trivy | push / pull・タグ戦略・脆弱性スキャン |
理解度チェック(○× 形式・全 8 問)
| 問 | 問題文 | 解答 |
|---|---|---|
| 1 | Docker Registry(registry:2)は Docker Hub と同じ OCI Distribution Spec に基づいており、HTTP / HTTPS の両方で動作できる | ○ |
| 2 | docker tag コマンドを実行すると、新しいレイヤーを持つ新しいイメージが作成される | × |
| 3 | latest タグは常に最新の安定バージョンを指すため、本番環境での使用が推奨される | × |
| 4 | セマンティックバージョニングでは PATCH 番号は後方互換性のない変更を意味する | × |
| 5 | イメージダイジェスト(sha256:...)はイメージの内容が変わると変化する | ○ |
| 6 | Trivy の --severity HIGH,CRITICAL オプションを使うと LOW・MEDIUM の脆弱性は出力から除外される | ○ |
| 7 | docker push 時に、ローカルに存在するレイヤーと同一のレイヤーがレジストリに既にある場合、そのレイヤーのアップロードはスキップされる | ○ |
| 8 | K8s の Pod マニフェストで image: fanclub-backend:0.2.0 と書いた場合、デフォルトでは Docker Hub からの pull が試みられる(fanclub-backend は Docker Hub に存在しないため pull は失敗する) | ○ |
解説(重要問のみ):
- 問 2:
docker tagはレイヤーを共有する参照名の追加のみで、新しいレイヤーや新しいイメージは作成されません。docker imagesで確認すると Image ID が同一になります。 - 問 3:
latestタグはミュータブルで上書きが可能です。「常に最新の安定版」を保証する仕組みは存在せず、本番運用では SemVer による明示的なバージョン指定が必須です。 - 問 4:PATCH 番号は バグ修正・セキュリティ修正のみ を意味します。後方互換性のない変更は MAJOR 番号を上げる必要があります。
- 問 8:レジストリ URL の指定がない場合、Docker クライアントも K8s の kubelet も同じく
docker.io/library(Docker Hub)への補完を行ってイメージ取得を試みます。プライベートレジストリを使う場合は192.168.1.123:5000/fanclub-backend:0.2.0のように完全修飾する必要があり、第7回以降の Pod マニフェストでも常にこのフォーマットを使います。なおバージョンタグ付き指定ではimagePullPolicyのデフォルトがIfNotPresentとなり、一度 pull 成功した Node では再 pull されません(Node 移設・障害時の再デプロイで pull が必要になる場面でレジストリへの到達性が問われます)。
次回予告:第5回 Kubernetes の全体像 + kind で軽量 K8sでは、第1部で構築した Docker 知識を土台に Kubernetes の全体像と kind による軽量クラスタの構築手順を習得します。K8s アーキテクチャ(Control Plane Node / Workload Node)を図解で理解し、kind v0.31.0 でシングルノードクラスタを起動します。
第4回で k8s-registry に push した fanclub-backend:0.2.0 は第7回 Pod + Multi-container パターンで初めて K8s の Pod として動作します。第19回 fanclub-api 全機構連携の実技総ざらい総合演習に向けた基盤づくりを進めます。
シリーズ一覧
第1部:コンテナと Docker
- 第1回 コンテナ技術概念 + Docker 環境準備
- 第2回 Docker 基本操作
- 第3回 Dockerfile + マルチステージビルド + JDK 25 / Payara Micro イメージビルド
- 第4回 コンテナレジストリ + イメージタグ戦略 + Trivy スキャン ← 今ここ
第2部:Kubernetes 基礎
第3部:アプリリソース
- 第7回 Pod + Multi-container パターン
- 第8回 Service とネットワーキング
- 第9回 ストレージ(PVC + StatefulSet)+ PostgreSQL DB 追加
- 第10回 ConfigMap + Secret + ServiceAccount 基礎
- 第11回 Job + CronJob + DaemonSet
第4部:ワークロード戦略
- 第12回 Deployment + 3 Probe + Rolling Update + Probe デバッグ実践
- 第13回 Deployment 戦略補完(Blue/Green + Canary + Recreate)
- 第14回 ResourceQuota + LimitRange + Multi-tenant Namespace
