Kubernetes 入門3 [ Deployment、ReplicaSet、Service、宣言的YAML ]


## 概要

この記事では、minikubeを使ってKubernetesの基本的なリソースを実際に作成・操作しながら学習します。Deployment、ReplicaSet、Service、そしてストレージ管理について、宣言的YAML管理を中心とした実践的なハンズオンを行います。

## 前提条件

- Docker Desktop または Docker がインストール済み
- minikube がインストール済み
- kubectl がインストール済み

## 1. 環境準備

### minikubeクラスターの起動

```bash
# minikubeクラスターを起動
minikube start

# クラスターの状態確認
kubectl cluster-info

# ノードの確認
kubectl get nodes
```

## 2. Namespace による名前空間管理

### 2.1 Namespaceとは

Namespaceは、Kubernetesクラスター内のリソースを論理的に分離するための仕組みです。一つのクラスター内で複数のプロジェクトや環境を管理する際に使用します。

**主な特徴：**
- リソース名の重複を回避
- アクセス制御の境界
- リソースクォータの適用単位
- ネットワークポリシーの適用範囲

**デフォルトNamespace：**
```bash
# デフォルトで存在するNamespaceを確認
kubectl get namespaces
```

通常、以下のNamespaceが初期状態で存在します：
- `default`: 明示的にNamespaceを指定しない場合のデフォルト
- `kube-system`: Kubernetesシステムコンポーネント用
- `kube-public`: 全ユーザーが読み取り可能な公開リソース用
- `kube-node-lease`: ノードのハートビート情報用

### 2.2 Namespaceの作成と管理

```yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: hands-on
  labels:
    purpose: tutorial
    environment: development
  annotations:
    description: "Kubernetes hands-on tutorial namespace"
```

コメントを追加したバージョン
```yaml
# Kubernetesの設定ファイルのバージョンを指定
# v1は最も基本的で安定したバージョン
apiVersion: v1

# 作成するリソースの種類を指定
# Namespaceは「名前空間」という意味で、リソースをグループ分けするための仕組み
kind: Namespace

# このリソースに関する情報（メタデータ）を定義
metadata:
  # Namespaceの名前を指定
  # この名前でKubernetes内でこのNamespaceを識別する
  name: hands-on

  # ラベル：リソースに付ける「タグ」のようなもの
  # 後で検索や管理がしやすくなる
  labels:
    # このNamespaceの目的を示すラベル
    purpose: tutorial
    # 環境の種類を示すラベル（開発環境、本番環境など）
    environment: development

  # アノテーション：ラベルよりも詳細な情報を記録
  # 人間が読むための説明やメモとして使用
  annotations:
    # このNamespaceの説明文
    description: "Kubernetes hands-on tutorial namespace"
```

```bash
# Yamlファイルの情報に従ってNamespace作成
kubectl apply -f namespace.yaml

# コマンドラインからnamespaceを作成する
kubectl create namespace production
kubectl create namespace staging

# Namespace確認
kubectl get namespaces

# Namespace詳細確認 describe(説明する)
kubectl describe namespace hands-on

# ラベル情報も含めてNamespaceの一覧を見やすく表示するコマンド
# -L : ラベルを追加の列として表示するオプション
# purpose,environment : 表示したいラベルの名前
kubectl get namespaces -L purpose,environment
```

### 2.3 Namespaceを使った運用

```bash
# 特定のNamespace内のリソース確認
kubectl get pods -n hands-on
kubectl get all -n hands-on

# デフォルトNamespaceの変更
kubectl config set-context --current --namespace=hands-on

# 現在のNamespace確認
# kubectl config view --minify の出力から namespace 行のみ抽出
# パイプ（|） は「左のコマンドの結果を右のコマンドに渡す」仕組みです。
# grep は「指定した文字列を含む行だけを抽出する」コマンドです。
kubectl config view --minify | grep namespace

# 全Namespace横断でのリソース確認
kubectl get pods --all-namespaces
kubectl get pods -A  # 短縮形
```

## 3. Deployment によるアプリケーション管理

### 3.1 基本的なDeployment

Nginxアプリケーションを3つのレプリカで展開します。

```yaml
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: hands-on
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
```

```bash
# Deployment作成
kubectl apply -f nginx-deployment.yaml

# Deployment確認
kubectl get deployments -n hands-on

# Pod確認
kubectl get pods -n hands-on

# ReplicaSetの自動作成確認
kubectl get replicasets -n hands-on
```

