0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kubernetes④(全7回)|minikube|ConfigMap・Secret・PersistentVolumeを理解する

0
Last updated at Posted at 2026-02-18

シリーズ記事一覧

📑 目次

  1. この記事について
  2. この記事のゴール
  3. 前提条件
  4. なぜ設定と永続化を分離するのか?
  5. ConfigMapとは?
  6. Secretとは?
  7. Secretの保護レイヤーと実務運用
  8. データの永続化 ― PersistentVolume(PV)とPVC
  9. PVの自動作成 ― StorageClassと動的プロビジョニング
  10. DBをk8sで動かす ― StatefulSet
  11. YAMLの書き方 ― ConfigMap・Secret・PVCの定義
  12. ハンズオン:ConfigMap・Secret・PVCを操作する
  13. まとめ

1. この記事について

1-1. シリーズ概要

Docker Compose経験者が「素のKubernetes」を
1週間で実践レベルまで習得する
ことを目指す学習記録です。

1-2. シリーズ構成

テーマ 内容
第1回 全体像と環境構築 Docker Composeとの対比、minikube導入
第2回 Pod と Deployment コンテナ起動〜スケーリング〜ローリングアップデート
第3回 Service と Ingress ネットワークと外部公開
第4回(本記事) ConfigMap / Secret / PV 設定管理と永続化
第5回 模擬プロジェクト 全概念を組み合わせて実践
第6回 トラブルシュートと運用 エラー対応、ログ確認
第7回 総まとめ 振り返り

1-3. 対象読者

  • 第3回を読み終えた方(Service・Ingress・CoreDNSが理解済み)
  • Docker Composeの environmentvolumes を使ったことがある方
  • 「k8sでパスワードやデータをどう管理するの?」を知りたい方

2. この記事のゴール

# ゴール 確認方法
なぜ設定と永続化を分離するかを説明できる Docker Composeの課題と、k8sの3リソースによる解決策を語れる
ConfigMapの2つの使い方を実践できる 環境変数注入とファイルマウントの違いを語れる
SecretとConfigMapの違いを説明できる Base64の本質、保護レイヤーの構成を語れる
PV/PVCの関係とStorageClassの
動的プロビジョニングを説明できる
手動/動的の違い、volumeBindingModeを語れる
DeploymentとStatefulSetの
使い分けを判断できる
ステートレス/ステートフルの選定基準を語れる

3. 前提条件

3-1. 環境情報

項目 バージョン / 詳細
OS Windows 11 + WSL2 Ubuntu
minikube インストール済み(第1回で構築)
kubectl インストール済み(第1回で構築)

3-2. 前提知識

  • 第3回の内容(Service・Ingress・CoreDNS・YAML書き方)
  • Docker Composeの environmentvolumes の意味

4. なぜ設定と永続化を分離するのか?

4-1. Docker Composeの課題

# docker-compose.yml
services:
  api:
    image: myapp-api:1.0
    environment:
      - RAILS_ENV=production
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
      - SECRET_KEY_BASE=abc123verysecretkey
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data:
課題 問題
パスワードが丸見え docker-compose.yml にDB接続情報が平文
環境ごとの切替が面倒 dev/staging/prodで別々のファイルが必要
設定変更 = コンテナ再起動 環境変数を変えるには docker-compose up -d が必要
ボリュームがNode固定 データが特定のホストに紐づく

4-2. k8sの解決策:3つのリソースで責務分離

リソース 責務 Docker Composeとの対応
ConfigMap 一般的な設定(環境変数、設定ファイル) environment: の非機密部分
Secret 機密情報(パスワード、APIキー、証明書) environment: の機密部分
PersistentVolume データの永続化 volumes:

🍽️
Docker Compose = 「レシピ・材料リスト・金庫の鍵を全部同じノートに書く」。
k8s =
「レシピ(Deployment)」/「材料リスト(ConfigMap)」/「金庫の鍵(Secret)」/「食材倉庫(PV)」を別々に管理


5. ConfigMapとは?

5-1. 基本概念

ConfigMapは「アプリケーションの設定情報を外部化して管理するリソース」

観点 Docker Compose k8s ConfigMap
設定の定義場所 docker-compose.yml の中 別リソース(YAML)
設定の変更 ファイル書き換え → up -d ConfigMap更新 → Pod再起動 or 自動反映
環境の切替 ファイルを丸ごと差し替え ConfigMapだけ差し替え
再利用性 低い 複数のDeploymentから参照可能

