Open11

Kubernetes 学習ログ

glaciermeltglaciermelt

kubectl

https://kubernetes.io/ja/docs/reference/kubectl/

kubectlはKubernetesクラスターを操作するためのコマンドラインツールです。

インストール

brew install kubectl

https://kubernetes.io/ja/docs/tasks/tools/install-kubectl-macos/#install-with-homebrew-on-macos

基本コマンド

# クラスター情報を確認
kubectl cluster-info

# ノード一覧を表示
kubectl get nodes

# Pod一覧を表示
kubectl get pods

# 詳細情報を表示
kubectl describe pod <pod-name>
glaciermeltglaciermelt

Minikube

MinikubeはローカルでKubernetesクラスターを簡単に構築できるツールです。

https://kubernetes.io/ja/docs/tutorials/hello-minikube/

インストールと起動

# macOS
brew install minikube

# クラスター開始
minikube start

# 状態確認
minikube status

# ダッシュボード起動
minikube dashboard

brew install minikube

$ brew install minikube

==> Downloading https://formulae.brew.sh/api/formula.jws.json
==> Downloading https://formulae.brew.sh/api/cask.jws.json
==> Downloading https://ghcr.io/v2/homebrew/core/minikube/manifests/1.36.0
################################################################################################################################################################################################### 100.0%
==> Fetching minikube
==> Downloading https://ghcr.io/v2/homebrew/core/minikube/blobs/sha256:e9a0f9e6e9218387985c3dd006b85fbfd8a83f76578902da2bc15a3753bd2839
################################################################################################################################################################################################### 100.0%
==> Pouring minikube--1.36.0.arm64_sequoia.bottle.tar.gz
🍺  /opt/homebrew/Cellar/minikube/1.36.0: 10 files, 124.6MB
==> Running `brew cleanup minikube`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Caveats
zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions

minikube start

$ minikube start
😄  Darwin 15.3.2 (arm64) 上の minikube v1.36.0
✨  docker ドライバーが自動的に選択されました。他の選択肢 : virtualbox, ssh
📌  root 権限を持つ Docker Desktop ドライバーを使用
👍   Starting "minikube" primary control-plane node in "minikube" cluster
🚜   Pulling base image v0.0.47 ...
💾  ロード済み Kubernetes v1.33.1 をダウンロードしています ...
    > preloaded-images-k8s-v18-v1...:  327.15 MiB / 327.15 MiB  100.00% 35.29 M
    > gcr.io/k8s-minikube/kicbase...:  463.69 MiB / 463.69 MiB  100.00% 13.74 M
🔥  Creating docker container (CPUs=2, Memory=7889MB) ...|
🐳  Docker 28.1.1 で Kubernetes v1.33.1 を準備しています...
    ▪ 証明書と鍵を作成しています...
    ▪ コントロールプレーンを起動しています...
    ▪ RBAC のルールを設定中です...
🔗  bridge CNI (コンテナーネットワークインターフェース) を設定中です ...
🔎  Kubernetes コンポーネントを検証しています ...
    ▪ gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
🌟  有効なアドオン : storage-provisioner, default-storageclass
🏄  終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました

minikube status

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

minikube dashboard

$ minikube dashboard
🔌  ダッシュボードを有効化しています...
    ▪ docker.io/kubernetesui/metrics-scraper:v1.0.8 イメージを使用しています
    ▪ docker.io/kubernetesui/dashboard:v2.7.0 イメージを使用しています
💡  Some dashboard features require the metrics-server addon. To enable all features please run:

        minikube addons enable metrics-server

🤔  ダッシュボードの状態を検証しています...
🚀  プロキシーを起動しています...
🤔  プロキシーの状態を検証しています...
🎉  デフォルトブラウザーで http://127.0.0.1:55379/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ を開いています...

Pod と Node の理解

Node(ノード)

Kubernetesクラスターの物理的または仮想的なマシンです。複数のPodを実行できます。

Pod(ポッド)

Kubernetesの最小デプロイ単位で、1つ以上のコンテナを含みます。同じPod内のコンテナはネットワークとストレージを共有します。

Deployment 作成

DeploymentはPodの宣言的な管理を行い、スケーリングやローリングアップデートを簡単に実現できます。

# Deployment 作成
# Webサーバーを含むテストコンテナイメージを実行する
kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.39 -- /agnhost netexec --http-port=8080

# Deployment 確認
kubectl get deployments

# Pod 確認
kubectl get pods

# クラスターイベント確認
kubectl get events

# kubectl設定確認
kubectl config view

# Pod で実行されているコンテナのアプリケーションログ確認
kubectl logs <pod-name>

kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.39 -- /agnhost netexec --http-port=8080

$ kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.39 -- /agnhost netexec --http-port=8080
deployment.apps/hello-node created

kubectl get deployments

$ kubectl get deployments
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
hello-node   1/1     1            1           17m

kubectl get pods

$ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
hello-node-c74958b5d-9r2rb   1/1     Running   0          20m

kubectl get events

