CLOVER🍀

That was when it all began.

OKD/MinishiftでConfigMapとSecretsを試す

これは、なにをしたくて書いたもの?

  • OpenShift(というかKubernetes)での、ConfigMapとSecretsのお試しに
  • アプリケーションの環境変数に組み込んで試してみたい

今回は、ConigMapとSecretsを使って環境変数から値を読む、簡単なNode.jsアプリケーションを書いてみます。

ConfigMapとSecretsの説明自体は、実際に作成する時に書いていきます。

環境

今回の環境は、こちら。

$ minishift version
minishift v1.23.0+91235ee


$ oc version
oc v3.10.0+dd10d17
kubernetes v1.10.0+b81c8f8
features: Basic-Auth GSSAPI Kerberos SPNEGO

Server https://192.168.42.238:8443
openshift v3.10.0+756ae6e-40
kubernetes v1.10.0+b81c8f8

アプリケーションを書く

最初に、Node.jsでアプリケーションを書いていきます。

Expressのインストール。

$ npm i --save express

Expressのバージョンは、こちら。

  "dependencies": {
    "express": "^4.16.3"
  }

アプリケーションは、「/config」でConfigMapから設定した環境変数を、「/secrets」でSecretsから設定した環境変数を 参照するように作成します。 src/server.js

const express = require('express');
const app = express();

app.get('/config', (req, res) => {
    const username = process.env.CONFIG_USERNAME;
    const password = process.env.CONFIG_PASSWORD;

    res.send({ config_username: username, config_password: password });
});

app.get('/secrets', (req, res) => {
    const username = process.env.SECRET_USERNAME;
    const password = process.env.SECRET_PASSWORD;

    res.send({ secret_username: username, secret_password: password });
});

app.listen(8080);

で、このスクリプトを「npm start」で起動するように設定。 package.json

  "scripts": {
    "start": "node src/server.js"
  },

ConfigMapとSecretsを作る

続いて、このアプリケーションに設定するConfigMapとSecretsを作成します。

まずは、ConfigMapから。

ConfigMaps | Developer Guide | OKD 3.10

ConfigMapとは、文字通り設定情報ですが、設定を稼働するコンテナに含めるのではなく、デプロイ時にコンテナに提供する仕組みの ことを言うそうです。

コンテナは、ConfigMapを環境変数やコンテナの起動引数、ファイルとして参照することができるそうな。

Consuming in Environment Variables

Setting Command-line Arguments

作り方はYAMLで、ファイルから、リテラルからといくつかあるようですが、今回はリテラルから作ってみます。

Creating from Literal Values

参考)

Creating from Directories

Creating from Files

Consuming in Volumes

ConfigMapの作成。

$ oc create configmap app-config --from-literal=config-username=cuser --from-literal=config-password=cpassword

確認。

$ oc get cm/app-config -o yaml
apiVersion: v1
data:
  config-password: cpassword
  config-username: cuser
kind: ConfigMap
metadata:
  creationTimestamp: 2018-09-08T07:33:30Z
  name: app-config
  namespace: myproject
  resourceVersion: "27888"
  selfLink: /api/v1/namespaces/myproject/configmaps/app-config
  uid: 7bf7b343-b339-11e8-9de6-52540089d814

Secretsを作る

今度は、Secretsを作成します。

Secrets | Developer Guide | OKD 3.10

Secretsは、パスワード、OKDクライアントの設定ファイル、dockercfg、プライベートなソースリポジトリのクレデンシャルなどを 管理する仕組みのことだそうな。

Base64エンコードされ、データはtmpfs上に置かれて参照されます。Node上には置かれません、と。また、namespace内で共有することが できます。

Properties of Secrets

作成できるSecretsの種類はいくつかあり、Service Account Tokenやdockercfg、TLSに関するものなどがあります。

Types of Secrets

もちろん、汎用的な設定情報としても作成することができます(type=Opaque)。

作成したSecretsは、ボリュームとしてマウントしたり、コンテナの起動引数としたり、環境変数として参照できたりします。

Examples

ConfigMapと同じですね。

Secretsの作成は、ファイルやリテラルから行います。

今回は、リテラルから作成してみます。

$ oc create secret generic app-secrets --from-literal=secret-username=suser --from-literal=secret-password=spassword

確認。

$ oc get secrets/app-secrets -o yaml
apiVersion: v1
data:
  secret-password: c3Bhc3N3b3Jk
  secret-username: c3VzZXI=
kind: Secret
metadata:
  creationTimestamp: 2018-09-08T07:33:35Z
  name: app-secrets
  namespace: myproject
  resourceVersion: "27896"
  selfLink: /api/v1/namespaces/myproject/secrets/app-secrets
  uid: 7eec487a-b339-11e8-9de6-52540089d814
type: Opaque

確かに、Base64エンコードされて保存されています。

$ echo -n 'c3Bhc3N3b3Jk' | base64 -d
spassword

参考)

Kubernetes勉強会第1回 〜Secrets、StatefulSet、DaemonSet、API server への接続方法〜 - 世界中の羊をかき集めて

KubernetesのSecrets機能を試してみた

