序論:設定管理と外部アクセスの重要性

コンテナ化されたアプリケーションを運用する際の最も重要な課題の1つは、設定の分離です。アプリケーションコードと設定を分離すれば、同じイメージを開発、ステージング、プロダクション環境で再利用できます。KubernetesはこのためにConfigMapSecretというリソースを提供します。

また、クラスター外部から内部サービスにアクセスするには、適切なルーティングメカニズムが必要です。Ingressは、HTTP/HTTPSトラフィックをクラスター内部のサービスにルーティングするL7ロードバランサーの役割を果たします。この編では、これら3つのコアリソースを詳しく見ていきます。

1. 設定管理の重要性

1.1 なぜ設定を分離すべきか?

12-Factor App方法論で強調されているように、設定はコードから分離されるべきです:

  • 環境別デプロイ:同じイメージをさまざまな環境(開発、テスト、プロダクション)にデプロイできます
  • セキュリティ強化:機密情報をコードリポジトリに含める必要がありません
  • 柔軟な変更:設定変更時にイメージの再ビルドなしで適用できます
  • チームコラボレーション:開発者と運用者がそれぞれの領域を独立して管理できます

1.2 Kubernetesの設定管理方式

Kubernetesは2つのリソースで設定を管理します:

リソース 用途 保存方式
ConfigMap 一般的な設定データ 平文(Plain text)
Secret 機密情報 Base64エンコーディング

2. ConfigMapの作成と使用

2.1 ConfigMapとは?

ConfigMapは、キーと値のペアで構成された設定データを保存するKubernetesリソースです。アプリケーションの環境変数、設定ファイル、コマンドライン引数などを保存できます。

2.2 ConfigMapの作成方法

方法1:リテラル値で作成

# 単一のキーと値のペア
kubectl create configmap app-config --from-literal=APP_ENV=production

# 複数のキーと値のペア
kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --from-literal=LOG_LEVEL=info \
  --from-literal=MAX_CONNECTIONS=100

方法2:ファイルから作成

# 単一ファイル
kubectl create configmap nginx-config --from-file=nginx.conf

# ディレクトリ全体
kubectl create configmap app-configs --from-file=./configs/

方法3:YAMLマニフェストで作成

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  # 単純なキーと値のペア
  APP_ENV: "production"
  LOG_LEVEL: "info"
  MAX_CONNECTIONS: "100"

  # 複数行の設定ファイル
  application.properties: |
    server.port=8080
    spring.datasource.url=jdbc:mysql://mysql:3306/mydb
    spring.jpa.hibernate.ddl-auto=update
    logging.level.root=INFO

  # JSON形式の設定
  config.json: |
    {
      "apiEndpoint": "https://api.example.com",
      "timeout": 30,
      "retryCount": 3
    }
kubectl apply -f configmap.yaml

2.3 ConfigMapの使用:環境変数

個別のキーを環境変数として使用

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    env:
    # 特定のキーのみ環境変数として注入
    - name: APPLICATION_ENV
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_ENV
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: LOG_LEVEL

すべてのキーを環境変数として使用

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    envFrom:
    - configMapRef:
        name: app-config
    # プレフィックスの追加も可能
    - configMapRef:
        name: app-config
      prefix: CONFIG_

2.4 ConfigMapの使用:ボリュームマウント

設定ファイルが必要な場合はボリュームとしてマウントできます:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/nginx/conf.d
      readOnly: true
  volumes:
  - name: config-volume
    configMap:
      name: nginx-config
      # 特定のキーのみマウントする場合
      items:
      - key: nginx.conf
        path: default.conf

3. Secretの作成と使用

3.1 Secretとは?

Secretは、パスワード、OAuthトークン、SSHキーなどの機密情報を保存するリソースです。ConfigMapと似ていますが、データがBase64でエンコードされて保存されます。

3.2 Secretのタイプ

タイプ 説明 使用例
Opaque 任意のユーザー定義データ パスワード、APIキー
kubernetes.io/tls TLS証明書 HTTPS証明書
kubernetes.io/dockerconfigjson Dockerレジストリ認証 プライベートレジストリアクセス
kubernetes.io/basic-auth 基本認証情報 ユーザー名/パスワード
kubernetes.io/ssh-auth SSH認証 SSH秘密鍵

3.3 Opaque Secretの作成

方法1:コマンドラインで作成

# リテラル値で作成
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=s3cr3tP@ssw0rd

# ファイルから作成
kubectl create secret generic ssh-key \
  --from-file=ssh-privatekey=/path/to/id_rsa

方法2:YAMLマニフェストで作成

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  # Base64エンコードされた値
  # echo -n 'admin' | base64 -> YWRtaW4=
  username: YWRtaW4=
  # echo -n 's3cr3tP@ssw0rd' | base64 -> czNjcjN0UEBzc3cwcmQ=
  password: czNjcjN0UEBzc3cwcmQ=
