EKSでConfigMapとSecretを使ったアプリケーション設定管理を構築してみる

はじめに

こんにちは。akibaです。

本記事では、Amazon EKS上でConfigMapとSecretを使用し、アプリケーション設定を管理する構成を構築します。

EKS上でアプリケーションを動かす場合、環境ごとの設定値や接続情報などを、コンテナイメージとは分けて管理したい場面があります。

Kubernetesでは、ConfigMapやSecretを使用することで、設定値をPodから参照できる形で管理できます。

今回は、ConfigMapとSecretを作成し、Deploymentから環境変数として参照させることで、Pod内のコンテナから設定値を利用できることを確認します。

また、ConfigMapの値を変更した際に、Podへどのように反映されるかについても確認します。

前提

本記事では、作成済みのEKSクラスターを使用します。

EKSクラスターの作成や、kubectl の接続設定については過去のEKS関連記事で扱っているため、本記事では詳細な手順は省略します。

今回は、kubectl でEKSクラスターを操作できる状態から、検証用のNamespaceを作成し、その中にConfigMap、Secret、Deploymentを作成します。

Deploymentではnginxの公式イメージを使用し、ConfigMapとSecretの値を環境変数としてPodへ渡します。

その後、Pod内で環境変数を確認することで、設定値がコンテナから参照できることを確認します。

なお、本記事ではConfigMapとSecretによる設定管理を主題とするため、アプリケーションの外部公開は行いません。

ConfigMapとSecretの作成

まず、今回の検証で使用するNamespaceを作成します。

Namespaceを分けることで、今回作成するConfigMap、Secret、Deploymentなどのリソースを、他の検証リソースと分けて管理できます。

# 検証用Namespaceを作成する
kubectl create namespace config-secret-test

作成後、Namespaceの状態を確認します。

# 作成したNamespaceがActiveになっているか確認する
$ kubectl get namespace config-secret-test

NAME                 STATUS   AGE
config-secret-test   Active   69s

次に、アプリケーションで使用する通常の設定値をConfigMapとして作成します。

ConfigMapは、機密情報ではない設定値をkey-value形式で管理するために使用します。
今回は検証用に、環境名とメッセージを設定値として定義します。

# アプリケーションで使用する設定値をConfigMapとして作成する
kubectl create configmap app-config \
  --from-literal=APP_ENV=dev \
  --from-literal=APP_MESSAGE="Hello from ConfigMap" \
  -n config-secret-test

作成したConfigMapの内容を確認します。

# ConfigMapに登録したキーと値を確認する
$ kubectl describe configmap app-config -n config-secret-test

Name:         app-config
Namespace:    config-secret-test
Labels:       <none>
Annotations:  <none>

Data
====
APP_ENV:
----
dev

APP_MESSAGE:
----
Hello from ConfigMap


BinaryData
====

Events:  <none>

APP_ENVAPP_MESSAGE が表示されていれば、ConfigMapに設定値が登録されていることが確認できます。

続いて、Secretを作成します。

Secretは、パスワードやトークンなどの機密情報を想定した値を管理するために使用します。
今回は検証用として、ダミーのユーザー名とパスワードを定義します。

# ダミーのユーザ名とパスワードの値をSecretとして作成する
kubectl create secret generic app-secret \
  --from-literal=DB_USER=test-user \
  --from-literal=DB_PASSWORD=test-password \
  -n config-secret-test

作成したSecretの内容を確認します。

# Secretに登録されたキー名とデータサイズを確認する
$ kubectl describe secret app-secret -n config-secret-test

Name:         app-secret
Namespace:    config-secret-test
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
DB_PASSWORD:  13 bytes
DB_USER:      9 bytes

Secretでは、値そのものではなく、キー名やデータサイズが表示されます。
DB_USERDB_PASSWORD が確認できれば、Secretに値が登録されています。

これで、通常の設定値を管理するConfigMapと、機密情報を想定した値を管理するSecretを作成できました。

Deploymentへの反映

次に、作成したConfigMapとSecretをDeploymentから参照します。

Deploymentは、Podの起動数や使用するコンテナイメージなどを管理するリソースです。
今回はnginxの公式イメージを使用し、ConfigMapとSecretの値を環境変数としてPodへ渡します。

まず、CloudShell上で作業用ディレクトリを作成します。

# Deploymentマニフェストを配置する作業用ディレクトリを作成する
mkdir -p ~/eks-config-secret-test

# 作成した作業用ディレクトリへ移動する
cd ~/eks-config-secret-test

以下の内容で、config-secret-deployment.yaml を作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: config-secret-app
  namespace: config-secret-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: config-secret-app
  template:
    metadata:
      labels:
        app: config-secret-app
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: app-config
            - secretRef:
                name: app-secret

このマニフェストでは、envFrom を使用してConfigMapとSecretを環境変数として参照しています。

これにより、コンテナイメージの中に設定値を含めずに、Pod起動時にKubernetes側のリソースから値を渡すことができます。

作成したマニフェストを適用します。

# DeploymentマニフェストをEKSクラスターに適用する
kubectl apply -f config-secret-deployment.yaml

DeploymentによってPodが作成されていることを確認します。

# Deploymentのロールアウトが完了したか確認する
$ kubectl get pods -n config-secret-test

NAME                                 READY   STATUS    RESTARTS   AGE
config-secret-app-6dbf999896-zdxzf   1/1     Running   0          91s

STATUSRunning になっていれば、Podが正常に起動しています。

これで、ConfigMapとSecretを参照するDeploymentを作成できました。

動作確認

作成したDeploymentにより、ConfigMapとSecretの値がPodへ渡されているか確認します。