クラスターないからnginxのpodに接続確認
```
kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
```
```
curl 10.244.0.39
```
成功レスポンス
```
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

### 3.2 Deploymentの更新とロールバック

```bash
# イメージの更新
kubectl set image deployment/nginx-deployment nginx=nginx:1.22 -n hands-on

# ロールアウト状況の確認
kubectl rollout status deployment/nginx-deployment -n hands-on

# ロールアウト履歴の確認
kubectl rollout history deployment/nginx-deployment -n hands-on

# 前のバージョンにロールバック
kubectl rollout undo deployment/nginx-deployment -n hands-on
```

### 3.3 スケーリング
**HAP(Horizontal Pod Autoscaler)**
**HPA**は「水平Pod自動スケーラー」という意味で、負荷に応じてPodの数を自動的に増減する仕組みです。

```bash
# レプリカ数の変更
kubectl scale deployment nginx-deployment --replicas=5 -n hands-on

# オートスケーリング（HPA）の設定
kubectl autoscale deployment nginx-deployment --cpu-percent=70 --min=2 --max=10 -n hands-on

# HPA確認
kubectl get hpa -n hands-on
```

```
# スケーリングの種類

# 【水平スケーリング（Horizontal Scaling）】
# = Pod数を増減する方法（HPAが対応）
# 
# 負荷が高い時：
# Pod1 → Pod1 + Pod2 + Pod3（Pod数を増やす）
# 
# 負荷が低い時：
# Pod1 + Pod2 + Pod3 → Pod1（Pod数を減らす）

# 【垂直スケーリング（Vertical Scaling）】
# = 個々のPodのリソース（CPU/メモリ）を増減する方法
# 
# 負荷が高い時：
# Pod（CPU: 100m） → Pod（CPU: 500m）（リソースを増やす）
# 
# 負荷が低い時：
# Pod（CPU: 500m） → Pod（CPU: 100m）（リソースを減らす）

# Kubernetesでは主に水平スケーリング（HPA）が使われる理由：
# ✅ Pod追加/削除は比較的安全
# ✅ 障害時の影響範囲を限定できる
# ✅ より柔軟な負荷分散が可能
```

## 4. Service によるネットワーク管理

### 4.1 ClusterIP Service

```yaml
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: hands-on
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
```

```yaml 
# Kubernetes Service設定ファイル
# Service = 複数のPodへのアクセスを管理する「受付窓口」

apiVersion: v1               # KubernetesのAPIバージョン
kind: Service                # リソースの種類：Service（サービス）

# このServiceに関する基本情報
metadata:
  name: nginx-service        # このServiceの名前（他から呼び出す時に使用）
  namespace: hands-on        # どのNamespace内に作成するか

# Serviceの動作設定
spec:
  # どのPodを対象にするかを決める「選択条件」
  selector:
    app: nginx              # ラベルが「app: nginx」のPodを対象にする
                           # ※対象Podには「app: nginx」ラベルが必要

  # ネットワーク接続の設定
  ports:
  - protocol: TCP           # 通信プロトコル（TCP/UDP）
    port: 80               # Serviceが受け付けるポート番号
                          # 他のPodやサービスがアクセスする時のポート
    targetPort: 80         # 実際のPod内のアプリが動いているポート番号
                          # nginxコンテナ内でWebサーバーが80番で動作

  # Serviceの公開方法を指定
  type: ClusterIP          # ClusterIP = クラスター内部のみでアクセス可能
                          # 外部のインターネットからは直接アクセス不可

# 【重要】このServiceが動作するには：
# 1. 対象のPodに「app: nginx」ラベルが付いている必要がある
# 2. 対象のPod内で80番ポートでアプリケーションが動作している必要がある
```

```bash
# Service作成
kubectl apply -f nginx-service.yaml

# Service確認
kubectl get services -n hands-on

# Serviceの詳細確認
kubectl describe service nginx-service -n hands-on
```

### 4.2 NodePort Service

```yaml
# nginx-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
  namespace: hands-on
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30080
  type: NodePort
```
詳細なバージョン
```
# Kubernetesリソースのバージョンを指定
# v1は安定版のAPIバージョン
apiVersion: v1

# 作成するリソースの種類を指定
# Serviceはアプリケーションへのアクセス方法を定義する
kind: Service