$ kubectl get events
LAST SEEN   TYPE     REASON                    OBJECT                            MESSAGE
21m         Normal   Scheduled                 pod/hello-node-c74958b5d-9r2rb    Successfully assigned default/hello-node-c74958b5d-9r2rb to minikube
21m         Normal   Pulling                   pod/hello-node-c74958b5d-9r2rb    Pulling image "registry.k8s.io/e2e-test-images/agnhost:2.39"
21m         Normal   Pulled                    pod/hello-node-c74958b5d-9r2rb    Successfully pulled image "registry.k8s.io/e2e-test-images/agnhost:2.39" in 3.401s (3.401s including waiting). Image size: 127408057 bytes.
21m         Normal   Created                   pod/hello-node-c74958b5d-9r2rb    Created container: agnhost
21m         Normal   Started                   pod/hello-node-c74958b5d-9r2rb    Started container agnhost
21m         Normal   SuccessfulCreate          replicaset/hello-node-c74958b5d   Created pod: hello-node-c74958b5d-9r2rb
21m         Normal   ScalingReplicaSet         deployment/hello-node             Scaled up replica set hello-node-c74958b5d from 0 to 1
29m         Normal   Starting                  node/minikube                     Starting kubelet.
29m         Normal   NodeHasSufficientMemory   node/minikube                     Node minikube status is now: NodeHasSufficientMemory
29m         Normal   NodeHasNoDiskPressure     node/minikube                     Node minikube status is now: NodeHasNoDiskPressure
29m         Normal   NodeHasSufficientPID      node/minikube                     Node minikube status is now: NodeHasSufficientPID
29m         Normal   NodeAllocatableEnforced   node/minikube                     Updated Node Allocatable limit across pods
29m         Normal   Starting                  node/minikube                     Starting kubelet.
29m         Normal   NodeAllocatableEnforced   node/minikube                     Updated Node Allocatable limit across pods
29m         Normal   NodeHasSufficientMemory   node/minikube                     Node minikube status is now: NodeHasSufficientMemory
29m         Normal   NodeHasNoDiskPressure     node/minikube                     Node minikube status is now: NodeHasNoDiskPressure
29m         Normal   NodeHasSufficientPID      node/minikube                     Node minikube status is now: NodeHasSufficientPID
29m         Normal   RegisteredNode            node/minikube                     Node minikube event: Registered Node minikube in Controller

kubectl config view

$ kubectl config view

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /Users/glaciermelt/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Sat, 14 Jun 2025 09:07:06 JST
        provider: minikube.sigs.k8s.io
        version: v1.36.0
      name: cluster_info
    server: https://127.0.0.1:55306
  name: minikube
contexts:
- context:
    cluster: minikube
    extensions:
    - extension:
        last-update: Sat, 14 Jun 2025 09:07:06 JST
        provider: minikube.sigs.k8s.io
        version: v1.36.0
      name: context_info
    namespace: default
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /Users/glaciermelt/.minikube/profiles/minikube/client.crt
    client-key: /Users/glaciermelt/.minikube/profiles/minikube/client.key

$ kubectl logs <pod-name>

$ kubectl logs hello-node-c74958b5d-9r2rb
I0614 00:15:37.195655       1 log.go:195] Started HTTP server on port 8080
I0614 00:15:37.196060       1 log.go:195] Started UDP server on port  8081
glaciermeltglaciermelt

Service 作成

Podへの安定したアクセスを提供するためにServiceを作成します。

# Pod をインターネットに公開
# --type=LoadBalancerフラグはServiceをクラスター外部に公開したいことを示しています。
kubectl expose deployment hello-node --type=LoadBalancer --port=8080

# Service 確認
kubectl get services

# Minikube でサービスにアクセス
minikube service hello-node

kubectl expose deployment hello-node --type=LoadBalancer --port=8080

$ kubectl expose deployment hello-node --type=LoadBalancer --port=8080
service/hello-node exposed

kubectl get services

$ kubectl get services
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
hello-node   LoadBalancer   10.105.28.56   <pending>     8080:30119/TCP   112s
kubernetes   ClusterIP      10.96.0.1      <none>        443/TCP          37m

minikube service hello-node

$ minikube service hello-node
|-----------|------------|-------------|---------------------------|
| NAMESPACE |    NAME    | TARGET PORT |            URL            |
|-----------|------------|-------------|---------------------------|
| default   | hello-node |        8080 | http://192.168.49.2:30119 |
|-----------|------------|-------------|---------------------------|
🏃  hello-node サービス用のトンネルを起動しています。
|-----------|------------|-------------|------------------------|
| NAMESPACE |    NAME    | TARGET PORT |          URL           |
|-----------|------------|-------------|------------------------|
| default   | hello-node |             | http://127.0.0.1:56373 |
|-----------|------------|-------------|------------------------|
🎉  デフォルトブラウザーで default/hello-node サービスを開いています ...
❗  Docker ドライバーを darwin 上で使用しているため、実行するにはターミナルを開く必要があります。
glaciermeltglaciermelt

クリーンアップ

クラスターに作成したリソースをクリーンアップします。

# クラスターに作成したリソースをクリーンアップ
kubectl delete service hello-node
kubectl delete deployment hello-node

# minikube クラスターを停止
minikube stop

kubectl delete service hello-node

$ kubectl delete service hello-node
service "hello-node" deleted

kubectl delete deployment hello-node

$ kubectl delete deployment hello-node
deployment.apps "hello-node" deleted

minikube stop

$ minikube stop
✋  「minikube」ノードを停止しています ...
🛑  SSH 経由で「minikube」の電源をオフにしています ...
🛑  1 台のノードが停止しました。
glaciermeltglaciermelt

構築する環境の全体像

1. インフラ構成

  • Minikubeを使用したローカルKubernetes環境
  • Dockerコンテナランタイム
  • MacBook上で動作(192.168.49.2:80でアクセス可能)

