ConfigMap和Secret:配置应用程序

更改容器的主进程

我们需要一个可以用配置控制进程的服务,例如配置不同参数,程序表现不一样,我们看下这个程序
1
# cat fortuneloop.sh
2
#!/bin/bash
3
trap "exit" SIGINT
4
5
INTERVAL=$1 #默认值来自命令行参数
6
echo Configured to generate new fortune every $INTERVAL seconds
7
8
mkdir -p /var/htdocs
9
10
while :
11
do
12
echo $(date) Writing fortune to /var/htdocs/index.html
13
/usr/games/fortune > /var/htdocs/index.html
14
sleep $INTERVAL
15
done
Copied!
里面有个环境变量INTERVAL可以控制休眠的时间长短(默认值来自命令行参数),也就控制了fortune财富“鸡汤“的变化速度,我们来用Dockerfile制作这个服务
1
# cat Dockerfile
2
FROM ubuntu:latest
3
4
RUN apt-get update ; apt-get -y install fortune
5
ADD fortuneloop.sh /bin/fortuneloop.sh
6
7
ENTRYPOINT ["/bin/fortuneloop.sh"]
8
CMD ["10"]
Copied!
大家看懂服务逻辑就行了,镜像已经制作好了的。我们直接进入kubernetes部署环节

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

见pod描述文件
1
# cat fortune-pod-args.yaml
2
apiVersion: v1
3
kind: Pod
4
metadata:
5
name: fortune2s
6
spec:
7
containers:
8
- image: luksa/fortune:args #生产财富鸡汤
9
args: ["2"] #默认2秒
10
name: html-generator
11
volumeMounts:
12
- name: html
13
mountPath: /var/htdocs
14
- image: nginx:alpine #对外提供服务
15
name: web-server
16
volumeMounts:
17
- name: html
18
mountPath: /usr/share/nginx/html
19
readOnly: true
20
ports:
21
- containerPort: 80
22
protocol: TCP
23
volumes:
24
- name: html
25
emptyDir: {}
Copied!
create试试看(可以跳过),因为上面的INTERVAL是来自命令行,所以结果可想而知频率是固定的2秒。

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

1
# cat fortune-pod-env.yaml
2
apiVersion: v1
3
kind: Pod
4
metadata:
5
name: fortune-env
6
spec:
7
containers:
8
- image: luksa/fortune:env
9
env: #和上面不一样,增加了环境变量
10
- name: INTERVAL
11
value: "30" #30s
12
name: html-generator
13
volumeMounts:
14
- name: html
15
mountPath: /var/htdocs
16
- image: nginx:alpine
17
name: web-server
18
volumeMounts:
19
- name: html
20
mountPath: /usr/share/nginx/html
21
readOnly: true
22
ports:
23
- containerPort: 80
24
protocol: TCP
25
volumes:
26
- name: html
27
emptyDir: {}
Copied!
create试试,我们继续使用port-forward代理访问pod端口
1
$ k create -f fortune-pod-env.yaml
2
pod/fortune-env created
3
4
$ k port-forward fortune-env 8080:80 1 ↵
5
Forwarding from 127.0.0.1:8080 -> 80
6
Forwarding from [::1]:8080 -> 80
Copied!
然后在另一个控制台访问,观察是否设定的环境变量秒数
1
$ while True; do curl http://localhost:8080; sleep 3; done
Copied!

通过ConfigMap配置应用程序