# このサービスの基本情報
metadata:
  # サービス名（他のリソースからこの名前で参照される）
  name: nginx-nodeport
  # 配置する名前空間（リソースを整理するためのグループ）
  namespace: hands-on

# サービスの詳細設定
spec:
  # このサービスがどのPodに通信を転送するかを決める条件
  # app: nginxラベルが付いたPodにトラフィックを送る
  selector:
    app: nginx
  
  # ポート設定（複数設定可能）
  ports:
  # 使用するプロトコル（TCP or UDP）
  - protocol: TCP
    # サービス内で使用するポート番号
    # 他のPodからこのサービスにアクセスする時のポート
    port: 80
    # 実際のPod（nginx）が待ち受けているポート番号
    # nginxは通常80番ポートでWebサーバーが動いている
    targetPort: 80
    # 外部からアクセスする時のポート番号
    # ブラウザで http://ノードのIP:30080 でアクセス可能
    # 30000-32767の範囲で指定する必要がある
    nodePort: 30080
  
  # サービスのタイプを指定
  # NodePort = 各ノード（サーバー）の特定ポートで外部公開
  type: NodePort
```

```bash
# NodePort Service作成
kubectl apply -f nginx-nodeport.yaml

# minikubeでサービスアクセス
minikube service nginx-nodeport -n hands-on --url
```

## 5. ConfigMap と Secret による設定管理

### 5.1 ConfigMap
ConfigMapは平文の設定データを保存するKubernetesリソースです。

**特徴と用途**
- アプリケーションの設定ファイルや環境変数を外部化
- 機密性のないデータ（データベースホスト名、ポート番号、ログレベルなど）
- Podから環境変数やボリュームマウントとして利用可能

**ボリュームマウント**は、外部のデータストレージをコンテナ内のファイルシステムに接続する仕組みです。ConfigMapやSecretをファイルとしてコンテナ内で利用できます。

```yaml
# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config          # ConfigMap名
  namespace: hands-on       # 名前空間
data:
  # キー: 値の形式で設定データを格納
  app.properties: |         # プロパティファイル形式
    database.host=localhost
    database.port=5432
    log.level=INFO
  nginx.conf: |            # 設定ファイル全体を格納
    server {
        listen 80;
        server_name localhost;
        location / {
            root /usr/share/nginx/html;
            index index.html;
        }
    }
```

### 5.2 Secret（秘密情報）
Secretは機密データを安全に保存するKubernetesリソースです。

**特徴と用途**
- パスワード、APIキー、証明書などの機密情報
- データはBase64エンコードされて保存
- etcdで暗号化して保存（設定により）


```yaml
# app-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
  namespace: hands-on
type: Opaque
data:
  # base64エンコード済み値
  username: YWRtaW4=  # admin
  password: cGFzc3dvcmQ=  # password
```

エンコード方法
```
# コマンドラインでBase64エンコード
echo -n "admin" | base64
# 結果: YWRtaW4=

echo -n "password" | base64  
# 結果: cGFzc3dvcmQ=
```

デコード確認
```
# Base64デコードして確認
echo "YWRtaW4=" | base64 -d
# 結果: admin

echo "cGFzc3dvcmQ=" | base64 -d
# 結果: password
```

リソース作成と確認
```bash
# ConfigMapとSecret作成
kubectl apply -f app-config.yaml
kubectl apply -f app-secret.yaml

# 確認
kubectl get configmaps -n hands-on
kubectl get secrets -n hands-on

# 詳細確認
kubectl describe configmap app-config -n hands-on
kubectl describe secret app-secret -n hands-on
```

### 5.3 ConfigMapとSecretを使用するDeployment

```yaml
# app-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-config
  namespace: hands-on
spec:
  replicas: 2
  selector:
    matchLabels:
      app: config-app
  template:
    metadata:
      labels:
        app: config-app
    spec:
      containers:
      - name: app
        image: nginx:1.21
        env:
        - name: DATABASE_USER
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: username
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: password
        volumeMounts:
        - name: config-volume
          mountPath: /etc/config
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
      volumes:
      - name: config-volume
        configMap:
          name: app-config
          items:
          - key: app.properties
            path: app.properties
      - name: nginx-config
        configMap:
          name: app-config
          items:
          - key: nginx.conf
            path: default.conf