2. アプリケーション構成

  • Node.jsベースのWebアプリケーション
  • /etc/hostsによる名前解決(http://sm-api.local
  • Ingressによるルーティング制御

3. Kubernetesリソース構成

ネットワーク層

  • Ingress: 外部からのHTTPアクセスを管理
  • Service (NodePort): クラスター外部からのアクセスを可能に
  • Service (ClusterIP): クラスター内部での通信
  • Service (Headless): StatefulSet用のサービス

ワークロード層

  • Deployment: ステートレスなアプリケーションのデプロイ
  • StatefulSet: ステートフルなアプリケーション(データベース等)
  • Job: バッチ処理の実行
  • CronJob: 定期的なタスクの実行
  • slack-metrics API: アプリケーション内のAPIエンドポイント
  • DBマイグレーション: アプリケーション内のマイグレーション機能

ストレージ層

  • Pod: 基本的なコンテナ実行単位(複数種類)
  • PVC (Persistent Volume Claim): 永続ストレージの要求
  • PV (Persistent Volume): 実際の永続ストレージ
  • postgres DB: アプリケーションが接続するデータベース

設定管理

  • ConfigMap: 環境変数や設定ファイルの管理
  • Secret: 機密情報の管理
glaciermeltglaciermelt

StatefulSet、PersistentVolume、PersistentVolumeClaimの関係と使い方

重要なポイントのまとめ

  1. StatefulSet = 状態を持つアプリ用のコントローラー
  • 順序付きPod名(app-0, app-1)
  • 安定したネットワークID
  • Pod毎の専用ストレージ
  1. PersistentVolume (PV) = 実際のストレージリソース
  • クラスター管理者が作成
  • 物理ストレージの抽象化
  1. PersistentVolumeClaim (PVC) = ストレージの要求書
  • 開発者が作成
  • 必要な容量・性能を指定
  1. 関係性:
StatefulSet → Pod → PVC → PV → 物理ストレージ

PostgreSQLの例で言えば、StatefulSetがデータベースPodを管理し、各PodはPVCを通じて専用のストレージ(PV)を確保することで、データの永続化を実現しています。

StatefulSet、PersistentVolume、PersistentVolumeClaim 完全ガイド

1. StatefulSet とは

1.1 概要

StatefulSetは、ステートフル(状態を持つ)アプリケーションを管理するためのKubernetesリソースです。データベース、メッセージキュー、分散システムなど、永続的なデータや一意な識別子が必要なアプリケーションに適しています。

1.2 Deployment との違い

特徴 StatefulSet Deployment
Pod名 順序付き・固定(app-0, app-1) ランダム(app-7b9f8d-x2z)
起動順序 順番に起動(0→1→2) 並列起動
削除順序 逆順に削除(2→1→0) 順不同
ストレージ Pod毎に専用PVC 共有可能
ネットワークID 安定したDNS名 変動する
用途 DB、キャッシュ等 Webアプリ等

1.3 StatefulSet の特徴

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"  # Headless Service名(必須)
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:  # PVCテンプレート
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

作成されるリソース:

  • Pod: web-0, web-1, web-2(順序付き)
  • PVC: www-web-0, www-web-1, www-web-2(Pod毎)
  • DNS: web-0.nginx, web-1.nginx, web-2.nginx

2. PersistentVolume (PV) とは

2.1 概要

PersistentVolume(PV)は、クラスター管理者が提供する物理的なストレージリソースの抽象化です。実際のストレージ(NFS、iSCSI、クラウドディスク等)をKubernetesで使用可能にします。

2.2 PV の例

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-example
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:  # ローカルストレージ(テスト用)
    path: /mnt/data

2.3 アクセスモード

モード 略称 説明
ReadWriteOnce RWO 単一ノードで読み書き可能
ReadOnlyMany ROX 複数ノードで読み取り専用
ReadWriteMany RWX 複数ノードで読み書き可能

2.4 回収ポリシー

persistentVolumeReclaimPolicy: Retain  # 選択肢
  • Retain: PVC削除後もPVとデータを保持
  • Delete: PVC削除時にPVと物理ストレージも削除
  • Recycle: データを削除してPVを再利用(非推奨)

3. PersistentVolumeClaim (PVC) とは

3.1 概要

PersistentVolumeClaim(PVC)は、ユーザーがストレージを要求するためのリソースです。必要な容量やアクセスモードを指定して、適合するPVを要求します。

3.2 PVC の例

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: manual
  selector:  # 特定のPVを選択(オプション)
    matchLabels:
      type: local

3.3 PVC のライフサイクル

[Pending] → [Bound] → [Released]
    ↓          ↓           ↓
  待機中    使用中    解放済み

4. ストレージクラス(StorageClass)

4.1 動的プロビジョニング

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs  # プロビジョナー
parameters:
  type: gp3
  iopsPerGB: "10"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

4.2 Minikube のデフォルト StorageClass

# 確認コマンド
kubectl get storageclass

# 出力例
NAME                 PROVISIONER                RECLAIMPOLICY   
standard (default)   k8s.io/minikube-hostpath   Delete

5. StatefulSet + PV/PVC の連携

5.1 完全な例:MongoDB StatefulSet

# mongodb-statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: mongodb-headless
spec:
  ports:
  - port: 27017
  clusterIP: None
  selector:
    app: mongodb
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
spec:
  serviceName: mongodb-headless
  replicas: 3
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo:5.0
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongodb-data
          mountPath: /data/db
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          value: admin
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: password
  volumeClaimTemplates:
  - metadata:
      name: mongodb-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: standard
      resources:
        requests:
          storage: 10Gi

5.2 作成されるリソースの関係

StatefulSet (mongodb)
    ├── Pod: mongodb-0
    │   └── PVC: mongodb-data-mongodb-0 → PV (自動作成)
    ├── Pod: mongodb-1
    │   └── PVC: mongodb-data-mongodb-1 → PV (自動作成)
    └── Pod: mongodb-2
        └── PVC: mongodb-data-mongodb-2 → PV (自動作成)

6. 実践的な使用例

6.1 データの永続性テスト

# データ作成
kubectl exec -it mongodb-0 -- mongo -u admin -p password --eval "
  use testdb;
  db.users.insert({name: 'John', age: 30});
"

# Pod削除
kubectl delete pod mongodb-0

# Pod再作成後、データ確認
kubectl exec -it mongodb-0 -- mongo -u admin -p password --eval "
  use testdb;
  db.users.find();
"

6.2 スケーリング時の動作

# スケールアップ
kubectl scale statefulset mongodb --replicas=5

# 新しいPVCが作成される
kubectl get pvc | grep mongodb-data
# mongodb-data-mongodb-0   Bound    pvc-xxx   10Gi
# mongodb-data-mongodb-1   Bound    pvc-yyy   10Gi
# mongodb-data-mongodb-2   Bound    pvc-zzz   10Gi
# mongodb-data-mongodb-3   Bound    pvc-aaa   10Gi  # 新規
# mongodb-data-mongodb-4   Bound    pvc-bbb   10Gi  # 新規

7. トラブルシューティング

7.1 PVC が Pending のまま

# 原因調査
kubectl describe pvc mongodb-data-mongodb-0

# よくある原因:
# 1. StorageClassが存在しない
# 2. 要求サイズが大きすぎる
# 3. アクセスモードが未対応

7.2 Pod が起動しない

# イベント確認
kubectl describe pod mongodb-0

# ログ確認
kubectl logs mongodb-0

# PVCのマウント状態確認
kubectl get pvc -o wide

8. ベストプラクティス

8.1 本番環境での推奨設定

# 1. リソース制限の設定
resources:
  requests:
    memory: "1Gi"
    cpu: "500m"
  limits:
    memory: "2Gi"
    cpu: "1000m"

# 2. Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: mongodb-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: mongodb

# 3. アンチアフィニティ
affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: app
          operator: In
          values:
          - mongodb
      topologyKey: kubernetes.io/hostname

8.2 バックアップ戦略

# CronJobでバックアップ
apiVersion: batch/v1
kind: CronJob
metadata:
  name: mongodb-backup
spec:
  schedule: "0 2 * * *"  # 毎日2時
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: mongo:5.0
            command:
            - sh
            - -c
            - |
              mongodump --host=mongodb-0.mongodb-headless \
                --username=admin \
                --password=$MONGO_PASSWORD \
                --out=/backup/$(date +%Y%m%d)
            volumeMounts:
            - name: backup
              mountPath: /backup
          volumes:
          - name: backup
            persistentVolumeClaim:
              claimName: backup-pvc

9. まとめ

使い分けガイドライン

ユースケース 推奨リソース 理由
ステートレスWebアプリ Deployment + emptyDir データ永続化不要
データベース StatefulSet + PVC 順序保証とデータ永続化
共有ストレージ Deployment + PVC (RWX) 複数Podで共有
キャッシュサーバー StatefulSet + PVC 各インスタンスが独立
ログ収集 DaemonSet + hostPath 各ノードのログアクセス

チェックリスト

  • アプリケーションの状態管理要件を理解
  • 適切なアクセスモードを選択
  • ストレージ容量を適切に見積もり
  • バックアップ・リストア手順を準備
  • 監視・アラートを設定
  • 災害復旧計画を策定
glaciermeltglaciermelt

StatefulSet により Postgres DB を構築

事前準備

  • Secret: DB 認証情報(環境変数から生成)
  • ConfigMap: PostgreSQL 設定ファイル
  • Headless Service: StatefulSet 用の Pod 間通信
  • StatefulSet: PostgreSQL 15 Alpine 版、1 レプリカ
  • PersistentVolumeClaim: 10Gi のデータ永続化

Minikube の起動

# Minikube クラスタを起動(メモリとCPUを多めに割り当て)
$ minikube start --cpus=2 --memory=4096 --driver=docker
😄  Darwin 15.3.2 (arm64) 上の minikube v1.36.0
✨  既存のプロファイルを元に、docker ドライバーを使用します
❗  既存の minikube クラスターに対して、メモリサイズを変更できません。最初にクラスターを削除してください。
👍  Starting "minikube" primary control-plane node in "minikube" cluster
🚜  Pulling base image v0.0.47 ...
🔄  「minikube」のために既存の docker container を再起動しています...
🐳  Docker 28.1.1 で Kubernetes v1.33.1 を準備しています...
🔎  Kubernetes コンポーネントを検証しています...
    ▪ docker.io/kubernetesui/dashboard:v2.7.0 イメージを使用しています
    ▪ gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
    ▪ docker.io/kubernetesui/metrics-scraper:v1.0.8 イメージを使用しています
💡  Some dashboard features require the metrics-server addon. To enable all features please run:

        minikube addons enable metrics-server

🌟  有効なアドオン: default-storageclass, storage-provisioner, dashboard
🏄  終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました

# クラスタの状態を確認
$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

2. ストレージの準備

StatefulSet では PersistentVolume が必要です。Minikube では自動的に hostPath タイプの PV が作成されます。

# デフォルトの StorageClass を確認
$ kubectl get storageclass
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           false                  13h

3. PostgreSQL StatefulSet のデプロイ

環境変数の設定

# プロジェクトルートに移動
cd /path/to/project/root

# 環境変数を設定
cp .envrc.example .envrc
vim .envrc

# direnv を使用している場合
direnv allow

Secret の生成

# Secret マニフェストを生成
./postgres/create-secret.sh

リソースのデプロイ

# すべてのリソースを適用
$ kubectl apply -f postgres/
configmap/postgres-config created
secret/postgres-secret created
service/postgres-headless created
statefulset.apps/postgres created

# デプロイの確認
$ kubectl get all -l app=postgres
NAME             READY   STATUS    RESTARTS   AGE
pod/postgres-0   0/1     Running   0          18s

$ kubectl get all -l app=postgres
NAME             READY   STATUS    RESTARTS   AGE
pod/postgres-0   1/1     Running   0          2m41s

4. 動作確認

Pod の状態確認

# Pod の詳細情報
$ kubectl describe pod postgres-0
Name:             postgres-0
Namespace:        default
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2
Start Time:       Sat, 14 Jun 2025 22:39:06 +0900
Labels:           app=postgres
                  apps.kubernetes.io/pod-index=0
                  controller-revision-hash=postgres-76d5fd8888
                  statefulset.kubernetes.io/pod-name=postgres-0
Annotations:      <none>
Status:           Running
IP:               10.244.0.9
IPs:
  IP:           10.244.0.9
Controlled By:  StatefulSet/postgres
Containers:
  postgres:
    Container ID:   docker://c8f9c8e9ca64230008a5c529610d106f4a9efc18488bd4c94c49f0a7d5d62ecc
    Image:          postgres:15-alpine
    Image ID:       docker-pullable://postgres@sha256:2985f77749c75e90d340b8538dbf55d4e5b2c5396b2f05b7add61a7d8cd50a99
    Port:           5432/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 14 Jun 2025 22:39:17 +0900
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     500m
      memory:  1Gi
    Requests:
      cpu:      250m
      memory:   512Mi
    Liveness:   exec [pg_isready -U postgres] delay=30s timeout=1s period=10s #success=1 #failure=3
    Readiness:  exec [pg_isready -U postgres] delay=5s timeout=1s period=5s #success=1 #failure=3
    Environment:
      POSTGRES_USER:      <set to the key 'POSTGRES_USER' in secret 'postgres-secret'>      Optional: false
      POSTGRES_PASSWORD:  <set to the key 'POSTGRES_PASSWORD' in secret 'postgres-secret'>  Optional: false
      POSTGRES_DB:        <set to the key 'POSTGRES_DB' in secret 'postgres-secret'>        Optional: false
      PGDATA:             /var/lib/postgresql/data/pgdata
    Mounts:
      /etc/postgresql/postgresql.conf from postgres-config (rw,path="postgresql.conf")
      /var/lib/postgresql/data from postgres-data (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-xnkjd (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True 
  Initialized                 True 
  Ready                       True 
  ContainersReady             True 
  PodScheduled                True 
Volumes:
  postgres-data:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  postgres-data-postgres-0
    ReadOnly:   false
  postgres-config:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      postgres-config
    Optional:  false
  kube-api-access-xnkjd:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    Optional:                false
    DownwardAPI:             true
QoS Class:                   Burstable
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason            Age                    From               Message
  ----     ------            ----                   ----               -------
  Warning  FailedScheduling  4m12s (x2 over 4m12s)  default-scheduler  0/1 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.
  Warning  FailedScheduling  4m12s                  default-scheduler  0/1 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.
  Normal   Scheduled         4m12s                  default-scheduler  Successfully assigned default/postgres-0 to minikube
  Normal   Pulling           4m12s                  kubelet            Pulling image "postgres:15-alpine"
  Normal   Pulled            4m2s                   kubelet            Successfully pulled image "postgres:15-alpine" in 9.823s (9.823s including waiting). Image size: 265525513 bytes.
  Normal   Created           4m2s                   kubelet            Created container: postgres
  Normal   Started           4m2s                   kubelet            Started container postgres

# ログの確認
$ kubectl logs postgres-0

The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "en_US.utf8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

fixing permissions on existing directory /var/lib/postgresql/data/pgdata ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... UTC
creating configuration files ... ok
running bootstrap script ... ok
sh: locale: not found
2025-06-14 13:39:17.984 UTC [36] WARNING:  no usable system locales were found
performing post-bootstrap initialization ... ok
initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.
syncing data to disk ... ok


Success. You can now start the database server using:

    pg_ctl -D /var/lib/postgresql/data/pgdata -l logfile start

waiting for server to start....2025-06-14 13:39:18.577 UTC [42] LOG:  starting PostgreSQL 15.13 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 14.2.0) 14.2.0, 64-bit
2025-06-14 13:39:18.578 UTC [42] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2025-06-14 13:39:18.580 UTC [45] LOG:  database system was shut down at 2025-06-14 13:39:18 UTC
2025-06-14 13:39:18.583 UTC [42] LOG:  database system is ready to accept connections
 done
server started
CREATE DATABASE


/usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*

waiting for server to shut down....2025-06-14 13:39:18.709 UTC [42] LOG:  received fast shutdown request
2025-06-14 13:39:18.711 UTC [42] LOG:  aborting any active transactions
2025-06-14 13:39:18.712 UTC [42] LOG:  background worker "logical replication launcher" (PID 48) exited with exit code 1
2025-06-14 13:39:18.743 UTC [43] LOG:  shutting down
2025-06-14 13:39:18.744 UTC [43] LOG:  checkpoint starting: shutdown immediate
2025-06-14 13:39:18.775 UTC [43] LOG:  checkpoint complete: wrote 921 buffers (5.6%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.011 s, sync=0.018 s, total=0.032 s; sync files=301, longest=0.005 s, average=0.001 s; distance=4238 kB, estimate=4238 kB
2025-06-14 13:39:18.778 UTC [42] LOG:  database system is shut down
 done
server stopped

PostgreSQL init process complete; ready for start up.

2025-06-14 13:39:18.827 UTC [1] LOG:  starting PostgreSQL 15.13 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 14.2.0) 14.2.0, 64-bit
2025-06-14 13:39:18.827 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
2025-06-14 13:39:18.827 UTC [1] LOG:  listening on IPv6 address "::", port 5432
2025-06-14 13:39:18.828 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2025-06-14 13:39:18.830 UTC [58] LOG:  database system was shut down at 2025-06-14 13:39:18 UTC
2025-06-14 13:39:18.833 UTC [1] LOG:  database system is ready to accept connections

データベースへの接続

# Pod 内から接続
$ kubectl exec -it postgres-0 -- psql -U postgres -d postgresdb
psql (15.13)
Type "help" for help.

postgresdb=# 

# ポートフォワード経由で接続
$ kubectl port-forward postgres-0 5432:5432 &
[1] 27845
Forwarding from 127.0.0.1:5432 -> 5432                                                                                                                                                                   
Forwarding from [::1]:5432 -> 5432

$ psql -h localhost -U postgres -d postgresdb
Handling connection for 5432
psql (17.2, server 15.13)
Type "help" for help.

postgresdb=# exit

5. 永続性の確認

# データを作成
$ kubectl exec -it postgres-0 -- psql -U postgres -d postgresdb -c "CREATE TABLE test (id int);"
CREATE TABLE

$ kubectl exec -it postgres-0 -- psql -U postgres -d postgresdb -c "INSERT INTO test VALUES (1);"
INSERT 0 1

# Pod を削除
$ kubectl delete pod postgres-0
pod "postgres-0" deleted

# Pod が再作成されるのを待つ
$ kubectl wait --for=condition=ready pod/postgres-0 --timeout=60s
pod/postgres-0 condition met

# データが残っていることを確認
kubectl exec -it postgres-0 -- psql -U postgres -d postgresdb -c "SELECT * FROM test;"
glaciermeltglaciermelt

Headless Service 経由でのアクセス

StatefulSet の Pod は Headless Service を通じて DNS 名でアクセスできます。

DNS 名の形式

<pod-name>.<service-name>.<namespace>.svc.cluster.local

PostgreSQL の場合:

  • postgres-0.postgres-headless.default.svc.cluster.local

テスト用クライアント Pod の作成

# クライアント Pod を作成
$ kubectl apply -f postgres/test-pod.yaml
pod/postgres-client created

# クライアント Pod から Headless Service 経由で接続
$ kubectl exec -it postgres-client -- psql -h postgres-0.postgres-headless.default.svc.cluster.local -U postgres -d postgresdb
psql (15.13)
Type "help" for help.

postgresdb=#

# または短縮形で接続
$ kubectl exec -it postgres-client -- psql -h postgres-0.postgres-headless -U postgres -d postgresdb
psql (15.13)
Type "help" for help.

postgresdb=# 

# Service 名だけでも接続可能(ラウンドロビンではなく、StatefulSet の場合は postgres-0 に接続)
kubectl exec -it postgres-client -- psql -h postgres-headless -U postgres -d postgresdb

# DNS 解決の確認
$ kubectl exec -it postgres-client -- nslookup postgres-headless
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find postgres-headless.svc.cluster.local: NXDOMAIN

** server can't find postgres-headless.cluster.local: NXDOMAIN

** server can't find postgres-headless.svc.cluster.local: NXDOMAIN


Name:   postgres-headless.default.svc.cluster.local
Address: 10.244.0.10

** server can't find postgres-headless.cluster.local: NXDOMAIN

command terminated with exit code 1

$ kubectl exec -it postgres-client -- nslookup postgres-0.postgres-headless
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find postgres-0.postgres-headless: NXDOMAIN

** server can't find postgres-0.postgres-headless: NXDOMAIN

command terminated with exit code 1
glaciermeltglaciermelt

Job とは

1.1 概要

Jobは、一度だけ実行して完了するタスク(バッチ処理)を管理するKubernetesリソースです。Podが正常に終了するまで実行を保証し、失敗した場合は再試行します。

1.2 Job の特徴

特徴 説明
一度きりの実行 タスクが完了したら終了
完了保証 成功するまで再試行
並列実行 複数のPodで並列処理可能
履歴保持 完了後もJobとPodの情報を保持

1.3 基本的な Job の例

apiVersion: batch/v1
kind: Job
metadata:
  name: hello-job
spec:
  template:
    metadata:
      name: hello-job
    spec:
      containers:
      - name: hello
        image: busybox
        command: ["sh", "-c", "echo 'Hello, Job!' && sleep 30"]
      restartPolicy: Never  # JobではNeverまたはOnFailure

2. Job の設定オプション

2.1 重要なフィールド

apiVersion: batch/v1
kind: Job
metadata:
  name: batch-job
spec:
  # 並列実行するPod数
  parallelism: 3
  
  # 成功が必要なPod数
  completions: 10
  
  # バックオフ制限(再試行回数)
  backoffLimit: 4
  
  # アクティブな期限(秒)
  activeDeadlineSeconds: 3600
  
  # 完了後のTTL(秒)
  ttlSecondsAfterFinished: 86400
  
  template:
    spec:
      containers:
      - name: worker
        image: myapp:latest
        command: ["./process.sh"]
      restartPolicy: OnFailure

2.2 restartPolicy の選択

Policy 動作 使用場面
Never Podを再作成して再試行 環境をクリーンに保ちたい場合
OnFailure 同じPod内でコンテナを再起動 高速な再試行が必要な場合

3. 実践的な Job の例

3.1 データベースマイグレーション

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration-v2
spec:
  template:
    metadata:
      labels:
        app: db-migration
        version: v2
    spec:
      containers:
      - name: migration
        image: myapp:latest
        command: ["npm", "run", "migrate"]
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: url
        - name: MIGRATION_VERSION
          value: "v2"
      restartPolicy: Never

3.2 データ処理ジョブ(並列実行)

apiVersion: batch/v1
kind: Job
metadata:
  name: data-processing
spec:
  parallelism: 5      # 同時に5つのPodを実行
  completions: 20     # 合計20個のタスクを完了
  backoffLimit: 3
  template:
    spec:
      containers:
      - name: processor
        image: data-processor:latest
        env:
        - name: TASK_INDEX
          valueFrom:
            fieldRef:
              fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
        command:
        - sh
        - -c
        - |
          echo "Processing task $TASK_INDEX"
          # タスクインデックスに基づいて処理を分割
          ./process-data.sh --partition=$TASK_INDEX --total=20
      restartPolicy: Never

3.3 バックアップジョブ

apiVersion: batch/v1
kind: Job
metadata:
  name: postgres-backup
  labels:
    app: postgres-backup
spec:
  ttlSecondsAfterFinished: 604800  # 1週間後に自動削除
  template:
    spec:
      containers:
      - name: backup
        image: postgres:15
        command:
        - sh
        - -c
        - |
          set -e
          echo "Starting backup at $(date)"
          
          # バックアップ実行
          PGPASSWORD=$POSTGRES_PASSWORD pg_dump \
            -h postgres-service \
            -U postgres \
            -d myapp \
            -f /backup/myapp-$(date +%Y%m%d-%H%M%S).sql
          
          # S3にアップロード(例)
          aws s3 cp /backup/myapp-*.sql s3://my-backup-bucket/postgres/
          
          echo "Backup completed at $(date)"
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: password
        - name: AWS_ACCESS_KEY_ID
          valueFrom:
            secretKeyRef:
              name: aws-secret
              key: access-key
        - name: AWS_SECRET_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: aws-secret
              key: secret-key
        volumeMounts:
        - name: backup
          mountPath: /backup
      volumes:
      - name: backup
        emptyDir: {}
      restartPolicy: OnFailure

4. Job パターン

4.1 Work Queue パターン

# メッセージキューから取得して処理
apiVersion: batch/v1
kind: Job
metadata:
  name: work-queue-consumer
spec:
  parallelism: 10
  completions: 100
  template:
    spec:
      containers:
      - name: worker
        image: worker:latest
        env:
        - name: QUEUE_URL
          value: "redis://redis-service:6379"
        command:
        - python
        - -c
        - |
          import redis
          import json
          import time
          
          r = redis.from_url(os.environ['QUEUE_URL'])
          
          while True:
              # キューからタスクを取得
              task = r.blpop('task_queue', timeout=30)
              if not task:
                  print("No more tasks")
                  break
              
              task_data = json.loads(task[1])
              print(f"Processing task: {task_data['id']}")
              
              # タスク処理
              process_task(task_data)
              
              # 完了マーク
              r.sadd('completed_tasks', task_data['id'])
      restartPolicy: Never

4.2 Indexed Job パターン(K8s 1.24+)

apiVersion: batch/v1
kind: Job
metadata:
  name: indexed-job
spec:
  completions: 5
  parallelism: 3
  completionMode: Indexed  # インデックス付きモード
  template:
    spec:
      containers:
      - name: worker
        image: busybox
        command:
        - sh
        - -c
        - |
          echo "My index is: $JOB_COMPLETION_INDEX"
          # インデックスに基づいて異なる処理を実行
          case $JOB_COMPLETION_INDEX in
            0) echo "Processing customer data..." ;;
            1) echo "Processing order data..." ;;
            2) echo "Processing inventory data..." ;;
            3) echo "Processing shipping data..." ;;
            4) echo "Generating reports..." ;;
          esac
          sleep 10
      restartPolicy: Never