🍽️
Docker Compose = レシピと材料リストが同じノートに書いてある。
ConfigMap = 材料リストだけ別のカードに書く
「塩の量を変えたい」→ カードだけ差し替え。
レシピ(Deployment)は変更不要。

5-2. ConfigMapに入れるもの / 入れないもの

入れる ✅ 入れない ❌
RAILS_ENV=production パスワード
DATABASE_HOST=db-service APIキー
LOG_LEVEL=info 秘密鍵・証明書
nginx.conf 等の設定ファイル これらはSecretへ

5-3. 2つの使い方

① 環境変数として注入

Docker Composeの environment: と同じ感覚。
ConfigMapの全キーがPodの環境変数になります。

② ファイルとしてマウント

Docker Composeの volumes: ./nginx.conf:/etc/nginx/nginx.conf と同じ感覚。
ConfigMapの中身をファイルとしてPod内にマウントします。

使い方 適するケース Docker Composeとの対応
環境変数 少数のキー=値ペア environment:
ファイルマウント 設定ファイル丸ごと volumes: でホストファイルをマウント

5-4. 更新時の反映ルール

マウント方式 ConfigMap更新時の挙動 Pod再起動
環境変数 反映されない 必要
ファイルマウント 自動反映(数十秒〜数分) 不要(ただしアプリの再読み込みが必要)

🍽️
環境変数 = 「入社時に渡すマニュアル印刷版」→ 改訂しても既存スタッフは古い版のまま。
ファイルマウント = 「共有フォルダのマニュアル」→ 更新すればみんな最新版が見える。

5-5. 共有パターン

1つのConfigMapを複数のDeploymentから参照できます。

パターン 構成 ユースケース
共通 + 個別 common + web/api/worker 最も一般的
環境別 dev/staging/prod 同じアプリの環境切替
設定ファイル共有 nginx.conf等をマウント 複数PodでProxy設定を統一

🍽️
app-common-config = 全店舗共通の営業マニュアル
web-config = ホール担当専用のマニュアル
api-config = 厨房担当専用のマニュアル

環境別の切替

ポイント 説明
Deploymentは全く同じYAML 環境差分はConfigMapだけ
ConfigMap名を同じにする 中身だけ違う
Namespaceで分離 dev用/prod用Namespaceにそれぞれ同名のConfigMapを配置

⚠️ 共有ConfigMap更新時の注意

共通ConfigMapを変更すると参照している全Deploymentに影響します。
対策として、
immutable: true でイミュータブルにしたり、
名前にバージョン番号を含めて明示的に参照先を切り替える方法があります。

# イミュータブルConfigMap(変更不可)
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-v2
immutable: true
data:
  LOG_LEVEL: "debug"
フィールド 意味
immutable: true 作成後に変更不可(誤変更を防ぐ安全策)
変更したい場合 ConfigMapを削除→再作成が必要

🔰 いつ使う? DB接続先やAPIキーなど「絶対に動的変更してほしくない値」に有効です。


6. Secretとは?

6-1. 基本概念

SecretはConfigMapの「機密情報版」 です。
構造はほぼ同じですが、機密データ向けの追加保護があります。

観点 ConfigMap Secret
用途 一般的な設定 機密情報
データ形式 平文 Base64エンコード
メモリ上の扱い 通常 tmpfs(ディスクに書かない)
アクセス制御 RBAC RBAC + より厳格な制限が可能

🍽️
ConfigMap = 店舗の営業マニュアル(棚に置いてある)。
Secret = 金庫の暗証番号メモ(鍵付きの引き出しに保管)、中身の書き方は同じ、
保管方法と閲覧権限が違う。

6-2. Secretの種類

type 用途
Opaque 汎用(デフォルト) パスワード、APIキー
kubernetes.io/tls TLS証明書 第3回で学んだIngress用証明書
kubernetes.io/dockerconfigjson Dockerレジストリ認証 プライベートレジストリのログイン情報
kubernetes.io/basic-auth Basic認証 ユーザー名 + パスワード