```
詳細バージョン
```yaml
# ConfigMapとSecretを使用したアプリケーションのデプロイメント設定
apiVersion: apps/v1              # Kubernetes APIバージョン
kind: Deployment                 # リソース種類: アプリケーションのデプロイメント
metadata:                        # このリソースの基本情報
  name: app-with-config          # Deploymentの名前
  namespace: hands-on            # 配置先の名前空間（プロジェクト単位）
spec:                           # Deploymentの詳細設定
  replicas: 2                   # 起動するPod数（同じアプリを2つ実行）
  selector:                     # このDeploymentが管理するPodの選択条件
    matchLabels:                # ラベルでPodを識別
      app: config-app           # "app: config-app"ラベルを持つPodを管理対象とする
  template:                     # 作成するPodのテンプレート（設計図）
    metadata:                   # 作成されるPodの基本情報
      labels:                   # Podに付与するラベル（識別タグ）
        app: config-app         # 上記selectorと一致するラベル
    spec:                       # Podの詳細設定
      containers:               # Pod内で実行するコンテナの一覧
      - name: app               # コンテナの名前
        image: nginx:1.21       # 使用するDockerイメージ（Nginx Webサーバー v1.21）
        
        # 環境変数の設定（Secretから機密情報を取得）
        env:
        - name: DATABASE_USER     # コンテナ内で使用する環境変数名
          valueFrom:              # 値の取得元を指定
            secretKeyRef:         # Secretリソースから取得
              name: app-secret    # 参照するSecret名
              key: username       # Secretの中の特定のキー
        - name: DATABASE_PASSWORD # データベースパスワード用環境変数
          valueFrom:
            secretKeyRef:
              name: app-secret    # 同じSecretリソースから
              key: password       # パスワードが格納されているキー
        
        # ボリュームマウント設定（外部ファイルをコンテナ内にマウント）
        volumeMounts:
        - name: config-volume     # マウントするボリューム名（下記volumesで定義）
          mountPath: /etc/config  # コンテナ内でのマウント先パス
        - name: nginx-config      # Nginx設定ファイル用ボリューム
          mountPath: /etc/nginx/conf.d  # Nginxの設定ディレクトリにマウント
      
      # ボリューム定義（ConfigMapをファイルとして利用）
      volumes:
      - name: config-volume       # ボリューム名（上記volumeMountsで参照）
        configMap:                # ConfigMapをボリュームソースとして使用
          name: app-config        # 参照するConfigMap名
          items:                  # ConfigMapの特定のキーのみを選択
          - key: app.properties   # ConfigMapに格納されているキー名
            path: app.properties  # マウント先でのファイル名
      - name: nginx-config        # Nginx設定用ボリューム
        configMap:
          name: app-config        # 同じConfigMapを参照
          items:
          - key: nginx.conf       # Nginx設定が格納されているキー
            path: default.conf    # Nginxが読み込む設定ファイル名
```

アプリケーションデプロイ
```bash 
# Deployment作成
kubectl apply -f app-with-config.yaml

# 確認
kubectl get deployments -n hands-on
kubectl get pods -n hands-on
```

動作確認
```bash 
# Pod内でファイル確認
kubectl exec -it $(kubectl get pods -n hands-on -l app=config-app -o jsonpath='{.items[0].metadata.name}') -n hands-on -- ls /etc/config/

kubectl exec -it $(kubectl get pods -n hands-on -l app=config-app -o jsonpath='{.items[0].metadata.name}') -n hands-on -- cat /etc/config/app.properties