Kubernetes Secrets の紹介 – データベースのパスワードやその他秘密情報をどこに保存するか? – ゆびてく

確認

それでは、ここまで作成してきたアプリケーションとConfigMap、Secretsを使って動作確認してみます。

アプリケーションのデプロイ。

$ oc new-app [GitリポジトリのURL]

Routeの作成。

$ oc expose svc/node-config-and-secrets
route "node-config-and-secrets" exposed

$ oc get routes/node-config-and-secrets
NAME                      HOST/PORT                                                PATH      SERVICES                  PORT       TERMINATION   WILDCARD
node-config-and-secrets   node-config-and-secrets-myproject.192.168.42.24.nip.io             node-config-and-secrets   8080-tcp                 None

アプリケーションに、環境変数としてConfigMapとSecretsを取り込みます。

$ oc set env --from=configmap/app-config dc/node-config-and-secrets

$ oc set env --from=secrets/app-secrets dc/node-config-and-secrets

確認。

$ curl node-config-and-secrets-myproject.192.168.42.24.nip.io/config
{"config_username":"cuser","config_password":"cpassword"}

$ curl node-config-and-secrets-myproject.192.168.42.24.nip.io/secrets
{"secret_username":"suser","secret_password":"spassword"}

アプリケーションから、環境変数として参照できていますね。

変更してみる

ConfigMapやSecretsの変更は、今回は「oc edit」でYAMLを変更。

$ oc edit cm/app-config

$ oc edit secrets/app-secrets

変更したら、DeploymentConfigをrollout。

$ oc rollout latest dc/node-config-and-secrets

これで、変更がコンテナ側にも反映されました、と。

YAMLで書こう

最後に、ここまでのことをYAMLで書き直してみます。

ConfigMap。 config-resources.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  config-password: cpassword
  config-username: cuser

Secrets。 secrets-resources.yml

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  secret-password: c3Bhc3N3b3Jk
  secret-username: c3VzZXI=

stringDataを使えば、Base64エンコードなしで書くこともできるようで。 secrets-resources.yml

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  secret-username: secret-username
  secret-password: secret-password

アプリケーション。 application-resources.yml

---
## ImageStream
apiVersion: v1
kind: ImageStream
metadata:
  labels:
    app: node-config-and-secrets
  name: node-config-and-secrets

---
## BuildConfig
apiVersion: v1
kind: BuildConfig
metadata:
  labels:
    app: node-config-and-secrets
  name: node-config-and-secrets
spec:
  triggers:
    - type: ConfigChange
    - imageChange: {}
      type: ImageChange
  source:
    git:
      uri: [GitリポジトリのURL]
      ref: master
    type: Git
  strategy:
    type: Source
    sourceStrategy:
      from:
        kind: ImageStreamTag
        name: nodejs:8
        namespace: openshift
  output:
    to:
      kind: ImageStreamTag
      name: node-config-and-secrets:latest

---
## DeploymentConfig
apiVersion: v1
kind: DeploymentConfig
metadata:
  labels:
    app: node-config-and-secrets
  name: node-config-and-secrets
spec:
  replicas: 1
  selector:
    app: node-config-and-secrets
    deploymentconfig: node-config-and-secrets
  template:
    metadata:
      labels:
        app: node-config-and-secrets
        deploymentconfig: node-config-and-secrets
    spec:
      containers:
      - name: node-config-and-secrets
        image: node-config-and-secrets:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
        env:
          - name: CONFIG_USERNAME
            valueFrom:
              configMapKeyRef:
                name: app-config
                key: config-username
          - name: CONFIG_PASSWORD
            valueFrom:
              configMapKeyRef:
                name: app-config
                key: config-password
          - name: SECRET_USERNAME
            valueFrom:
              secretKeyRef:
                name: app-secrets
                key: secret-username
          - name: SECRET_PASSWORD
            valueFrom:
              secretKeyRef:
                name: app-secrets
                key: secret-password
      restartPolicy: Always
  triggers:
  - type: ConfigChange
  - type: ImageChange
    imageChangeParams:
      automatic: true
      containerNames:
      - node-config-and-secrets
      from:
        kind: ImageStreamTag
        name: node-config-and-secrets:latest

---
## Service
apiVersion: v1
kind: Service
metadata:
  labels:
    app: node-config-and-secrets
  name: node-config-and-secrets
spec:
  ports:
  - name: 8080-tcp
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: node-config-and-secrets
    deploymentconfig: node-config-and-secrets

---
## Route
apiVersion: v1
kind: Route
metadata:
  labels:
    app: node-config-and-secrets
  name: node-config-and-secrets
spec:
  port:
    targetPort: 8080-tcp
  to:
    kind: Service
    name: node-config-and-secrets

なお、今回のConfigMapおよびSecretsのキー名だと、そのまま環境変数として使うのは微妙ですが、コンテナにConfigMapやSecretsの 内容を環境変数として一括で取り込むには、こんな感じで。

spec:
  ...
  template:
    metadata:
      ...
    spec:
      containers:
      - name: node-config-and-secrets
        image: node-config-and-secrets:latest
        ...
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secrets