ConfigMap也是我们最常用的配置服务的方式了
我们现在为财富鸡汤服务创建一个配置文件
1
# cat fortune-config.yaml
2
apiVersion: v1
3
kind: ConfigMap
4
metadata:
5
name: fortune-config
6
data:
7
sleep-interval: "25"
Copied!
ConfigMap还有其他方式创建,不过yaml方式是我们推荐经常使用的,其他方式不做练习了。
create并get,使用-o yaml配合get可以获得最全的yaml描述
1
$ kubectl create -f fortune-config.yaml 130 ↵
2
configmap/fortune-config created
3
4
$ kubectl get configmap/fortune-config -o yaml
5
apiVersion: v1
6
data:
7
sleep-interval: "25"
8
kind: ConfigMap
9
metadata:
10
creationTimestamp: "2020-01-10T12:48:10Z"
11
name: fortune-config
12
namespace: liuzongxian
13
resourceVersion: "86688245"
14
selfLink: /api/v1/namespaces/liuzongxian/configmaps/fortune-config
15
uid: 74ec7700-33a7-11ea-bb51-3a8f4bdea85b
Copied!
上述data部分就是我们的配置了,现在我们使用这个配置来为服务设置环境变量(这个操作和传统开发不一样吧)
1
# cat fortune-pod-env-configmap.yaml
2
apiVersion: v1
3
kind: Pod
4
metadata:
5
name: fortune-env-from-configmap
6
spec:
7
containers:
8
- image: luksa/fortune:env
9
env:
10
- name: INTERVAL
11
valueFrom: #这段控制了环境变量来自配置
12
configMapKeyRef:
13
name: fortune-config #配置文件名
14
key: sleep-interval #具体数据的key
15
name: html-generator
16
volumeMounts:
17
- name: html
18
mountPath: /var/htdocs
19
- image: nginx:alpine
20
name: web-server
21
volumeMounts:
22
- name: html
23
mountPath: /usr/share/nginx/html
24
readOnly: true
25
ports:
26
- containerPort: 80
27
protocol: TCP
28
volumes:
29
- name: html
30
emptyDir: {}
Copied!
1
$ k create -f fortune-pod-env-configmap.yaml
2
pod/fortune-env-from-configmap created
3
4
$ k get all
5
NAME READY STATUS RESTARTS AGE
6
pod/fortune-env 2/2 Running 0 14m
7
pod/fortune-env-from-configmap 2/2 Running 0 4s
Copied!
同样使用port-forward看下调用下服务吧,这里不贴出结果
1
$ k port-forward fortune-env-from-configmap 8080:80
2
Forwarding from 127.0.0.1:8080 -> 80
3
Forwarding from [::1]:8080 -> 80
Copied!
从上面的实例可以看出ConfigMap是一个含有数据的资源,它能借助kubernetes转为容器所使用的环境变量、参数、甚至是文件。

将ConfigMap暴露为pod中的文件

拿上述服务中的nginx做这个实验,先看看它的配置文件,我们尝试控制它是否开启压缩
1
# cat my-nginx-config.conf
2
server {
3
listen 80;
4
server_name www.kubia-example.com;
5
6
gzip on;
7
gzip_types text/plain application/xml;
8
9
location / {
10
root /usr/share/nginx/html;
11
index index.html index.htm;
12
}
13
14
}
Copied!
可以将这个文件直接创建成ConfigMap,见
出现命名冲突,记得清理自己空间以前部署的资源
1
#删掉重建
2
$ k delete configmap fortune-config 1
3
configmap "fortune-config" deleted
4
5
$ kubectl create configmap fortune-config --from-file=configmap-files
6
configmap/fortune-config created
Copied!
我们使用的是文件夹,里面含有两个文件,从configmap中能看出
1
$ kubectl get configmap fortune-config -o yaml
2
apiVersion: v1
3
data:
4
my-nginx-config.conf: |
5
server {
6
listen 80;
7
server_name www.kubia-example.com;
8
9
gzip on;
10
gzip_types text/plain application/xml;
11
12
location / {
13
root /usr/share/nginx/html;
14
index index.html index.htm;
15
}
16
17
}
18
sleep-interval: |
19
25
20
kind: ConfigMap
21
metadata:
22
... ...
23
... ...
Copied!
有my-nginx-config.conf和sleep-interval两个,那我们使用他们
后面yaml文件都可能都会有点大,大家能理解大概就可以了,不过这个文件比较典型,先努力读懂它
1
# cat fortune-pod-configmap-volume.yaml
2
apiVersion: v1
3
kind: Pod
4
metadata:
5
name: fortune-configmap-volume
6
spec:
7
containers:
8
- image: luksa/fortune:env
9
env:
10
- name: INTERVAL
11
valueFrom:
12
configMapKeyRef:
13
name: fortune-config
14
key: sleep-interval
15
name: html-generator
16
volumeMounts:
17
- name: html
18
mountPath: /var/htdocs
19
- image: nginx:alpine
20
name: web-server
21
volumeMounts:
22
- name: html
23
mountPath: /usr/share/nginx/html
24
readOnly: true
25
- name: config
26
mountPath: /etc/nginx/conf.d
27
readOnly: true
28
- name: config
29
mountPath: /tmp/whole-fortune-config-volume
30
readOnly: true
31
ports:
32
- containerPort: 80
33
name: http
34
protocol: TCP
35
volumes:
36
- name: html
37
emptyDir: {}
38
- name: config #guan
39
configMap:
40
name: fortune-config
Copied!
部署上,看看效果
1
$ kubectl create -f fortune-pod-configmap-volume.yaml 1 ↵
2
pod/fortune-configmap-volume created
3
4
$ k port-forward fortune-configmap-volume 8080:80
5
Forwarding from 127.0.0.1:8080 -> 80
6
Forwarding from [::1]:8080 -> 80
Copied!
在另外一个控制台,curl能看到开启了gzip
1
$ curl -H "Accept-Encoding: gzip" -I localhost:8080
2
HTTP/1.1 200 OK
3
Server: nginx/1.17.7
4
Date: Fri, 10 Jan 2020 13:59:24 GMT
5
Content-Type: text/html
6
Last-Modified: Fri, 10 Jan 2020 13:59:03 GMT
7
Connection: keep-alive
8
ETag: W/"5e188327-5c"
9
Content-Encoding: gzip
Copied!
Well!现在我们体验了如何在kubernetes中为自己的应用使用配置文件,这样一来我们发版管理配置是不是更方便了呢?

