🖥️

【4-7】Kubernetes実践編:Namespace, Label/Annotation & 完全なアプリスタック構築

に公開

Kubernetes実践編:Namespace, Label/Annotation & 完全なアプリスタック構築

はじめに

Kubernetes入門の旅も、いよいよ最終章です。

これまで私たちは、Pod、Deployment、Service、ConfigMap、Secret、PV/PVC、StatefulSetといったKubernetesの核心的なリソースを一つずつ学び、コンテナ化されたアプリケーションを動かし、ネットワークを繋ぎ、設定を外部化し、データを永続化する方法をマスターしてきました。

しかし、実際のプロジェクトでは、開発・ステージング・本番といった複数の環境を管理したり、大量のリソースを整理したりする必要が出てきます。

この最終回では、Kubernetesクラスターを仮想的に分割する Namespace、リソースに 「付箋」 を貼って整理する Label「メモ」 を書き込む Annotation を学びます。

そして最後に、これまでの全ての知識を結集して、より本番に近い構成のWordPressアプリケーションスタックをゼロから構築します。

Part 1: Namespace - クラスター内の仮想的な仕切り

Namespaceは、1つの物理的なKubernetesクラスターを、複数の仮想的なクラスターに分割するための仕組みです。

なぜ必要?

  • 名前の衝突回避: チームAとチームBが、どちらもweb-appという名前のDeploymentを作っても、Namespaceが違えば衝突しません(team-a/web-appteam-b/web-appのように区別される)
  • 環境分離: development, staging, productionのようにNamespaceを分けることで、環境ごとのリソースを明確に分離・管理できます
  • アクセス制御: Namespace単位で「誰がどのリソースを触れるか」という権限(RBAC)を設定できます

Step 1: Namespaceの作成と操作

# 作業ディレクトリ準備
cd ~/k8s-practice
mkdir namespace-practice
cd namespace-practice

# コマンドでのNamespace作成
k create namespace development
k create namespace staging
k create namespace production

# YAMLでのNamespace作成 (ラベルも付与)
cat > namespace-qa.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
  name: qa
  labels:
    environment: qa
EOF

# YAMLを適用して作成
k apply -f namespace-qa.yaml

# Namespace一覧を確認
k get namespaces --show-labels

Step 2: Namespace内でのリソース管理

リソースを作成する際、metadata.namespaceを指定します。
実際にdevelopmentとproductionのNamespaceに、それぞれ異なる設定のWebアプリをデプロイしてみましょう。

# development Namespace用のアプリを作成
cat > app-development.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: development # <- Namespaceを指定
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
  namespace: development # <- Namespaceを指定
spec:
  type: NodePort
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30081
EOF

# YAMLを適用して作成
k apply -f app-development.yaml

# 特定Namespace内のリソースを確認するには `-n` オプションを使う
k get all -n development

# ブラウザでアクセス確認
http://192.168.3.101:30081

同様にproduction Namespaceにもアプリをデプロイできます(nodePortは30082に変更するなど重複を避ける)。

# developmentをproductionに、env: devをenv: prodに、
# NodePortを30081から30082に置換して別ファイルに保存
sed 's/development/production/g; s/dev/prod/g; s/30081/30082/g' app-development.yaml > app-production.yaml

# production用YAMLを適用
k apply -f app-production.yaml

# production Namespace内のリソースを確認
k get all -n production

# ブラウザでアクセス確認: http://192.168.3.101:30082

同じweb-appという名前のDeploymentでも、Namespaceが違うため衝突せずに共存できています。

Part 2: LabelとAnnotation - リソースに情報を付与する

リソースが増えてくると、「本番環境のWebサーバーだけ表示したい」「バージョンv2のPodだけ再起動したい」といった操作が必要になります。それを可能にするのがLabelです。

1. Label(ラベル):識別のための「付箋」