今回は、ConfigMapとSecretを環境変数として参照する設定にしているため、Pod内で環境変数を確認することで、値がコンテナへ渡されているかを確認できます。

まず、確認対象のPod名を変数に格納します。

# app=config-secret-app のラベルを持つPod名を取得し、変数に格納する
POD_NAME=$(kubectl get pods -n config-secret-test -l app=config-secret-app -o jsonpath='{.items[0].metadata.name}')

次に、Pod内で環境変数を確認します。

# Pod内の環境変数からConfigMapとSecretで定義した値を確認する
$ kubectl exec -it $POD_NAME -n config-secret-test -- printenv | grep -E 'APP_ENV|APP_MESSAGE|DB_USER|DB_PASSWORD'

DB_PASSWORD=test-password
DB_USER=test-user
APP_ENV=dev
APP_MESSAGE=Hello from ConfigMap

ConfigMapで定義した APP_ENVAPP_MESSAGE と、Secretで定義した DB_USERDB_PASSWORD が表示されました。

これにより、ConfigMapとSecretで定義した値を、Deployment経由でPodの環境変数として渡せることが確認できました。

なお、今回は検証用のダミー値を使用しています。
実運用でSecretを扱う場合は、実際のパスワードやトークンなどを不用意にログや画面に出力しないよう注意が必要です。

次に、ConfigMapの値を変更した場合の反映について確認します。

今回は、ConfigMapの値を環境変数としてPodへ渡しています。
この場合、ConfigMapを更新しても、すでに起動しているPod内の環境変数には即時反映されません。

まず、ConfigMapの値を変更します。

# ConfigMapの値を更新する
kubectl create configmap app-config \
  --from-literal=APP_ENV=stg \
  --from-literal=APP_MESSAGE="Updated from ConfigMap" \
  -n config-secret-test \
  --dry-run=client -o yaml | kubectl apply -f -

Warning: resource configmaps/app-config is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
configmap/app-config configured

この警告は、最初に kubectl create configmap で作成したConfigMapを、後続で kubectl apply を使用して更新したために表示されています。
configmap/app-config configured と表示されていれば、ConfigMapの更新自体は完了しています。

変更後のConfigMapの内容を確認します。

# 更新後のConfigMapの値を確認する
$ kubectl describe configmap app-config -n config-secret-test

Name:         app-config
Namespace:    config-secret-test
Labels:       <none>
Annotations:  <none>

Data
====
APP_ENV:
----
stg

APP_MESSAGE:
----
Updated from ConfigMap


BinaryData
====

Events:  <none>

APP_ENVAPP_MESSAGE の値が変更されていれば、ConfigMapの更新は完了しています。

変更後の値をPodに反映するため、Deploymentを再起動し、Podを再作成します。

# Deploymentを再起動し、ConfigMap変更後の値を読み込むPodを再作成する
kubectl rollout restart deployment/config-secret-app -n config-secret-test

ロールアウトの状態を確認します。

# Deploymentのロールアウトの状態確認をする
$ kubectl rollout status deployment/config-secret-app -n config-secret-test

deployment "config-secret-app" successfully rolled out

Podが再作成されたことを確認します。

# Deployment再起動後に作成されたPodの状態を確認する
$ kubectl get pods -n config-secret-test

NAME                                 READY   STATUS    RESTARTS   AGE
config-secret-app-674648df4c-l42rd   1/1     Running   0          3m42s

再作成されたPod内で、環境変数を確認します。

# 再作成後のPod名を取得し、変数を更新する
POD_NAME=$(kubectl get pods -n config-secret-test -l app=config-secret-app -o jsonpath='{.items[0].metadata.name}')
# 再作成後のPodで、ConfigMapの変更後の値が反映されているか確認する
$ kubectl exec -it $POD_NAME -n config-secret-test -- printenv | grep -E 'APP_ENV|APP_MESSAGE'

APP_ENV=stg
APP_MESSAGE=Updated from ConfigMap

変更後のConfigMapの値が表示されました。

これにより、環境変数として参照しているConfigMapは、ConfigMapの値を変更しただけでは既存Podに即時反映されず、Podを再作成することで変更後の値が反映されることを確認できました。

これで、ConfigMapとSecretを環境変数としてPodに渡す構成と、ConfigMap変更後にPodを再作成して値を反映する流れを確認できました。

後片付け

検証が完了したため、作成したKubernetesリソースを削除します。

今回は検証用Namespace内にConfigMap、Secret、Deployment、Podを作成しているため、Namespaceを削除することでまとめて削除できます。

# 検証用Namespaceを削除し、関連するConfigMap、Secret、Deployment、Podもまとめて削除する
kubectl delete namespace config-secret-test

まとめ

本記事では、EKS上でConfigMapとSecretを使用し、アプリケーション設定を管理する構成を構築しました。

ConfigMapには通常の設定値、Secretには機密情報を想定した値を定義し、Deploymentから環境変数として参照させることで、Pod内のコンテナから設定値を利用できることを確認しました。

アプリケーションの設定値をコンテナイメージから分離することで、環境ごとの設定変更や、設定値の管理をKubernetesリソースとして扱いやすくなります。

また、ConfigMapを環境変数として参照している場合、ConfigMapの値を変更しただけでは既存Pod内の環境変数には即時反映されないため、Podの再作成が必要になることも確認しました。

実運用でSecretを扱う場合は、値の管理方法やアクセス権限、ログへの出力有無などに注意が必要です。

EKS上でアプリケーションを運用する際は、ConfigMapとSecretを活用することで、設定値をコンテナイメージと分けて管理する構成を検討できます。