Posted at

Kubernetes の 環境変数設定方法を調べる

作業メモ。

Kubernetes完全ガイド impress top gearシリーズを読みながら手元で確認した時のメモ。


環境

$ kubectl version

Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:03:09Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.5-eks-6bad6d", GitCommit:"6bad6d9c768dc0864dab48a11653aa53b5a47043", GitTreeState:"clean", BuildDate:"2018-12-06T23:13:14Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}

Kubernetes 環境としては EKS を利用。


概要

環境変数を利用することでコンテナに任意の情報を与えることが出来る。

例えば DB への接続先 URL,ユーザー名やパスワード情報など。


  1. 静的設定

  2. Pod の情報

  3. コンテナの情報

  4. Secret リソースの機密情報

  5. ConfigMap リソースの設定値


1. 静的設定

Define an environment variable for a container

上記にあるように env もしくは envFrom フィールドでマニュフェストファイルに定義できる。


evnvars.yaml

apiVersion: v1

kind: Pod
metadata:
name: envar-demo
labels:
purpose: demonstrate-envars
spec:
containers:
- name: envar-demo-container
image: gcr.io/google-samples/node-hello:1.0
env:
- name: DEMO_GREETING
value: "Hello from the environment"
- name: DEMO_FAREWELL
value: "Such a sweet sorrow"

やってみる。

# Pod 作成

$kubectl apply -f https://k8s.io/examples/pods/inject/envars.yaml
pod "envar-demo" created

# describe すると設定がわかる
$kubectl describe pod envar-demo

・・・
Environment:
DEMO_GREETING: Hello from the environment
DEMO_FAREWELL: Such a sweet sorrow

# exec を使って env コマンドを実行すると設定されていることが確認出来る
$ kubectl exec -it envar-demo -- env|grep DEMO
DEMO_GREETING=Hello from the environment
DEMO_FAREWELL=Such a sweet sorrow


マニュフェストファイルで環境変数を利用する場合の注意点

Using environment variables inside of your config

上記のようにマニュフェストファイルに環境変数を定義し、マニュフェストファイルで参照(command や args など)する場合には注意が必要。

通常であれば ${GREETING} という形式で参照できるがマニュフェストファイル内での読み込む場合には $(GREETING) というように「{}」ではなく、「()」を利用する。


evnvars2.yaml

apiVersion: v1

kind: Pod
metadata:
name: print-greeting
spec:
containers:
- name: env-print-demo
image: bash
env:
- name: GREETING
value: "Warm greetings to"
- name: HONORIFIC
value: "The Most Honorable"
- name: NAME
value: "Kubernetes"
command: ["echo"]
args: ["$(GREETING) $(HONORIFIC) $(NAME)"]

# Pod 作成

$kubectl apply -f envvars2.yaml
pod "print-greeting" created

# マニュフェストファイルに定義した環境変数が args で読み込めている
$kubectl logs print-greeting
Warm greetings to The Most Honorable Kubernetes


2. Pod の情報、3. コンテナの情報 

Expose Pod Information to Containers Through Environment Variables

Pod の情報(どのノードで起動しているか、自分の IP アドレスなど)について fieldRef を使って参照可能。

参照可能な値については kubectl get pods -o yaml などで確認出来る。

コンテナの情報(CPU リソース設定など)は resourceFieldRef を使って参照可能。

参照可能な値については kubectl get pods -o yaml などで確認出来る。

同じような方法で取得が可能なので今回は Pod の情報取得を試す。


dapi-envars-pod.yaml

apiVersion: v1

kind: Pod
metadata:
name: dapi-envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
sleep 10;
done;
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
restartPolicy: Never

# Pod 作成

$ kubectl apply -f dapi-envars-pod.yaml
pod "dapi-envars-fieldref" created

# Pod の情報が確認できる。while tru; doしているので継続的に表示される
$kubectl logs dapi-envars-fieldref

ip-172-31-23-75.ap-northeast-1.compute.internal
dapi-envars-fieldref
default
172.31.24.230
default

ip-172-31-23-75.ap-northeast-1.compute.internal
dapi-envars-fieldref
default
172.31.24.230
default

# exec しても環境変数が設定されている事が分かる
$kubectl exec -it dapi-envars-fieldref -- env |grep MY
MY_POD_NAMESPACE=default
MY_POD_IP=172.31.24.230
MY_POD_SERVICE_ACCOUNT=default
MY_NODE_NAME=ip-172-31-23-75.ap-northeast-1.compute.internal
MY_POD_NAME=dapi-envars-fieldref


4. Secret リソースの機密情報

Secrets

Distribute Credentials Securely Using Secrets

シークレット

ユーザー名・パスワードなどの機密情報を設定する場合には Secret を利用する。

なお、Secret は Base64 エンコードされているだけで暗号化されていない。

その為、Git リポジトリにマニュフェストファイルを配置するような場合、kubesecを使って暗号化するなど対応が必要。

以下より試す。


Base64 エンコード化する

Convert your secret data to a base-64 representation

Secret を使うためにはまずは設定したい値を Base64 エンコード化する。

$echo -n 'my-app' | base64