役割: リソース(Pod, Serviceなど)を識別・分類するためのキーと値のペアです。(例: app: web, tier: frontend, environment: production

用途: Serviceのselectorや、kubectl -lでの検索・フィルタリングに使われます。

# ラベルを使った検索
k get pods --show-labels
k get pods -l app=web               # appがwebのPod
k get pods -l environment=production # environmentがproductionのPod
k get pods -l app=web,tier=frontend # app=web かつ tier=frontend のPod

# 後からラベルを追加
k label pod web-frontend-v1 release=stable

2. Annotation(アノテーション):補足情報の「メモ書き」

役割: リソースの識別に使うのではなく、人間や外部ツール向けの補足情報(メタデータ) を付与するためのキーと値のペアです。

用途: 管理者の連絡先、ビルド番号、ドキュメントURL、監視ツール用の設定などを記述します。

# 起動中のPodにAnnotationを追加
k annotate pod web-frontend-v1 \
  owner="platform-team" \
  last-updated="$(date +%Y-%m-%d)"

# describeでAnnotationsセクションを確認
k describe pod web-frontend-v1 | grep -A5 Annotations

YAMLで定義する例:

apiVersion: v1
kind: Pod
metadata:
  name: annotated-pod
  labels:
    app: web
  annotations:
    description: "Demo pod with extensive metadata"
    contact: "devops@example.com"
    monitoring.prometheus.io/scrape: "true"
spec:
  # ...

Labelは「検索用」、Annotationは「メモ用」 と覚えておきましょう。

Part 3: グランドフィナーレ - 完全なWordPressスタック構築

いよいよ、これまでの学習内容(Namespace, ConfigMap, Secret, StatefulSet(DB), Deployment(Web), Service, PVC)を全て統合し、app-prodという専用Namespace内に、本番運用に近いWordPress環境を構築します。

# 作業ディレクトリ準備
cd ~/k8s-practice
mkdir full-app-stack
cd full-app-stack

Step 1: Namespace作成 (01-namespace.yaml)

cat > 01-namespace.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
  name: app-prod
  labels:
    environment: production
EOF

k apply -f 01-namespace.yaml

Step 2: ConfigMap & Secret作成 (02-config-secret.yaml)

app-prod Namespace内に作成します。SecretではstringDataを使うとBase64エンコードせずに書けて便利です。

cat > 02-config-secret.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: app-prod
data:
  APP_ENV: "production"
  LOG_LEVEL: "info"
  CACHE_ENABLED: "true"
---
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
  namespace: app-prod
type: Opaque
# stringDataを使うとBase64エンコードせずに平文で書ける(裏で自動エンコードされる)
stringData:
  username: "produser"
  password: "SecureProdP@ss123"
  database: "proddb"
EOF

k apply -f 02-config-secret.yaml

Step 3: MySQL StatefulSet & Headless Service (03-mysql.yaml)

app-prod Namespace内に作成し、Secretから認証情報を注入します。tier: databaseラベルも付与します。

cat > 03-mysql.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: app-prod
spec:
  ports:
  - port: 3306
  clusterIP: None
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: app-prod
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
        tier: database # tierラベルを追加
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        # SecretからパスワードとDB名を注入
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: database
        # (ユーザー名もSecretから取るのがよりセキュアだが、今回は省略)
        - name: MYSQL_USER
          value: "produser" # Secretから取るべき
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: local-path
      resources:
        requests:
          storage: 2Gi # 容量を2Giに増量
EOF

k apply -f 03-mysql.yaml

Step 4: WordPress Deployment & NodePort Service (04-wordpress.yaml)

app-prod Namespace内に作成。ConfigMapとSecretから設定を注入し、tier: frontendラベルを付与。DBホスト名には完全修飾ドメイン名(FQDN) を使います。

cat > 04-wordpress.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  namespace: app-prod
spec:
  replicas: 3 # レプリカ数を3に増やす
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend # tierラベルを追加
    spec:
      containers:
      - name: wordpress
        image: wordpress:latest
        env:
        # ★ NamespaceをまたいだServiceへの接続方法 ★
        # Service名.Namespace名.svc.cluster.local という完全修飾ドメイン名(FQDN)を使う
        - name: WORDPRESS_DB_HOST
          value: mysql.app-prod.svc.cluster.local
        # SecretからDB認証情報を注入
        - name: WORDPRESS_DB_USER
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: username
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password
        - name: WORDPRESS_DB_NAME
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: database
        # ConfigMap全体を環境変数として注入
        envFrom:
        - configMapRef:
            name: app-config
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: app-prod
spec:
  type: NodePort
  selector:
    app: wordpress
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30090 # NodePortを変更
EOF

k apply -f 04-wordpress.yaml

Step 5: 全体確認とブラウザアクセス

# app-prod Namespace内の全リソースとPVCを確認
k get all -n app-prod
k get pvc -n app-prod

# Labelを使った検索
k get pods -n app-prod -l tier=frontend
k get pods -n app-prod -l tier=database

# ブラウザでアクセス
# http://192.168.3.101:30090

WordPressの初期設定画面が表示されれば、全ての知識を結集したアプリケーションスタックの構築は成功です! 🎉

まとめ

Kubernetes入門の旅、お疲れ様でした!

最終回では、Namespaceによる環境分離、LabelとAnnotationによるリソース管理、そして全ての知識を統合した実践的なアプリケーション構築を経験しました。

基本リソースを一通りマスターしたあなたは、もうKubernetesの世界への扉を開けました。

ここから先は、より高度な機能(Ingress, Helm, CI/CD連携など)への探求が待っています。この入門で得た知識と経験が、あなたのこれからのクラウドネイティブな旅の確かな土台となることを願っています。

次のステップ

Kubernetesの基礎を習得した今、以下のような学習へと進むことができます:

  • Ingress: より高度な外部公開とルーティング
  • Helm: パッケージマネージャーによるアプリケーション管理
  • CI/CD統合: GitOps、ArgoCD、Jenkins等との連携
  • モニタリング: Prometheus、Grafanaによる監視
  • 本番クラスター: マルチノード構成の構築

ホームラボでの学習の旅、本当にお疲れ様でした! 🎓

Discussion