---
# stringDataを使用(自動的にBase64エンコード)
apiVersion: v1
kind: Secret
metadata:
  name: api-credentials
type: Opaque
stringData:
  api-key: my-super-secret-api-key
  api-secret: another-secret-value

3.4 Secretの使用

環境変数として注入

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password

ボリュームとしてマウント

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: db-credentials
      # ファイル権限の設定
      defaultMode: 0400

3.5 Secretのセキュリティ考慮事項

Secretは基本的にBase64エンコードのみで暗号化されていません。以下のセキュリティ対策を検討する必要があります:

  • etcd暗号化:etcdに保存されるSecretを暗号化します
  • RBAC制限:Secretへのアクセス権限を最小化します
  • 外部Secret管理ツールの使用:HashiCorp Vault、AWS Secrets Manager、Azure Key Vaultなど
  • Secretのローテーション:定期的にSecret値を変更します
  • 監査ログ:Secretアクセスに対する監査ログを有効化します

4. Ingressとは?

4.1 Ingressの概念

Ingressは、クラスター外部から内部サービスへのHTTP/HTTPSトラフィックを管理するAPIオブジェクトです。L7(アプリケーション層)ロードバランサーとして以下の機能を提供します:

  • ホストベースルーティング:ドメイン名に応じて異なるサービスにルーティング
  • パスベースルーティング:URLパスに応じて異なるサービスにルーティング
  • TLS/SSL終端:HTTPSトラフィックの処理
  • ロードバランシング:複数のPodにトラフィックを分散

4.2 Ingress vs Service(NodePort/LoadBalancer)

特性 NodePort LoadBalancer Ingress
レイヤー L4 L4 L7
プロトコル TCP/UDP TCP/UDP HTTP/HTTPS
URLルーティング 不可 不可 可能
TLS終端 不可 不可 可能
コスト 無料 クラウド費用発生 単一LBで複数サービス

5. Ingress Controller

5.1 Ingress Controllerとは?

Ingressリソースは宣言的なルーティングルールにすぎず、実際に動作するにはIngress Controllerが必要です。Ingress Controllerは、Ingressリソースを監視し、それに応じてロードバランサーを構成します。

5.2 主要なIngress Controller

Nginx Ingress Controller

# Nginx Ingress Controllerのインストール(Helm)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install nginx-ingress ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace

# またはマニフェストでインストール
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

Traefik Ingress Controller

# Traefikのインストール(Helm)
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace

6. Ingress YAMLの作成

6.1 基本的なIngress構造

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    # Ingress Controller固有の設定
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx  # 使用するIngress Controllerを指定
  rules:
  - host: example.com      # ホストベースルーティング
    http:
      paths:
      - path: /            # パスベースルーティング
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80

6.2 ホストベースルーティング

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: host-based-ingress
spec:
  ingressClassName: nginx
  rules:
  # api.example.com -> api-service
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

  # web.example.com -> web-service
  - host: web.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

6.3 パスベースルーティング

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      # example.com/api/* -> api-service
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 8080

      # example.com/web/* -> web-service
      - path: /web(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: web-service
            port:
              number: 80

      # example.com/*(デフォルト)-> frontend-service
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80

7. TLS設定

7.1 TLS Secretの作成

# 自己署名証明書の生成(テスト用)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key \
  -out tls.crt \
  -subj "/CN=example.com"

# TLS Secretの作成
kubectl create secret tls example-tls \
  --cert=tls.crt \
  --key=tls.key

7.2 IngressにTLSを適用

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    - www.example.com
    secretName: example-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

7.3 cert-managerによる自動証明書管理

# cert-managerのインストール
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
# Let's Encrypt ClusterIssuerの設定
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
---
# 自動証明書発行Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auto-tls-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    secretName: example-tls-auto  # cert-managerが自動生成
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

8. 結論

この第9編では、Kubernetesのコア設定管理リソースであるConfigMapとSecret、そして外部トラフィックを管理するIngressについて学びました:

  • ConfigMap:一般的な設定データを管理し、環境変数やボリュームとしてPodに注入できます
  • Secret:機密情報を安全に保存し、追加のセキュリティ対策が必要です
  • Ingress:L7ロードバランサーとして、ホスト/パスベースルーティングとTLS終端を提供します
  • Ingress Controller:Ingressリソースを実際に実装するコンポーネントです

次の第10編では、KubernetesパッケージマネージャーであるHelmCI/CDパイプラインの構築について学びます。Helm Chartを活用したアプリケーションデプロイと、GitOpsベースの自動化されたデプロイ戦略を扱う予定です。