🔰 Memo:
Opaque(オペイク)は
英語で「中身が見えない・不透明」という意味。
つまり「k8sが中身の形式を気にしない、何でも入れられる汎用タイプ」ということ。
他のtypeはk8sが中身の形式をチェックしますが、Opaqueはノーチェックで自由に使えます。
ほとんどのケースで Opaque を使います。

🍽️
Opaque = 「中身おまかせ弁当箱」。
他のtypeは「TLS専用ケース」「認証情報専用ケース」のように形が決まっている。

6-3. Base64は「暗号化」ではない

🔰誤解しやすいポイントだと思いました。

# Base64エンコード(誰でも元に戻せる)
echo -n "mypassword" | base64
# → bXlwYXNzd29yZA==

# Base64デコード(1コマンドで元に戻る)
echo "bXlwYXNzd29yZA==" | base64 -d
# → mypassword
誤解 現実
「Base64だから安全」 ❌ Base64はただのエンコード。暗号化ではない
「Secretに入れれば安心」 ❌ デフォルトではetcdに平文保存される

6-4. 使い分けの判断

🔰 Memo:
迷ったらSecretにしておくのが安全。
後からConfigMapに変更するのは簡単ですが、漏れた情報は取り消せない。

情報 ConfigMap or Secret 理由
RAILS_ENV=production ConfigMap 漏れても問題なし
DATABASE_HOST=db-service ConfigMap 接続先ホスト名は機密ではない
DATABASE_PASSWORD=xxx Secret パスワードは機密
API_KEY=sk-xxxx Secret APIキーは機密
TLS証明書 Secret 秘密鍵は機密

6-5. data: と stringData: の違い

# stringData:(平文で書ける ★推奨)
stringData:
  POSTGRES_PASSWORD: "secretpass123"

# data:(Base64エンコードが必要)
data:
  POSTGRES_PASSWORD: "c2VjcmV0cGFzczEyMw=="

どちらもk8sが保存する時はBase64に変換されます。
stringData: の方が読みやすいので実務ではこちらを使います。


7. Secretの保護レイヤーと実務運用

セクション6-3で、
「Base64は暗号化ではない」と書きました。
では、Secretはどうやって守られているのか?、
については、k8sには複数の保護の仕組みが重なっているので整理してみます。

7-1. Secretの保護レイヤー

保護レイヤー 説明 デフォルト
RBAC 誰がSecretを読めるか制御 ✅ 有効
tmpfs マウント Pod内でディスクに書かず、メモリ上のみ ✅ 有効
etcd暗号化 etcd内のSecret値を暗号化 ❌ 手動で有効化が必要
外部シークレット管理 AWS Secrets Manager等と連携 ❌ 別途設定が必要

🔰 Memo:
RBAC(Role-Based Access Control)は「役割ベースのアクセス制御」です。
「この人はSecretを読める」「この人は読めない」を役割(Role)で管理する仕組みです。

🍽️
RBAC = 「金庫の鍵を持てる人を役職で決める」、
店長は金庫を開けられるが、アルバイトは開けられない。

🍽️
Base64 = 「暗証番号を逆さまに書く」(見ればわかる)。
RBAC = 「引き出しに鍵をかける」。
etcd暗号化 = 「金庫に入れる」。
外部シークレット管理 = 「銀行の貸金庫」。

7-2. etcd暗号化

デフォルトではSecretetcdにBase64のまま保存されます。
暗号化を有効にするとAPI Serverが暗号化してから保存します。

環境 etcd暗号化の状況
AWS EKS ✅ デフォルトで有効(AWS KMS連携)
GCP GKE ✅ デフォルトで有効(Google KMS連携)
Azure AKS ✅ デフォルトで有効
minikube ❌ デフォルトで無効(手動設定が必要)

🔰 マネージドk8s(EKS/GKE/AKS)を使えばetcd暗号化は最初から有効、
素のk8sの場合のみ手動設定が必要です。

7-3. Secretとgit ― やってはいけないこと

やり方 安全性 説明
❌SecretのYAMLをそのままgitに入れる ❌危険 パスワードが平文でリポジトリに残る
✅ Sealed Secrets 安全 暗号化されたSecretをgitに入れる
✅ External Secrets Operator 安全 外部サービスから自動取得
✅ kubectl で手動作成 安全 gitに入れず手動でクラスタに投入

7-4. 比較 Sealed Secrets vs External Secrets Operator

