ConfigMap和Secret:配置应用程序
配置容器化应用程序
通常的容器化应用配置:
- 配置嵌入应用本身(不推荐)
- 以命令行参数形式配置应用,配置选项多时,将配置文件化
- 读取环境变量
相比使用配置文件,优势是不用重新打包
相比挂载卷,挂载卷需要在容器启动前确保配置文件已写入响应的卷中。(挂载卷因此可以使用gitRepo卷用git仓库管理配置)
向容器传递命令行参数
docker中定义命令和参数
ENTRYPOINT、CMD
Dockerfile的ENTRYPOINT定义容器启动时被调用的可执行程序,CMD指定传递给前者的参数。
尽管可以直接使用CMD指令指定镜像运行时想要执行的命令, 正确的做法依旧是借助ENTRYPOINT指令, 仅仅用CMD指定所需的默认参数。
之后,可以直接运行:docker run <image> <arguments>
,传参数会覆盖CMD指定的参数。
shell形式:ENTRYPOINT node app.js
exec形式:ENTRYPOINT [“node”, “app. js”]
区别是是否在shell中被调用。shell往往多余,可以直接使用exec形式调用。
准备好脚本文件
# 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
# 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中覆盖命令和参数
在kubernetes定义容器时,镜像的ENTRYPOINT和CMD可以被覆盖
kind: Pod
spec:
containers:
- image: arrowarcher/fortune:args
command: ["/bin/command"] # 覆盖ENTRYPOINT
args: ["args0","args1"] # 覆盖CMD
自定义间隔运行fortune pod
fortune-pod-args.yaml
提示:
args: ["2"] # 少参数
# or
args: # 多参数
- foo
- bar
- "2"
pod测试结果:
每2秒切换一次index.html
(使用了kubectl port-forward fortune2s 8081:80
转发到80端口)
为容器设置环境变量
容器化应用通常使用环境变量作为配置源。
kind: Pod
spec:
containers:
- image: arrowarcher/fortune:env
env:
- name: INTERVAL
value: "30"
注意:
每个容器中还会包含同命名空间里每个service对应的环境变量
# 环境变量引用别的环境变量的值
env:
- name: B1
value: "foo"
- name: B2
value: "$(B1)bar"
ConfigMap解耦配置
能够在多个环境中区分配置选项。
ConfigMap介绍
如图使用,应用程序虽然也可以通过kubernetes API直接读取ConfigMap,但应该尽可能保持对kubernetes无感知。
创建 ConfigMap
直接创建
kubectl create configmap fortune-config --from-literal=sleep-interval=25
创建了fortune-config,包含sleep-interval=25的键值。
添加–from-literal=key=value可以添加多个条目
# kubectl create -f的方式创建
apiVersion: v1
data:
sleep-interval: "25"
kind: ConfigMap
metadata:
name: fortune-config
从文件创建
kubectl create configmap my-config --from-file=config-file.conf
此时键名为config-file.conf,值是文件内容。
kubectl create configmap my-config --from-file=customkey=config-file.conf
手动指定键名。
一样可以加多个条目(–from-file)
从文件夹
kubectl create configmap my-config --from-file=/path/to/dir
此时文件名必须是合规的。
可以同时使用。
给容器传递ConfigMap条目作为环境变量
创建好ConfigMap后传递给pod使用。
如果ConfigMap不存在,对应的容器将会启动失败,其余正常,之后创建ConfigMap将会自动启动。
设置环境变量
# 单传递条目
containers:
- image: luksa/fortune:env
env:
- name: INTERVAL # 设置环境变量INTERVAL
valueFrom:
configMapKeyRef: # ConfigMap初始化
name: fortune-config # 引用ConfigMap名称
key: sleep-interval # 环境变量的值为sleep-interval的值
# 所有条目,使用envForm
containers:
- image: luksa/fortune:env
envForm:
- prefix: CONFIG_ # 为环境变量设置前缀,可选,不设置将与ConfigMap键名一样
configMapKeyRef: # ConfigMap初始化
name: fortune-config # 引用ConfigMap名称
多个条目时,如果ConfigMap的某键名格式不正确,创建环境变量时会忽略对应的条目(忽略时不会发出事件通知)。
传递ConfigMap条目作为命令行参数
需要先初始化环境变量,再在参数字段中引用改变量
# 单传递条目
containers:
- image: luksa/fortune:env
env:
- name: INTERVAL # 设置环境变量INTERVAL
valueFrom:
configMapKeyRef: # ConfigMap初始化
name: fortune-config # 引用ConfigMap名称
key: sleep-interval # 环境变量的值为sleep-interval的值
args: ["$(INTERVAL)"]
使用 configMap 卷将条目暴露为文件(适合大配置)
创建ConfigMap
nginx配置文件(开启了gzip压缩)和值文件:
configmap-files
如图包含了目录下所有文件的内容。键名与文件名相同。
在卷内使用ConfigMap 的条目
fortune-pod-configmap-volume.yaml
总的来说就是挂载一个卷,卷定义指定configMap,挂载位置是/etc/nginx/conf.d。
创建pod并端口转发:
查看ConfigMap两个条目所在文件夹:
如果只暴露其中一个条目可以使用items
volumes:
- name: config
configMap:
name: fortune-config
items:
- key: my-nginx-config.conf
path: gzip.conf # 值储存位置
注意:挂载卷时如果目录下已经存在文件,都会被隐藏,可能导致容器损坏(比如/etc)
volumeMount额外的subPath字段可以用来挂载卷中的某个独立文件或文件集,无需挂载完整卷。这样不会隐藏现有文件
volumeMounts:
- name: config # 挂载configMap卷
mountPath: /etc/some.conf # 挂载成文件而不是目录
subPath: myconfig.conf # 要挂载的文件
configMap卷中的文件权限
默认为644 (-rw-r-r–)。
可以使用卷规格定义中的defaultMode属性改变默认权限
fortune-pod-configmap-volume-defaultMode.yaml
Config更新后可以不重启应用程序
使用环境变量或者命令行参数作为配置源的弊端在于无法在进程运行时更新配置。 将ConfigMap暴露为卷可以达到配置热更新的效果, 无须重新创建pod或者重启容器,进程发现文件被改变之后进行重载。
修改之前的configmap
kubectl edit configmap fortune-config
gzip on ->gzip off
查看容器内部:
由于nginx不会自动重启,我们手动重启:
2次访问变了,修改配置热更新成功!
k8s是通过符号链接更新configMap卷的文件的:
配置更新后会将…data链接至新文件夹(重新写入所有文件)
如果挂载的是容器中的单个文件而不是完整的卷, ConfigMap更新之后对应的文件不会被更新!至少书中当时是如此。
总结
更新 ConfigMap 后:
使用该 ConfigMap 挂载的 Env 不会同步更新
使用该 ConfigMap 挂载的 Volume 中的数据需要一小段时间才能同步更新。
使用Secret给容器传递敏感数据
介绍Secret
Secret和ConfigMap不仅结构类似(键值对),使用方法也相同,作环境变量(不安全),作卷。。。但是Secret只分发到pod所在节点的内存里,不写入物理储存,这样从节点上删除Secret时不用擦除磁盘了。
每个pod有个默认挂载的Secret,包含了pod内部安全访问kubernetes API服务器的全部信息。
使用私有镜像仓库时就需要secret
- 创建包含 Docker 镜像仓库证书的 Secret。
kubectl create secret docker-registry mydockerhubsecret \
--docker-username=myusername --docker-password=mypassword \
--docker-email=my.email@provider.com
- pod定义中的 imagePullSecrets 宇段引用该Secret
其实不用为每个pod引用secret拉取镜像,可以添加secret至serviceAccount使所有pod自动添加镜像拉取secret。