# 環境変数確認
kubectl exec -it $(kubectl get pods -n hands-on -l app=config-app -o jsonpath='{.items[0].metadata.name}') -n hands-on -- env | grep DATABASE
```

## 6. ストレージ管理
### 6.1 なぜストレージ管理が必要？

通常のPodは「一時的」な存在です。Podが削除されると、その中のデータも一緒に消えてしまいます。しかし、データベースやファイルサーバーなど、データを永続的に保存する必要があるアプリケーションでは、この問題を解決する必要があります。

**問題の例：**
- MySQLのデータベース内容
- ファイルのアップロード
- ログファイル
- 設定ファイル

これらのデータは、Podが再起動しても保持される必要があります。

### 6.2 Kubernetesのストレージソリューション

Kubernetesでは以下の仕組みでストレージ問題を解決します：

1. **PersistentVolume (PV)** - 物理的なストレージリソース
2. **PersistentVolumeClaim (PVC)** - ストレージの利用申請
3. **StorageClass** - ストレージの種類定義
4. **StatefulSet** - 状態を持つアプリケーションの管理

### PersistentVolume (PV) の詳細解説
#### PVとは何か？

PersistentVolume（永続ボリューム）は、クラスター内の物理的なストレージリソースです。管理者が事前に用意したり、動的に作成されたりします。

#### PVの設定例と解説

```yaml
# persistent-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv                    # PVの名前
spec:
  capacity:
    storage: 1Gi                    # ストレージ容量（1GB）
  accessModes:
  - ReadWriteOnce                   # アクセスモード（1つのPodから読み書き可能）
  persistentVolumeReclaimPolicy: Retain  # PVC削除後の処理方針
  storageClassName: local-storage   # ストレージクラス名
  hostPath:                         # ローカルホストのパスを使用
    path: /tmp/k8s-data            # 実際のディスクパス
```

**アクセスモードの種類：**
- `ReadWriteOnce` (RWO): 1つのPodから読み書き可能
- `ReadOnlyMany` (ROX): 複数のPodから読み取り専用
- `ReadWriteMany` (RWX): 複数のPodから読み書き可能

**回収ポリシーの種類：**
- `Retain`: 手動削除が必要
- `Delete`: 自動削除
- `Recycle`: データを削除して再利用（非推奨）

### PersistentVolumeClaim (PVC) の詳細解説

#### PVCとは何か？

PersistentVolumeClaim（永続ボリューム要求）は、アプリケーションがストレージを要求するための仕組みです。PVCがPVに「バインド」されることで、実際にストレージが利用可能になります。

#### PVCの設定例と解説

```yaml
# persistent-volume-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: local-pvc                   # PVC名
  namespace: hands-on               # 名前空間
spec:
  accessModes:
  - ReadWriteOnce                   # 必要なアクセスモード
  resources:
    requests:
      storage: 500Mi                # 必要なストレージ容量（500MB）
  storageClassName: local-storage   # 使用するストレージクラス
```

#### PVとPVCの関係

```
[アプリケーション] →  [PVC]  →  [PV]  →  [実際のストレージ] 
     要求            申請     リソース      物理ディスク
```

### ストレージを使用するアプリケーションの例

#### MySQLデプロイメントの完全版

```yaml
# mysql-deployment.yaml
# Kubernetesのバージョン情報を指定
apiVersion: apps/v1

# このリソースの種類を指定（Deployment = アプリケーションの配置・管理）
kind: Deployment

# このDeploymentに関する基本情報
metadata:
  name: mysql-deployment          # このDeploymentの名前
  namespace: hands-on            # 配置する名前空間（プロジェクトのようなもの）
  labels:                        # ラベル（タグのようなもの）
    app: mysql                   # このリソースがmysqlアプリであることを示す

# Deploymentの設定内容
spec:
  replicas: 1                    # 起動するPod（コンテナの単位）の数

  # どのPodを管理対象にするかを決める条件
  selector:
    matchLabels:
      app: mysql                 # app=mysqlのラベルを持つPodを管理

  # 作成するPodの設計図
  template:
    metadata:
      labels:
        app: mysql               # Podに付けるラベル（上のselectorと一致させる）
    
    # Podの詳細設定
    spec:
      # セキュリティ設定（Pod全体）
      securityContext:
        fsGroup: 999             # ファイルシステムのグループID

      # コンテナの設定
      containers:
      - name: mysql              # コンテナの名前
        image: mysql:8.0         # 使用するDockerイメージ（MySQL 8.0版）
        
        # セキュリティ設定（コンテナレベル）
        securityContext:
          runAsUser: 999         # 実行ユーザーのID
          runAsGroup: 999        # 実行グループのID
        
        # 環境変数の設定（MySQLの初期設定）
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpassword"  # 管理者パスワード
        - name: MYSQL_DATABASE
          value: "testdb"        # 初期作成するデータベース名
        - name: MYSQL_USER
          value: "testuser"      # 一般ユーザー名
        - name: MYSQL_PASSWORD
          value: "testpass"      # 一般ユーザーのパスワード
        
        # ポート設定
        ports:
        - containerPort: 3306    # MySQLの標準ポート番号
          name: mysql-port       # ポートの名前
        
        # ボリュームマウント（データ保存場所の設定）
        volumeMounts:
        - name: mysql-storage    # 使用するボリューム名
          mountPath: /var/lib/mysql  # コンテナ内でのマウント先
        
        # リソース制限
        resources:
          requests:              # 最低限必要なリソース
            memory: "512Mi"      # メモリ512MB
            cpu: "500m"          # CPU 0.5コア
          limits:                # 最大使用可能リソース
            memory: "1Gi"        # メモリ1GB
            cpu: "1000m"         # CPU 1コア
        
        # プローブ（ヘルスチェック）を一時的に無効化
        # 注：本番環境では適切なヘルスチェックを設定することを推奨

      # ボリューム設定（データ保存用）
      volumes:
      - name: mysql-storage      # ボリュームの名前
        persistentVolumeClaim:   # 永続ボリュームクレームを使用
          claimName: local-pvc   # 使用するPVCの名前