✅Sealed Secrets — git内で暗号化して管理:

✅External Secrets Operator — 外部サービスから自動取得:

比較:

観点 Sealed Secrets External Secrets Operator
秘密情報の保管場所 gitリポジトリ内(暗号化済み) 外部サービス
外部サービス不要 ✅ k8s内で完結 ❌ AWS SM等が必要
シークレットローテーション 手動 自動対応可能
導入の手軽さ ★★★ 簡単 ★★☆ やや複雑
本番推奨度 小〜中規模 中〜大規模

8. データの永続化 ― PersistentVolume(PV)とPVC

ここまでConfigMap(設定)とSecret(機密情報)を学びました。
この記事の最後のテーマは 「データの永続化」 です。

ConfigMap/Secretは「アプリに渡す設定値」でしたが、
PersistentVolumeは「アプリが生成するデータの保存先」です。

リソース 何を扱う
ConfigMap 設定値 環境変数、設定ファイル
Secret 機密情報 パスワード、APIキー
PersistentVolume アプリが生成するデータ DBのデータ、アップロードファイル

8-1. なぜPodにデータを保存できないのか?

Podは使い捨てで、消えると中のデータも消えます。

🍽️
Pod = 紙皿。
料理(データ)を載せても、皿を捨てたら料理も消える。
料理を 別の保管庫(PersistentVolume) に置いておけば、
皿を替えても料理は残る。

8-2. 3つの登場人物

リソース 誰が作る? 役割
PV インフラ管理者(or 自動) ストレージの実体
PVC 開発者 ストレージの要求
Pod 開発者 PVCを参照してマウント

🍽️
PV = 飲食チェーンの食材倉庫(「渋谷の倉庫A、100㎡あります」)。
PVC = 店舗からの倉庫利用申請書(「100㎡の倉庫が欲しいです」)。
Pod = 店舗のスタッフ(「割り当てられた倉庫から食材を取り出して使う」)。

8-3. PVの主な設定項目

PVを作る時に決める設定は主に3つです。

設定項目 何を決める? 一番よく使う値
容量(storage) ストレージのサイズ 用途に応じて
アクセスモード 誰が読み書きできるか RWO(1つのNode)
回収ポリシー PVC削除時にデータをどうするか 本番: Retain / 開発: Delete

🍽️ 倉庫を借りる時に、
「広さは?」「個室か共有か?」、
「解約時に中身をどうするか?」を決めるのと同じです。

8-4. アクセスモード

モード 略称 意味 ユースケース
ReadWriteOnce RWO 1つのNodeだけが読み書き DB、一般的なアプリ
ReadOnlyMany ROX 複数Nodeが読み取り専用 共有設定ファイル
ReadWriteMany RWX 複数Nodeが読み書き 共有ファイルストレージ

🔰最も使うのはRWOです。

🍽️
RWO = 個室の倉庫
ROX = ショーケース(見るだけ)。
RWX = 共有倉庫

8-5. 回収ポリシー(ReclaimPolicy)

PVCが削除された時、PVのデータをどうするかの設定です。

ポリシー 動作 ユースケース
Retain PVとデータを残す 本番DB
Delete PVとデータを自動削除 開発環境

⚠️ 本番DBには必ず Retain を使う
Delete だとPVC削除でデータが消えます。

8-6. データのライフサイクル

シナリオ PVC PV データ
Podだけ削除 残る 残る 残る ✅
Pod + PVC を削除(Retain) 消える 残る 残る ✅
Pod + PVC を削除(Delete) 消える 消える 消える ❌

9. PVの自動作成 ― StorageClassと動的プロビジョニング

セクション8ではPV/PVCの仕組みを学びました。
しかし、PVを毎回手動で作るのは大変です。
アプリが増えるたびに管理者がPVを用意するのは現実的ではありません。

そこで登場するのがStorageClassです。
PVCを作るだけでPVが自動的に用意される「動的プロビジョニング」を実現します。

🍽️
セクション8 = 「倉庫を1つずつ手作業で契約」。
セクション9 = 「不動産会社に頼めば自動で倉庫が見つかる」。

9-1. 手動 vs 動的プロビジョニング

方式 PVの作成 使う場面
手動 管理者が手動で作成 オンプレミス、特殊要件
動的 StorageClassが自動作成 クラウド環境(主流)

