ConfigMap和Secret:配置应用程序

更改容器的主进程

我们需要一个可以用配置控制进程的服务,例如配置不同参数,程序表现不一样,我们看下这个程序

# cat fortuneloop.sh
#!/bin/bash
trap "exit" SIGINT

INTERVAL=$1   #默认值来自命令行参数
echo Configured to generate new fortune every $INTERVAL seconds

mkdir -p /var/htdocs

while :
do
  echo $(date) Writing fortune to /var/htdocs/index.html
  /usr/games/fortune > /var/htdocs/index.html
  sleep $INTERVAL
done

里面有个环境变量INTERVAL可以控制休眠的时间长短(默认值来自命令行参数),也就控制了fortune财富“鸡汤“的变化速度,我们来用Dockerfile制作这个服务

# cat Dockerfile
FROM ubuntu:latest

RUN apt-get update ; apt-get -y install fortune
ADD fortuneloop.sh /bin/fortuneloop.sh

ENTRYPOINT ["/bin/fortuneloop.sh"]
CMD ["10"]

大家看懂服务逻辑就行了,镜像已经制作好了的。我们直接进入kubernetes部署环节

将命令行选项传递给应用程序

见pod描述文件

# cat fortune-pod-args.yaml
apiVersion: v1
kind: Pod
metadata:
  name: fortune2s
spec:
  containers:
  - image: luksa/fortune:args   #生产财富鸡汤
    args: ["2"]                 #默认2秒
    name: html-generator
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine         #对外提供服务
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
  volumes:
  - name: html
    emptyDir: {}

create试试看(可以跳过),因为上面的INTERVAL是来自命令行,所以结果可想而知频率是固定的2秒。

设置暴露给应用程序的环境变量

# cat fortune-pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: fortune-env
spec:
  containers:
  - image: luksa/fortune:env
    env:               #和上面不一样,增加了环境变量
    - name: INTERVAL
      value: "30"      #30s
    name: html-generator
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
  volumes:
  - name: html
    emptyDir: {}

create试试,我们继续使用port-forward代理访问pod端口

$ k create -f fortune-pod-env.yaml
pod/fortune-env created

$ k port-forward fortune-env 8080:80                                                                                                                                           1 ↵
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

然后在另一个控制台访问,观察是否设定的环境变量秒数

$ while true; do curl http://localhost:8080; sleep 3;  done
Q:	What's the difference between an Irish wedding and an Irish wake?
A:	One less drunk.
Your lucky number is 3552664958674928.  Watch for it everywhere.
Your lucky number is 3552664958674928.  Watch for it everywhere.
...

通过ConfigMap配置应用程序

ConfigMap也是我们最常用的配置服务的方式了

我们现在为财富鸡汤服务创建一个配置文件

# cat fortune-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fortune-config
data:
  sleep-interval: "25"

ConfigMap还有其他方式创建,不过yaml方式是我们推荐经常使用的,其他方式不做练习了。

create并get,使用-o yaml配合get可以获得最全的yaml描述

$ kubectl create -f fortune-config.yaml                                                                                                                                      130 ↵
configmap/fortune-config created

$ kubectl get configmap/fortune-config -o yaml
apiVersion: v1
data:
  sleep-interval: "25"
kind: ConfigMap
metadata:
  creationTimestamp: "2020-01-10T12:48:10Z"
  name: fortune-config
  namespace: liuzongxian
  resourceVersion: "86688245"
  selfLink: /api/v1/namespaces/liuzongxian/configmaps/fortune-config
  uid: 74ec7700-33a7-11ea-bb51-3a8f4bdea85b

上述data部分就是我们的配置了,现在我们使用这个配置来为服务设置环境变量(这个操作和传统开发不一样吧)

# cat fortune-pod-env-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: fortune-env-from-configmap
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: INTERVAL
      valueFrom:             #这段控制了环境变量来自配置
        configMapKeyRef:
          name: fortune-config #配置文件名
          key: sleep-interval  #具体数据的key
    name: html-generator
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
  volumes:
  - name: html
    emptyDir: {}
$ k create -f fortune-pod-env-configmap.yaml
pod/fortune-env-from-configmap created

$ k get all
NAME                             READY   STATUS    RESTARTS   AGE
pod/fortune-env                  2/2     Running   0          14m
pod/fortune-env-from-configmap   2/2     Running   0          4s

同样使用port-forward看下调用下服务吧,这里不贴出结果

$ k port-forward fortune-env-from-configmap 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

从上面的实例可以看出ConfigMap是一个含有数据的资源,它能借助kubernetes转为容器所使用的环境变量、参数、甚至是文件。

将ConfigMap暴露为pod中的文件