bXktYXBw

$ echo -n '39528$vdg7Jb' | base64
Mzk1MjgkdmRnN0pi

それぞれの値をメモしておく。


Secret 作成

以下のうようなマニュフェストファイルを作成する。


secret.yaml

apiVersion: v1

kind: Secret
metadata:
name: test-secret
data:
username: bXktYXBw
password: Mzk1MjgkdmRnN0pi

作成。

$kubectl create -f https://k8s.io/docs/tasks/inject-data-application/secret-pod.yaml

secret "test-secret" created

# Secret の存在及び 2つのデータがあることを確認
$ kubectl get secret test-secret
NAME TYPE DATA AGE
test-secret Opaque 2 35s

# describe するとより詳細をな情報が確認出来る
$kubectl describe secret test-secret
Name: test-secret
Namespace: default
Labels: <none>
Annotations:
Type: Opaque

Data
====
password: 12 bytes
username: 6 bytes


Secret を環境変数経由で Pod からアクセスする

環境変数で Secret から値を参照する場合、 secretKeyRef を設定する。

なお、環境変数で参照した際には Base64 デコードされて設定されている。


secret-envars-pod.yaml

apiVersion: v1

kind: Pod
metadata:
name: secret-envars-test-pod
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: test-secret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: test-secret
key: password

$ kubectl create -f https://k8s.io/docs/tasks/inject-data-application/secret-envars-pod.yaml

pod "secret-envars-test-pod" created

# Secret の内容が Base64 デコードされて環境変数に設定されている。
$ kubectl exec -it secret-envars-test-pod -- env |grep SECRET
SECRET_USERNAME=my-app
SECRET_PASSWORD=39528$vdg7Jb

なお、Secret は環境変数だけでなく、 Volume を通して値を取得する事もできる。

Create a Pod that has access to the secret data through a Volume

volumes で Secret 名を定義し、対象の Volume をマウントする。


secret-pod.yaml

apiVersion: v1

kind: Pod
metadata:
name: secret-test-pod
spec:
containers:
- name: test-container
image: nginx
volumeMounts:
# name must match the volume name below
- name: secret-volume
mountPath: /etc/secret-volume
# The secret data is exposed to Containers in the Pod through a Volume.
volumes:
- name: secret-volume
secret:
secretName: test-secret


試す。

$kubectl create -f https://k8s.io/docs/tasks/inject-data-application/secret-pod.yaml

pod "secret-test-pod" created

# マウントした /etc/secret-volume 配下に2つのファイルが存在する
$kubectl exec -it secret-test-pod -- ls /etc/secret-volume
password username

# 環境変数と同様に Base64 デコードされて設定されている
$kubectl exec -it secret-test-pod -- cat /etc/secret-volume/username
my-app%
$kubectl exec -it secret-test-pod -- cat /etc/secret-volume/password
39528$vdg7Jb%


5. ConfigMap リソースの設定値

Configure a Pod to Use a ConfigMap

ConfigMap

機密性がないような情報の場合、ConfigMap を使って Key=Value 形式で値を予め保存し、環境変数で参照する事が出来る。

また、Secret と同じように ConfigMap においても Volume をマウントして値を参照する事もできる(基本的に方法は同じ)

ConfigMap を予め作成し、値を環境変数から参照する。


ConfigMap を作成する

ディレクトリを指定する、ファイルを指定する、 literal valuesから作成するなどいくつかの方法がある。

今回はマニュフェストファイル2つ作成して環境変数に設定し、参照する。

Define container environment variables with data from multiple ConfigMaps


configmap1.yaml

apiVersion: v1

kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very


configmap2.yaml

apiVersion: v1

kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO

# 作成

$kubectl apply -f configmap1.yaml
configmap "special-config" created
$kubectl apply -f configmap2.yaml
configmap "env-config" created

# 2つの ConfigMap が存在し、データはそれぞれ一つ(Key=value のペアが一つという意味)
$ kubectl get configmap
NAME DATA AGE
env-config 1 53s
special-config 1 1m

# Secret と違い、describe すると Value が確認出来る
$kubectl describe configmap env-config
Name: env-config
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","data":{"log_level":"INFO"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"env-config","namespace":"default"}}

Data
====
log_level:
----
INFO
Events: <none>


Pod から環境変数経由で参照する

configMapKeyRef を指定して環境変数で参照可能。


configmap-pod.yaml

apiVersion: v1

kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
restartPolicy: Never

# Pod 作成

$kubectl apply -f configmap-pod.yaml
pod "dapi-test-pod" created

# configmap1 の内容が参照可能
$ kubectl logs dapi-test-pod |grep SPECIAL
SPECIAL_LEVEL_KEY=very

# configmap2 の内容が参照可能
$kubectl logs dapi-test-pod |grep LOG
LOG_LEVEL=INFO

なお、envFrom フィールドを使うと指定し ConfigMap のすべての環境変数を参照するようにすることも出来る。


all-configmap.yaml

apiVersion: v1

kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never

上記を使う場合、マニュフェストファイルを見ただけではどのような内容が設定されているか分からない。