🍽️
手動 = 「倉庫が欲しい」→ 管理者が物件を探して契約。
動的 = 「倉庫が欲しい」→ 不動産会社(StorageClass)が自動で物件を用意してくれる

9-2. StorageClassの裏側 ― CSIドライバー

StorageClassが「PVを自動作成」すると書きましたが、
実際にクラウドのストレージを操作するのは、
CSI(Container Storage Interface)ドライバーです。

ストレージ制御はCSIという標準インターフェースで分離されています。
Ingress ControllerやCoreDNSと同じ設計パターン:
「仕様」と「実装」を分離して、プラグインで差し替え可能にしています。

クラウド StorageClass例 Provisioner
AWS gp3 ebs.csi.aws.com
GCP standard pd.csi.storage.gke.io
Azure managed-premium disk.csi.azure.com
minikube standard k8s.io/minikube-hostpath

9-3. いつPVを作る? ― volumeBindingMode

モード 動作 推奨
Immediate PVC作成時にすぐPVを作成 デフォルト
WaitForFirstConsumer PodがスケジュールされてからPVを作成 ★推奨

🔰 WaitForFirstConsumer が推奨な理由: EBSはAZに紐づくため、Podの配置先が決まる前にEBSを作ると、PodとEBSが別のAZになりマウントできない事態が起きます。

🍽️ Immediate = 「先に渋谷に倉庫を借りた」→ スタッフが新宿配属に → 遠い! WaitForFirstConsumer = 「配属先が決まってから近くの倉庫を借りる」→ ✅

9-4. どんなストレージを選ぶ? ― AWS EBSボリュームタイプ

StorageClassでは「どのタイプのストレージを使うか」も指定できます。
AWS EKSの場合、EBSのボリュームタイプを選択します。

🔰 Memo:
minikubeでの学習中はボリュームタイプの選択は不要です。
本番(AWS EKS等)に進む際の参考として紹介します。

タイプ 用途 ベースIOPS コスト
gp3 汎用(★推奨) 3,000 $
gp2 汎用(旧世代) 容量×3 $
io2 高性能DB 指定 $$$
st1 ログ、ビッグデータ - ¢

gp3の優位点:
・IOPS/スループットが容量と独立して設定可能。
・10GBでもベースラインIOPS 3,000が無料で付いてきます。

ワークロード別の設計指針

ワークロード 推奨タイプ IOPS 容量目安
開発環境のDB gp3(デフォルト) 3,000 20GB
本番PostgreSQL(小規模) gp3 3,000〜6,000 50〜100GB
本番PostgreSQL(中規模) gp3 6,000〜10,000 100〜500GB
本番MySQL(高負荷) io2 10,000〜30,000 200GB〜

実務的なアプローチ

ステップ やること
① まずgp3デフォルトで始める IOPS: 3,000, スループット: 125 MB/s
② CloudWatch で監視 VolumeReadOps, VolumeWriteOps
③ ボトルネック判明後に調整 gp3はオンラインで変更可能(ダウンタイムなし)
# 本番環境用 StorageClass(gp3カスタム)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3-prod-db
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "6000"
  throughput: "250"
  encrypted: "true"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

🍽️
gp3デフォルト = 「普通の冷蔵庫」。
gp3カスタム = 「業務用冷蔵庫」。
io2 = 「超低温冷凍庫」。
まずは普通の冷蔵庫で始めて、足りなくなったら業務用に切り替える。


10. DBをk8sで動かす ― StatefulSet

セクション8-9でPV/PVCとStorageClassを学びました。
ではDBのようなステートフルなアプリをk8sで動かすには、Deploymentで十分でしょうか?
実は、DBにはDeploymentでは対応できない要件があります。

10-1. Deploymentの問題点:ステートフルなアプリ

Deploymentの特性 DBでの問題
Podの名前がランダム どのPodがマスターかわからない
起動順序が保証されない レプリカがマスターより先に起動するかも
全Podが同じPVCを共有 データ競合

10-2. Deployment vs StatefulSet

