Kubernetes の Pod 内で使う環境変数を Secret から設定する
Kubernetes 時代の環境変数設定。
目次
- Kubernetes Secret について
deployment.yaml
のenv
プロパティ--from-literal
オプションで一つずつ登録env
・valueFrom
で1つずつ参照紐付け--from-env-file
オプションで一括登録envFrom
で一括読み込み- 以上
Kubernetes Secret について
Kubernetes クラスタ内で稼動する Pod が、API キーやトークンなどのいわゆる Credentials (クレデンシャル) 情報を扱う時、それをどこで管理するのが良いだろうか。
アプリ内へのハードコーディングは勿論避けたい。後からの差し替えが難しくなる、「設定ファイルに切り出して Docker コンテナに同梱」といった手法もイマイチ。
じゃあ環境変数として持たせよう、となると、Dockerfile の ENV
命令が思い付くが、コレも Docker イメージ丸ごとの差し替えが必要になってしまうので、環境変数以外の差分がウッカリ混じってしまう、といった事故 (デグレ) に繋がりかねない。
Docker は起動時に --env
や --env-file
といったオプションを指定することで、環境変数を設定できる。しかし Kubernetes クラスタ内では別に docker run
コマンドを自分で叩くワケではないので、別の方法を使うことになる。…というのが今回紹介するお話。
Kubernetes には Secret と呼ばれる秘密情報を保持するための領域があるので、コレを利用して、Pod に環境変数をブチ込んでみよう。
なお、似たようなモノに ConfigSet というモノもあるのだが、コチラは今回紹介しない。Secret との違いは Base64 で難読化されていないぐらいなので、主に外部の API サービスのエンドポイント URL など、直接覗かれてもあまり影響がない定数情報を保持するのに使える。設定方法や参照方法には大きな違いはない。
deployment.yaml
の env
プロパティ
まずは、Secret を使わない簡単なやり方から。deployment.yaml
の中に環境変数を記述できる。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-app-deployment
spec:
selector:
matchLabels:
app: my-app
replicas: 1
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app
ports:
- containerPort: 8080
# 以下のように設定する
env:
- name: API_KEY
value: "xxxxx"
仕組み的には、docker run --env
オプションを使った時に似ているだろうか。
コレの難点は、秘密情報がベタ書きである点。この設定ファイルを漏らしてしまったらアウト。また、開発環境と本番環境を切り替えたりする時に、同じ設定ファイルを使い回せないこともやりづらい。
そこで、環境変数情報を Kubernetes Secret という別領域に逃してしまおう、というワケ。
--from-literal
オプションで一つずつ登録
まずは Secret の登録方法の中でも簡単なモノから。先程と同様の環境変数を設定してみる。
$ kubectl create secret generic 【シークレット名】 --from-literal=【Key】=【Value】
# 先程の例だとこんな感じ
$ kubectl create secret generic my-api-key-secret --from-literal=API_KEY=xxxxx
# 一つの Secret に複数の Key・Value を保存させたりもできる
$ kubectl create secret generic my-secrets --from-literal=ANOTHER_API_KEY=yyyyy --from-literal=ANOTHER_TOKEN=zzzzz
このように登録できる。「シークレット名」は適当に決めて良い。登録したモノを参照するには、以下のように。
# 「シークレット名」を指定し、YAML 形式や JSON 形式で出力する
$ kubectl get secret my-secrets -o yaml
apiVersion: v1
data:
ANOTHER_API_KEY: Zzzzzzzzzzz=
ANOTHER_TOKEN: Llllllll=
kind: Secret
# 以下略
登録した情報は Base64 エンコードされているので、以下のようにデコードすれば元の値が分かる。
# ANOTHER_API_KEY 環境変数の値をデコードする
$ echo 'Zzzzzzzzzzz=' | base64 --decode
yyyyy
# デコードできた
env
・valueFrom
で1つずつ参照紐付け
さて、ココまでだと、Kubernetes Secret に秘密情報が登録されただけで、その情報を Pod で環境変数として参照できるような紐付けがされていない。deployment.yaml
を以下のように変更し、この Secret を環境変数として読み込ませるようにしてみる。
spec:
# 中略
template:
spec:
containers:
- name: my-app
# 以下のように設定する
env:
- name: API_KEY # Pod 内でこの環境変数名で参照できるようにする
valueFrom:
secretKeyRef:
name: my-api-key-secret # シークレット名
key: API_KEY # その Secret 内の Key 名
- name: NEW_API_KEY # Secret に登録した Key 名とは違う名前で環境変数を設定したりもできる
valueFrom:
secretKeyRef:
name: my-secrets # シークレット名
key: ANOTHER_API_KEY # シークレットに登録した Key 名
こんな感じ。シークレットに登録した Key と違う環境変数名を定義できるのは面白い。混乱するので揃えた方が良いけど。
このように設定し、Pod を再生成させれば変更が反映される (既存の Pod は環境変数をキャッシュしているので、deployment.yaml
を Apply しても反映されない)。再生成した Pod のシェルにログインして env
コマンドを叩けば、設定した環境変数が見えるはずだ。勿論、値は難読化されていない生の値になっている。
--from-env-file
オプションで一括登録
このようなやり方でも環境変数を設定できなくはないが、登録する変数の個数が増えてくると、Secret の登録と deployment.yaml
への記述を揃えるのが大変になってくる。
そこで、Docker における --env-file
オプションのように、Key=Value
を羅列した環境変数ファイルを一括登録し、それを一括読み込みしてみよう。
いわゆる .env
ファイルの要領で、以下のように環境変数を用意する。
API_KEY=xxxxx
# 空行や、シャープ「#」で始まる行は無視されるので、コメントも書ける
ANOTHER_API_KEY=yyyyy
ANOTHER_TOKEN=zzzzz
Docker の --env-file
もそうだが、コレって結局、シェルに source
しているのとほとんど同じで、空行は無視されるし、シャープ #
で始まる行はコメント行として無視される。
Lines beginning with
#
(i.e. comments) are ignored. Blank lines are ignored.
Secret への登録は次のように行う。
$ kubectl create secret generic my-env-file-secret --from-env-file=./.env
envFrom
で一括読み込み
ファイルごと登録した Secret を環境変数として読み込むには、deployment.yaml
を以下のように記述する。
spec:
template:
spec:
containers:
- name: my-app
# 以下のように指定する
envFrom:
- secretRef:
name: my-env-file-secret
このような deployment.yaml
を設定し、Pod を再生成すれば OK。.env
ファイルに定義していた複数の環境変数が一括で読み込まれる。
以上
--from-env-file
で Secret を登録し、envFrom.secretRef
で読み込む。コレがシンプルで良いかも。