```

#### リソースの作成手順

```bash
# 1. 名前空間の作成
kubectl create namespace hands-on

# 2. PVの作成
kubectl apply -f persistent-volume.yaml

# 3. PVの状態確認
kubectl get pv
# 出力例:
# NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS
# local-pv   1Gi        RWO            Retain           Available           local-storage

# 4. PVCの作成
kubectl apply -f persistent-volume-claim.yaml

# 5. PVCの状態確認とバインド確認
kubectl get pvc -n hands-on
# 出力例:
# NAME        STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS
# local-pvc   Bound    local-pv   1Gi        RWO            local-storage

# 6. MySQLデプロイメントの作成
kubectl apply -f mysql-deployment.yaml
```

### 7 リアルタイム監視コマンド

ハンズオン中にリソースの状態変化をリアルタイムで監視するための便利なコマンド集：

```bash
# 基本的な監視（今回作成する主要リソース）
watch 'kubectl get pod,svc,deployment,replicaset -n hands-on -o wide'

# ストレージリソース込みの監視
watch 'kubectl get pod,svc,deployment,pv,pvc,statefulset -n hands-on -o wide'

# 設定リソース込みの包括的監視
watch 'kubectl get pod,svc,deployment,configmap,secret,pv,pvc -n hands-on -o wide'

# 複数Namespaceにまたがる監視
watch 'kubectl get pod,svc,deployment -A -o wide'

# イベントを含む詳細監視
watch 'kubectl get events -n hands-on --sort-by=.lastTimestamp | tail -10; echo "---"; kubectl get pod,svc -n hands-on'

# リソース使用量の監視（メトリクスサーバーが必要）
watch 'kubectl top pods -n hands-on'

# ワンライナーでの複数リソース監視
watch -n 2 'echo "=== Pods ==="; kubectl get pods -n hands-on; echo "=== Services ==="; kubectl get svc -n hands-on; echo "=== Deployments ==="; kubectl get deploy -n hands-on'
```

**実際の使用例：**
```bash
# 新しいターミナルを開いて監視開始
watch 'kubectl get pod,svc,deployment,replicaset -n hands-on -o wide'

# 別のターミナルでリソース作成
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml

# 監視画面でリアルタイムに以下の変化が確認できます：
# 1. Deploymentの作成
# 2. ReplicaSetの自動作成
# 3. Podの起動プロセス（Pending → ContainerCreating → Running）
# 4. Serviceの作成とEndpointsの紐付け
```

**高度な監視コマンド：**
```bash
# JSONPath を使用したカスタム出力
watch 'kubectl get pods -n hands-on -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.spec.nodeName}{'\n'}{end}"'

# 特定の条件でフィルタリング
watch 'kubectl get pods -n hands-on --field-selector=status.phase!=Running'

# ラベルセレクターでの監視
watch 'kubectl get pods -n hands-on -l app=nginx -o wide'

# 複数リソースの詳細情報
watch 'kubectl describe pods -n hands-on | grep -E "(Name:|Status:|Ready:|Restarts:)"'
```

## 8. クリーンアップ

実習が完了したら、作成したリソースを削除します。

```bash
# Namespace削除（関連するすべてのリソースが削除される）
kubectl delete namespace hands-on

# PersistentVolumeの削除（必要に応じて）
kubectl delete pv local-pv

# minikubeクラスター停止
minikube stop

# minikubeクラスター削除（完全にクリーンアップしたい場合）
minikube delete
```