拿上述服务中的nginx做这个实验,先看看它的配置文件,我们尝试控制它是否开启压缩

# cat my-nginx-config.conf
server {
    listen              80;
    server_name         www.kubia-example.com;

    gzip on;
    gzip_types text/plain application/xml;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

}

可以将这个文件直接创建成ConfigMap,见

出现命名冲突,记得清理自己空间以前部署的资源

#删掉重建
$ k delete configmap fortune-config                                                                                                                                            1 ↵
configmap "fortune-config" deleted

$ kubectl create configmap fortune-config --from-file=configmap-files
configmap/fortune-config created

我们使用的是文件夹,里面含有两个文件,从configmap中能看出

$ kubectl get configmap fortune-config -o yaml
apiVersion: v1
data:
  my-nginx-config.conf: |
    server {
        listen              80;
        server_name         www.kubia-example.com;

        gzip on;
        gzip_types text/plain application/xml;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

    }
  sleep-interval: |
    25
kind: ConfigMap
metadata:
  ... ...
  ... ...

有my-nginx-config.conf和sleep-interval两个,那我们使用他们

后面yaml文件都可能都会有点大,大家能理解大概就可以了,不过这个文件比较典型,先努力读懂它

# cat fortune-pod-configmap-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: fortune-configmap-volume
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: INTERVAL
      valueFrom:
        configMapKeyRef:
          name: fortune-config
          key: sleep-interval
    name: html-generator
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    - name: config
      mountPath: /etc/nginx/conf.d
      readOnly: true
    - name: config
      mountPath: /tmp/whole-fortune-config-volume
      readOnly: true
    ports:
      - containerPort: 80
        name: http
        protocol: TCP
  volumes:
  - name: html
    emptyDir: {}
  - name: config      #guan
    configMap:
      name: fortune-config

部署上,看看效果

$ kubectl create -f fortune-pod-configmap-volume.yaml                                                                                                                          1 ↵
pod/fortune-configmap-volume created

$ k port-forward fortune-configmap-volume 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

在另外一个控制台,curl能看到开启了gzip

$ curl -H "Accept-Encoding: gzip" -I localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.17.7
Date: Fri, 10 Jan 2020 13:59:24 GMT
Content-Type: text/html
Last-Modified: Fri, 10 Jan 2020 13:59:03 GMT
Connection: keep-alive
ETag: W/"5e188327-5c"
Content-Encoding: gzip

Well!现在我们体验了如何在kubernetes中为自己的应用使用配置文件,这样一来我们发版管理配置是不是更方便了呢?

通过Secret传递敏感配置信息

有时我们有一些账号密码不能明文,kubernetes提供了Secret资源和ConfigMap使用非常相似,只是对文本加密了而已。

我们常见的是给阿里云、亚马逊的密钥做加密处理,这些密钥是用来控制权限访问云商资源的。

首先创建一个secret

$ k create secret generic ali-key --from-literal=key=1234567890abcdefghijk --from-literal=secret=secret1234567890abcdefg
secret/ali-key created

查看已经创建的secret

$ k get secret                                                                                                                                          1 ↵
NAME                  TYPE                                  DATA   AGE
ali-key               Opaque                                2      9s

$ k describe secret ali-key
Name:         ali-key
Namespace:    liuzongxian
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
key:     21 bytes
secret:  23 bytes

我们现在就可以使用secret了,写一个yaml

apiVersion: batch/v1
kind: CronJob
metadata:
  name: package-test
spec:
  schedule: "*/2 * * * *"
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: package-test
        spec:
          restartPolicy: OnFailure
          containers:
            - name: main
              image: registry.cn-hangzhou.aliyuncs.com/hio-open-image/hio-open:1.0.7
              imagePullPolicy: Always
              command: ["sh"]
              args: ["-c", "echo $accesskeyid $accesskeysecret"]
              env:
                - name: env
                  value: "tests"
                - name: accesskeyid
                  valueFrom:
                    secretKeyRef:
                      name: ali-key
                      key: key
                - name: accesskeysecret
                  valueFrom:
                    secretKeyRef:
                      name: ali-key
                      key: secret
                - name: parentPackageId
                  value: "2"
                - name: taskId
                  value: "3"
                - name: parentPackageOssKey
                  value: "channelpkg/2020/05/27/01/channelDemo_1.0.0.apk"
                - name: packageInfos
                  value: "11:1111,22:2222,33:3333"

将它保存到文件 package-test.yaml,执行

k apply -f package-test.yaml

它是一个cronjob,每两分钟运行一次作业(启动一个pod),我们的作业就是简单的打印环境变量 key和secret。

思考题

  • 请谈谈都有哪几种配置应用的方式,和传统开发的区别

最后更新于