観点 Deployment StatefulSet
Pod名 ランダム 連番(db-0, db-1
起動順序 並列 順番に起動(0→1→2)
停止順序 並列 逆順に停止(2→1→0)
PVC 全Pod共有 各Podに専用PVC
DNS名 なし 各Podに固定DNS名
ユースケース Webアプリ、API DB、メッセージキュー

🍽️ Deployment = 使い捨てのアルバイトチーム(名前はニックネーム、共有の道具箱)。StatefulSet = 正社員のシェフチーム(序列がある、自分専用の包丁セットを持つ、入社順に研修)。

10-3. 各Podに固定名でアクセス ― Headless Service

StatefulSetはHeadless Serviceと組み合わせて、各Podに固定DNS名を提供します。

比較 通常のService Headless Service
ClusterIP ✅ VIPあり None
DNS応答 VIP 1つを返す 全PodのIPを返す
負荷分散 kube-proxyが振り分け ❌ クライアント側で選択
個別Podへのアクセス Pod名でアクセス可能

個別PodのDNS名

<Pod名>.<Headless Service名>.<Namespace>.svc.cluster.local
Pod DNS名 用途
db-0 db-0.db-headless.default.svc.cluster.local マスターに直接アクセス
db-1 db-1.db-headless.default.svc.cluster.local レプリカ1に直接アクセス

なぜDBにはHeadless Serviceが必要か

通常のServiceはランダム振り分けするため、書き込みがレプリカに飛ぶ可能性があります。Headless Serviceならマスターを名前で指定できます。

通信パターン DNS名 用途
マスターに書き込み db-0.db-headless 個別Pod指定
レプリカから読み取り db-headless(全Pod返る) 読み取り分散

🍽️ Headless Service = 「各シェフの個人携帯番号」→ 料理長に直接電話できる。通常のService = 「ホールの代表番号」→ 空いてるウェイターに自動でつながる。

10-4. 使い分けの判断

アプリ 選択 理由
nginx(Web) Deployment ステートレス
Rails API Deployment(+ PVC) アップロードファイルがあればPVC追加
PostgreSQL StatefulSet マスター/レプリカ構成
Elasticsearch StatefulSet 各ノードに専用データ

11. YAMLの書き方 ― ConfigMap・Secret・PVCの定義

11-1. Docker Composeとの全体対比

やりたいこと: Rails API + PostgreSQL。環境変数でDB接続情報を管理し、DBデータを永続化。

Docker Compose

services:
  api:
    image: myapp-api:1.0
    environment:
      - RAILS_ENV=production
      - DATABASE_HOST=db
      - DATABASE_PASSWORD=secretpass123
    ports:
      - "3000:3000"
  db:
    image: postgres:14
    environment:
      - POSTGRES_PASSWORD=secretpass123
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data:

k8s(責務ごとにファイル分離)

ファイル 役割 Docker Composeとの対応
configmap.yaml 一般設定 environment: の非機密部分
secret.yaml 機密情報 environment: の機密部分
pvc.yaml ストレージ要求 volumes: db-data:
deployment-api.yaml APIアプリ services: api:
deployment-db.yaml DB services: db:
service-*.yaml 通信 ports:

11-2. ConfigMap YAML

# configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
data:
  RAILS_ENV: "production"
  DATABASE_HOST: "db-service"
  DATABASE_PORT: "5432"
  LOG_LEVEL: "info"
フィールド 意味
data キー: 値のペア Podに環境変数として注入される設定値
RAILS_ENV "production" アプリの動作モード
DATABASE_HOST "db-service" DB用Service名(CoreDNSで名前解決される)

🔰 data: の値はすべて文字列で指定します(数値の 5432"5432" と書く)。

11-3. Secret YAML

# secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  POSTGRES_PASSWORD: "secretpass123"
  DATABASE_PASSWORD: "secretpass123"
フィールド 意味
type: Opaque 汎用的なSecret(他に kubernetes.io/tls 等がある)
stringData 平文で書ける(apply時に自動でBase64エンコード)
data との違い data は自分でBase64エンコードが必要

🔰 ConfigMapとの使い分け: パスワード・APIキーなど漏れたら困る値はSecret、それ以外はConfigMap。

11-4. PVC YAML

# pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-data-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard     # minikubeのデフォルト
  resources:
    requests:
      storage: 1Gi
フィールド 意味
accessModes ReadWriteOnce 1つのNodeからのみ読み書き可能
storageClassName standard minikubeのデフォルトStorageClass(動的にPVを作成)
resources.requests.storage 1Gi 要求するディスクサイズ

🔰 PVCは「ストレージの申請書」 です。PVC を作ると、StorageClass が自動でPV(実体のディスク)を割り当ててくれます。

11-5. Deployment YAML:全てを参照する

# deployment-db.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: db
  template:
    metadata:
      labels:
        app: db
    spec:
      containers:
        - name: postgres
          image: postgres:14
          ports:
            - containerPort: 5432

          # ★ ConfigMapから環境変数を一括読み込み
          envFrom:
            - configMapRef:
                name: api-config

          # ★ Secretから個別の環境変数を読み込み
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: POSTGRES_PASSWORD

          # ★ PVCをマウント
          volumeMounts:
            - name: db-storage
              mountPath: /var/lib/postgresql/data
              subPath: pgdata

      # ★ PVCをボリュームとして定義
      volumes:
        - name: db-storage
          persistentVolumeClaim:
            claimName: db-data-pvc

11-6. 参照方法の全パターン

参照方法 ConfigMap Secret 用途
全キーを環境変数 envFrom.configMapRef envFrom.secretRef まとめて読み込み
1キーだけ環境変数 env.valueFrom.configMapKeyRef env.valueFrom.secretKeyRef 特定のキーだけ
ファイルとしてマウント volumes.configMap volumes.secret 設定ファイル/証明書

11-7. Docker Compose → k8s 対応マップ

Docker Compose k8s リソース k8s YAML フィールド
environment: (一般) ConfigMap envFrom.configMapRef
environment: (機密) Secret env.valueFrom.secretKeyRef
volumes: ./file:/path ConfigMap + volumeMount volumes.configMap
volumes: vol-name:/path PVC + volumeMount volumes.persistentVolumeClaim
volumes: vol-name: (定義) PVC + StorageClass PersistentVolumeClaim

12. ハンズオン:ConfigMap・Secret・PVCを操作する

このハンズオンでは、セクション11で学んだYAMLを実際にkubectl applyして動作を確認します。

ステップ やること 確認ポイント
12-3 ConfigMap作成 設定値が保存されているか
12-4 Secret作成 Base64で保存されているか
12-5 PVC作成 StatusがBoundになるか
12-6 Deployment作成 ConfigMap/Secret/PVCが全て参照できているか
12-7 データ永続化テスト Pod削除後もデータが残るか

🍽️ 設定メモ(ConfigMap)→ 金庫の暗証番号(Secret)→ 食材倉庫(PVC)→ 全部使って店舗オープン(Deployment)→ 店舗を建て替えても食材は残る(永続化テスト)

12-1. 作業ディレクトリ

# ホームディレクトリで実行
cd ~
mkdir -p k8s-practice/config-secret-pv
cd k8s-practice/config-secret-pv

12-2. この記事で作成するファイル

~/k8s-practice/
└── config-secret-pv/             ← 今回はここ
    ├── configmap.yaml
    ├── secret.yaml
    ├── pvc.yaml
    └── deployment-db.yaml

12-3. ConfigMapの作成と確認

# configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  RAILS_ENV: "production"
  DATABASE_HOST: "db-service"
  LOG_LEVEL: "info"

🔰 ConfigMap = 環境変数の設定ファイル。 Podに注入すると、アプリから process.env.DATABASE_HOST のように使える。

# ConfigMap作成
kubectl apply -f configmap.yaml

# 確認
kubectl get configmap app-config

# 中身を確認
kubectl describe configmap app-config

期待される出力:

Name:         app-config
Data
====
DATABASE_HOST:  db-service
LOG_LEVEL:      info
RAILS_ENV:      production

12-4. Secretの作成と確認

# secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  POSTGRES_PASSWORD: "secretpass123"

🔰 stringData で平文のまま書ける。 apply後は自動でBase64エンコードされ、data フィールドに格納される。

# Secret作成
kubectl apply -f secret.yaml

# 確認(値はBase64で表示される)
kubectl get secret db-secret -o yaml

期待される出力(抜粋):

data:
  POSTGRES_PASSWORD: c2VjcmV0cGFzczEyMw==
# Base64デコードで元の値を確認
kubectl get secret db-secret -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d
# → secretpass123

12-5. PVCの作成と確認

# pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-data-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 1Gi

🔰 PVCを作成すると、StorageClassが自動でディスク(PV)を確保してくれる。 Pod削除後もデータは残る。

# PVC作成
kubectl apply -f pvc.yaml

# 確認
kubectl get pvc db-data-pvc

期待される出力:

NAME          STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
db-data-pvc   Bound    pvc-xxx    1Gi        RWO            standard       10s

🔰 STATUS が Bound になればOK。PVが自動作成されてバインドされています。

12-6. 全てを組み合わせたDeployment

# deployment-db.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: db
  template:
    metadata:
      labels:
        app: db
    spec:
      containers:
        - name: postgres
          image: postgres:14
          ports:
            - containerPort: 5432
          envFrom:
            - configMapRef:
                name: app-config
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: POSTGRES_PASSWORD
          volumeMounts:
            - name: db-storage
              mountPath: /var/lib/postgresql/data
              subPath: pgdata
      volumes:
        - name: db-storage
          persistentVolumeClaim:
            claimName: db-data-pvc
# Deployment作成
kubectl apply -f deployment-db.yaml

# Pod確認
kubectl get pods

# Pod内の環境変数を確認
kubectl exec -it $(kubectl get pods -l app=db -o jsonpath='{.items[0].metadata.name}') -- env | grep -E "RAILS_ENV|DATABASE_HOST|POSTGRES_PASSWORD"

期待される出力:

RAILS_ENV=production
DATABASE_HOST=db-service
POSTGRES_PASSWORD=secretpass123

12-7. データの永続化を確認

# Pod内にテストデータを作成
kubectl exec -it $(kubectl get pods -l app=db -o jsonpath='{.items[0].metadata.name}') -- psql -U postgres -c "CREATE TABLE test (id int, name text);"
kubectl exec -it $(kubectl get pods -l app=db -o jsonpath='{.items[0].metadata.name}') -- psql -U postgres -c "INSERT INTO test VALUES (1, 'hello');"

# Podを削除(Deploymentが自動再作成)
kubectl delete pod -l app=db

# 新しいPodが起動するのを待つ
kubectl get pods --watch

# データが残っているか確認
kubectl exec -it $(kubectl get pods -l app=db -o jsonpath='{.items[0].metadata.name}') -- psql -U postgres -c "SELECT * FROM test;"

期待される出力:

 id | name
----+-------
  1 | hello

🔰 Podを削除してもPVCがデータを保持しているため、新しいPodでデータが復元されます。

12-8. お片付け

# 全リソースを削除
kubectl delete deployment db
kubectl delete pvc db-data-pvc
kubectl delete secret db-secret
kubectl delete configmap app-config

# 確認
kubectl get all
kubectl get pvc
kubectl get configmap
kubectl get secret

13. まとめ

13-1. 本記事で学んだこと

# 学んだこと キーポイント
分離の必要性 Docker Composeの全部入りから、k8sの責務分離(ConfigMap/Secret/PV)へ
ConfigMap 一般設定の外部化。環境変数注入 or ファイルマウント。共有パターン
Secret 機密情報版ConfigMap。Base64は暗号化ではない。保護レイヤーの理解
Secret運用 etcd暗号化、Sealed Secrets、External Secrets Operator
PV/PVC ストレージの実体(PV)と要求(PVC)の分離。ReclaimPolicy
StorageClass 動的プロビジョニング。CSI。volumeBindingMode
StatefulSet DB向け。連番Pod名、順序付き起動、各Podに専用PVC、Headless Service

13-2. ゴールの達成確認

# ゴール 達成状況
なぜ分離するかを説明できる ✅ セクション4で解説
ConfigMapの2つの使い方を実践できる ✅ セクション5, 11で解説
SecretとConfigMapの違いを説明できる ✅ セクション6-7で解説
PV/PVCとStorageClassを説明できる ✅ セクション8-9で解説
DeploymentとStatefulSetの使い分け ✅ セクション10で解説

13-3. 次回予告

第5回:模擬プロジェクト — 全概念を組み合わせて実践

次回は、第1回〜第4回で学んだ全概念(Deployment, Service, Ingress, ConfigMap, Secret, PVC)を組み合わせて、実践的なアプリケーションをk8s上に構築します。Docker Composeで作れるレベルのアプリを、k8sで一から構築する体験を通じて、各リソースの関係性と設計判断を体感します。


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?