5. Job の監視と管理

5.1 Job の状態確認

# Job一覧
kubectl get jobs

# 詳細情報
kubectl describe job hello-job

# Job のログ確認
kubectl logs -l job-name=hello-job

# 完了したPodも含めて表示
kubectl get pods -a -l job-name=hello-job

# Job の実行状況を監視
kubectl get job hello-job -w

5.2 Job の状態遷移

作成 → アクティブ → 成功/失敗
         ↓
      再試行(失敗時)

5.3 プログラムでの状態確認

# Python Kubernetes Client での例
from kubernetes import client, config

# Kubernetesクラスタに接続
config.load_incluster_config()  # Pod内から
# または
# config.load_kube_config()  # ローカルから

batch_v1 = client.BatchV1Api()

# Job の状態を確認
job = batch_v1.read_namespaced_job(
    name="my-job",
    namespace="default"
)

print(f"Active: {job.status.active}")
print(f"Succeeded: {job.status.succeeded}")
print(f"Failed: {job.status.failed}")

# 完了待機
import time
while True:
    job = batch_v1.read_namespaced_job(
        name="my-job",
        namespace="default"
    )
    if job.status.succeeded:
        print("Job completed successfully!")
        break
    elif job.status.failed:
        print("Job failed!")
        break
    time.sleep(10)