通过Secret传递敏感配置信息

有时我们有一些账号密码不能明文,kubernetes提供了Secret资源和ConfigMap使用非常相似,只是对文本加密了而已。
我们常见的是给阿里云、亚马逊的密钥做加密处理,这些密钥是用来控制权限访问云商资源的。
首先创建一个secret
1
k create secret generic ali-key --from-literal=key=1234567890abcdefghijk --from-literal=secret=secret1234567890abcdefg
Copied!
查看已经创建的secret
1
$ k get secret 1 ↵
2
NAME TYPE DATA AGE
3
ali-key Opaque 2 9s
4
5
$ k describe secret ali-key
6
Name: ali-key
7
Namespace: liuzongxian
8
Labels: <none>
9
Annotations: <none>
10
11
Type: Opaque
12
13
Data
14
====
15
key: 21 bytes
16
secret: 23 bytes
Copied!
我们现在就可以使用secret了,写一个yaml
1
apiVersion: batch/v1beta1
2
kind: CronJob
3
metadata:
4
name: package-test
5
spec:
6
schedule: "*/2 * * * *"
7
jobTemplate:
8
spec:
9
template:
10
metadata:
11
labels:
12
app: package-test
13
spec:
14
restartPolicy: OnFailure
15
containers:
16
- name: main
17
image: registry.cn-hangzhou.aliyuncs.com/hio-open-image/hio-open:1.0.7
18
imagePullPolicy: Always
19
command: ["sh"]
20
args: ["-c", "echo $accesskeyid $accesskeysecret"]
21
env:
22
- name: env
23
value: "tests"
24
- name: accesskeyid
25
valueFrom:
26
secretKeyRef:
27
name: ali-key
28
key: key
29
- name: accesskeysecret
30
valueFrom:
31
secretKeyRef:
32
name: ali-key
33
key: secret
34
- name: parentPackageId
35
value: "2"
36
- name: taskId
37
value: "3"
38
- name: parentPackageOssKey
39
value: "channelpkg/2020/05/27/01/channelDemo_1.0.0.apk"
40
- name: packageInfos
41
value: "11:1111,22:2222,33:3333"
42
Copied!
将它保存到文件 package-test.yaml,执行
1
k apply -f package-test.yaml
2
Copied!
它是一个cronjob,每两分钟运行一次作业(启动一个pod),我们的作业就是简单的打印环境变量 key和secret。

思考题

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