6. エラーハンドリング

6.1 再試行戦略

apiVersion: batch/v1
kind: Job
metadata:
  name: retry-job
spec:
  backoffLimit: 5  # 最大5回再試行
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
        command:
        - sh
        - -c
        - |
          # 再試行回数を確認
          RETRY_COUNT=${RETRY_COUNT:-0}
          echo "Attempt: $((RETRY_COUNT + 1))"
          
          # エクスポネンシャルバックオフ
          if [ $RETRY_COUNT -gt 0 ]; then
            SLEEP_TIME=$((2 ** RETRY_COUNT))
            echo "Waiting ${SLEEP_TIME}s before retry..."
            sleep $SLEEP_TIME
          fi
          
          # メイン処理
          ./main-task.sh || exit 1
        env:
        - name: RETRY_COUNT
          value: "0"  # Jobコントローラが管理
      restartPolicy: Never

6.2 タイムアウト設定

apiVersion: batch/v1
kind: Job
metadata:
  name: timeout-job
spec:
  activeDeadlineSeconds: 300  # 5分でタイムアウト
  template:
    spec:
      containers:
      - name: task
        image: busybox
        command: ["sleep", "600"]  # 10分スリープ(タイムアウトする)
      restartPolicy: Never

7. Job と CronJob の連携

7.1 手動で CronJob から Job を作成

# CronJob から Job を手動実行
kubectl create job manual-backup --from=cronjob/backup-cronjob

7.2 Job テンプレートの再利用

# job-template.yaml
apiVersion: batch/v1
kind: Job
metadata:
  generateName: templated-job-  # 名前を自動生成
spec:
  template:
    spec:
      containers:
      - name: task
        image: myapp:latest
        args: ["--date", "$(DATE)"]
      restartPolicy: Never

# 実行時に環境変数を注入
$ DATE=$(date +%Y%m%d) envsubst < job-template.yaml | kubectl apply -f -

8. ベストプラクティス

8.1 イディオムパターン

apiVersion: batch/v1
kind: Job
metadata:
  name: idempotent-job
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
        command:
        - sh
        - -c
        - |
          # イディオムポテント(冪等)な処理
          JOB_ID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 8)
          
          # 既に処理済みかチェック
          if exists_in_database "$JOB_ID"; then
            echo "Job $JOB_ID already processed"
            exit 0
          fi
          
          # メイン処理
          process_data
          
          # 完了マーク
          mark_as_completed "$JOB_ID"
      restartPolicy: OnFailure

8.2 リソース管理

apiVersion: batch/v1
kind: Job
metadata:
  name: resource-aware-job
spec:
  parallelism: 5
  template:
    spec:
      containers:
      - name: processor
        image: processor:latest
        resources:
          requests:
            memory: "1Gi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1000m"
      # ノードセレクタで特定のノードで実行
      nodeSelector:
        workload-type: batch
      # Tolerationでtaintedノードでも実行可能に
      tolerations:
      - key: "batch-only"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"
      restartPolicy: Never

8.3 クリーンアップ戦略

# 自動クリーンアップ
apiVersion: batch/v1
kind: Job
metadata:
  name: auto-cleanup-job
spec:
  ttlSecondsAfterFinished: 3600  # 完了後1時間で自動削除
  successfulJobsHistoryLimit: 3   # 成功したJobを3つまで保持
  failedJobsHistoryLimit: 1       # 失敗したJobを1つまで保持
  template:
    spec:
      containers:
      - name: task
        image: busybox
        command: ["echo", "Done"]
      restartPolicy: Never

9. Job のデバッグ

9.1 失敗の調査

# 失敗したJobの詳細確認
kubectl describe job failed-job

# Podのイベント確認
kubectl get events --field-selector involvedObject.name=failed-job-xxxxx

# 失敗したPodのログ確認
kubectl logs job/failed-job --all-containers=true

# 前回の実行ログ(コンテナが再起動した場合)
kubectl logs job/failed-job --previous

9.2 デバッグ用の設定

apiVersion: batch/v1
kind: Job
metadata:
  name: debug-job
spec:
  backoffLimit: 0  # 再試行しない(デバッグ用)
  template:
    spec:
      containers:
      - name: debug
        image: myapp:debug  # デバッグツール入りイメージ
        command: ["sh", "-c"]
        args:
        - |
          set -x  # コマンドを表示
          echo "Starting debug job..."
          
          # 環境変数を出力
          env | sort
          
          # ファイルシステムを確認
          ls -la /app/
          
          # メイン処理(エラー時は詳細を表示)
          ./main.sh || {
            echo "Failed with exit code: $?"
            # デバッグ情報を収集
            cat /tmp/debug.log
            exit 1
          }
      restartPolicy: Never

10. まとめ

Job を使うべき場合

ユースケース
データ処理 ETL、バッチ集計、レポート生成
メンテナンス DB移行、バックアップ、クリーンアップ
初期化処理 データロード、環境セットアップ
定期タスク CronJobと組み合わせた定期実行

チェックリスト

  • 適切な restartPolicy を選択(Never or OnFailure)
  • backoffLimit で再試行回数を制限
  • activeDeadlineSeconds でタイムアウトを設定
  • ttlSecondsAfterFinished で自動クリーンアップ
  • リソース制限を適切に設定
  • ログとモニタリングの仕組みを準備
  • イディオムポテントな処理設計
  • エラーハンドリングとリトライ戦略
glaciermeltglaciermelt

minikubeでDockerイメージを参照する方法

1. minikubeの内部Dockerデーモンを使用する方法

これが最も一般的な方法です。

# minikubeのDockerデーモンを使うように環境変数を設定
eval $(minikube docker-env)

# この状態でDockerイメージをビルド
docker build -t my-app:latest .

# 確認
docker images

eval $(minikube docker-env)を実行すると、ローカルのDockerクライアントがminikube内のDockerデーモンを使うようになります。

2. イメージをminikubeにロードする方法

既存のDockerイメージをminikubeに転送する場合:

# ローカルでイメージをビルド
docker build -t my-app:latest .

# minikubeにイメージをロード
minikube image load my-app:latest

3. Podで使用する際の注意点

minikube内のイメージを使う場合、imagePullPolicyNeverに設定する必要があります:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-app:latest
    imagePullPolicy: Never  # 重要:外部レジストリから取得しない

4. 環境を元に戻す

作業が終わったら、環境変数を元に戻します:

eval $(minikube docker-env -u)