kubernetes学习-配置管理(九)
一、ConfigMap
(1)通过指定目录,创建configmap
# 创建一个config目录
[root@k8s-master k8s]# mkdir config
[root@k8s-master k8s]# cd config/
[root@k8s-master config]# mkdir test
[root@k8s-master config]# cd test
[root@k8s-master test]# vim db.properties
username=root
password=admin
[root@k8s-master test]# vim redis.properties
host: 127.0.0.1
port: 6379
[root@k8s-master test]# cd ..
# 创建configmap
[root@k8s-master config]# kubectl create configmap test-dir-config --from-file=test/
configmap/test-dir-config created
# 查看configmap
[root@k8s-master config]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 32h
test-dir-config 2 18s
[root@k8s-master config]# kubectl describe cm test-dir-config
Name: test-dir-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
db.properties:
----
username=root
password=admin
redis.properties:
----
host: 127.0.0.1
port: 6379
BinaryData
====
Events: <none>
(2)通过指定文件的方式创建configmap
[root@k8s-master config]# vim application.yaml
spring:
application:
name: test-app
server:
port: 8080
# 通过指定文件的方式,创建configmap
[root@k8s-master config]# kubectl create cm spring-boot-test-yaml --from-file=/opt/k8s/config/application.yaml
configmap/spring-boot-test-yaml created
# 查看configmap
[root@k8s-master config]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 32h
spring-boot-test-yaml 1 6s
test-dir-config 2 9m2s
# 查看configmap内容
[root@k8s-master config]# kubectl describe cm spring-boot-test-yaml
Name: spring-boot-test-yaml
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
application.yaml:
----
spring:
application:
name: test-app
server:
port: 8080
BinaryData
====
Events: <none>
# 指定文件时,同时指定别名为app.yaml
[root@k8s-master config]# kubectl create cm spring-boot-test-alias-yaml --from-file=app.yaml=/opt/k8s/config/application.yaml
configmap/spring-boot-test-alias-yaml created
[root@k8s-master config]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 32h
spring-boot-test-alias-yaml 1 5s
spring-boot-test-yaml 1 4m25s
test-dir-config 2 13m
[root@k8s-master config]# kubectl describe cm spring-boot-test-alias-yaml
Name: spring-boot-test-alias-yaml
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
app.yaml: # 这里的文件名称就被修改为了指定的别名
----
spring:
application:
name: test-app
server:
port: 8080
BinaryData
====
Events: <none>
# 通过key value的形式指定
[root@k8s-master config]# kubectl create cm test-key-value-config --from-literal=username=root --from-literal=password=root
configmap/test-key-value-config created
[root@k8s-master config]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 32h
spring-boot-test-alias-yaml 1 3m29s
spring-boot-test-yaml 1 7m49s
test-dir-config 2 16m
test-key-value-config 2 5s
[root@k8s-master config]# kubectl describe cm test-key-value-config
Name: test-key-value-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
password:
----
root
username:
----
root
BinaryData
====
Events: <none>
(3)使用configmap
[root@k8s-master config]# kubectl create configmap test-env-config --from-literal=JAVA_OPTS_TEST='-Xms512m -Xmx512m' --from-literal=APP_NAME=springboot
configmap/test-env-config created
[root@k8s-master config]# kubectl describe configmap/test-env-config
Name: test-env-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
APP_NAME:
----
springboot
JAVA_OPTS_TEST:
----
-Xms512m -Xmx512m
BinaryData
====
Events: <none>
# 创建配置文件
[root@k8s-master config]# vim env-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-env-po
spec:
containers:
- name: env-test
image: alpine
command: ["/bin/sh", "-c", "env;sleep 3600"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_VM_OPTS
valueFrom:
configMapKeyRef:
name: test-env-config # configMap的名字
key: JAVA_OPTS_TEST # 表示从name 为 test-env-config配置中找到key为JAVA_OPTS_TEST的value,赋值给JAVA_VM_OPTS
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config
key: APP_NAME
restartPolicy: Never
[root@k8s-master config]# kubectl create -f env-test-pod.yaml
pod/test-env-cm created
[root@k8s-master config]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-778cb6d6f7-hmhcx 1/1 Running 1 (2m7s ago) 2d21h
test-env-po 1/1 Running 0 5s
[root@k8s-master config]# kubectl logs -f test-env-po
NGINX_SVC_SERVICE_HOST=10.106.43.135
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=test-env-po
NGINX_SVC_EXTERNAL_SERVICE_HOST=10.96.11.222
SHLVL=1
HOME=/root
JAVA_VM_OPTS=-Xms512m -Xmx512m
NGINX_SVC_SERVICE_PORT=80
NGINX_SVC_PORT=tcp://10.106.43.135:80
NGINX_SVC_EXTERNAL_PORT=tcp://10.96.11.222:80
NGINX_SVC_EXTERNAL_SERVICE_PORT=80
NGINX_SVC_SERVICE_PORT_WEB=80
NGINX_SVC_PORT_80_TCP_ADDR=10.106.43.135
APP=springboot
NGINX_SVC_EXTERNAL_SERVICE_PORT_WEB=80
NGINX_SVC_PORT_80_TCP_PORT=80
NGINX_SVC_PORT_80_TCP_PROTO=tcp
NGINX_SVC_EXTERNAL_PORT_80_TCP_ADDR=10.96.11.222
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_SVC_EXTERNAL_PORT_80_TCP_PORT=80
NGINX_SVC_EXTERNAL_PORT_80_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
NGINX_SVC_PORT_80_TCP=tcp://10.106.43.135:80
NGINX_SVC_EXTERNAL_PORT_80_TCP=tcp://10.96.11.222:80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
上面的两个值就是之前创建的configmap文件中的值。环境变量被成功加载。
(4)通过文件使用configmap
[root@k8s-master config]# vim file-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-configfile-po
spec:
containers:
- name: env-test
image: alpine
command: ["/bin/sh", "-c", "env;sleep 3600"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_VM_OPTS
valueFrom:
configMapKeyRef:
name: test-env-config # configMap的名字
key: JAVA_OPTS_TEST # 表示从name 为 test-env-config配置中找到key为JAVA_OPTS_TEST的value,赋值给JAVA_VM_OPTS
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config
key: APP_NAME
volumeMounts: # 加载数据卷
- name: db-config # 表示要加载的volumes 的名字
mountPath: "/usr/local/mysql/conf" # 想要将数据卷中的文件加载到哪个目录下
readOnly: true # 是否只读
volumes: # 数据卷挂载 configmap, secret
- name: db-config # 数据卷的名字,自定义设置,使用时要和其对应
configMap: # 数据类型为ConfigMap
name: test-dir-config # configmap 的名字,需要和想加载的configmap的名字相同
items: # 对configmap中的key进行映射,如果不指定,默认会将configmap中所有的key全部转换为一个个同名的文件
- key: "db.properties" # configMap中的key
path: "db.properties" # 将该key的值转换为文件
restartPolicy: Never
[root@k8s-master config]# kubectl create -f file-test-pod.yaml
pod/test-env-po created
[root@k8s-master config]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-778cb6d6f7-hmhcx 1/1 Running 1 (21m ago) 2d21h
test-configfile-po 1/1 Running 0 27s
# 进入容器,查看数据
[root@k8s-master config]# kubectl exec -it test-configfile-po -- sh
/ # cd /usr/local/mysql/conf/
/usr/local/mysql/conf # ls
db.properties
/usr/local/mysql/conf # cat db.properties
username=root
password=admin
在test-dir-config configmap中,有两个文件,分别为db.properties和redis.properties
但是上面我们在容器test-configfile-po 中 查看到只有db.properties被写入到路劲/usr/local/mysql/conf下,这是因为在 file-test-pod.yaml 配置文件中,指定了items,所以只有明确指定了的才会被写入到容器中。
二、加密数据配置 Secret
[root@k8s-master www]# kubectl create secret generic orig-secret --from-literal=username=admin --from-literal=password="ddddddd"
secret/orig-secret created
[root@k8s-master www]# kubectl describe secret orig-secret
Name: orig-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 7 bytes
username: 5 bytes
# 创建docker-registry
[root@k8s-master www]# kubectl create secret docker-registry harbor-secret --docker-username=admin --docker-password=wolfcode --docker-email=xxxx@qq.com
secret/harbor-secret created
[root@k8s-master www]# kubectl describe secret harbor-secret
Name: harbor-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/dockerconfigjson
Data
====
.dockerconfigjson: 136 bytes
# 查看密文值
[root@k8s-master www]# kubectl edit secret harbor-secret
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJhZG1pbiIsInBhc3N3b3JkIjoid29sZmNvZGUiLCJlbWFpbCI6Inh4eHhAcXEuY29tIiwiYXV0aCI6IllXUnRhVzQ2ZDI5c1ptTnZaR1U9In19fQ==
kind: Secret
metadata:
creationTimestamp: "2025-01-21T16:03:22Z"
name: harbor-secret
namespace: default
resourceVersion: "161226"
uid: b997d28d-80a5-483f-bdd3-ac574a2be9ab
type: kubernetes.io/dockerconfigjson
# 查看解码之后的数据
[root@k8s-master www]# echo "eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJhZG1pbiIsInBhc3N3b3JkIjoid29sZmNvZGUiLCJlbWFpbCI6Inh4eHhAcXEuY29tIiwiYXV0aCI6IllXUnRhVzQ2ZDI5c1ptTnZaR1U9In19fQ==" | base64 --decode
{"auths":{"https://index.docker.io/v1/":{"username":"admin","password":"wolfcode","email":"xxxx@qq.com","auth":"YWRtaW46d29sZmNvZGU="}}}
三、SubPath 的使用
[root@k8s-master www]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-778cb6d6f7-hmhcx 1/1 Running 1 (13d ago) 15d
test-configfile-po 0/1 Completed 0 13d
[root@k8s-master www]# kubectl exec -it nginx-deploy-778cb6d6f7-hmhcx -- sh
# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
# pwd
/etc/nginx
# cat nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
[root@k8s-master config]# vim nginx.conf # 将上面的内容复制进去
[root@k8s-master config]#
[root@k8s-master config]# kubectl create configmap nginx-conf-cm --from-file=./nginx.conf
configmap/nginx-conf-cm created
[root@k8s-master config]# kubectl describe cm nginx-conf-cm
Name: nginx-conf-cm
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
nginx.conf:
----
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
BinaryData
====
Events: <none>
把nginx.conf配置放在configmap中,将来修改configmap时,容器里配置文件能够被修改
在nginx-deploy中配置数据卷,
[root@k8s-master config]# kubectl edit deploy nginx-deploy # 编辑内容如下截图
error: deployments.apps "nginx-deploy" is invalid
deployment.apps/nginx-deploy edited
[root@k8s-master config]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 0/1 1 0 15d
发现容器没有启动起来,增加一个命令:
[root@k8s-master config]# kubectl edit deploy nginx-deploy
deployment.apps/nginx-deploy edited
[root@k8s-master config]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deploy-747f54c94b-4h86h 1/1 Running 0 24s
test-configfile-po 0/1 Completed 0 13d
# 进入到容器中的/etc/nginx目录下,发现配置文件只有一个nginx.conf了,其他的文件都被覆盖了
[root@k8s-master config]# kubectl exec -it nginx-deploy-747f54c94b-4h86h -- sh
# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# cd /etc/nginx
# ls
nginx.conf
此时,就需要使用subPath的配置,说明如下:
使用 ConfigMap 或 Secret 挂载到目录的时候,会将容器中源目录给覆盖掉,此时我们可能只想覆盖目录中的某一个文件,但是这样的操作会覆盖整个文件,因此需要使用到 SubPath
配置方式:
定义 volumes 时需要增加 items 属性,配置 key 和 path,且 path 的值不能从 / 开始
在容器内的 volumeMounts 中增加 subPath 属性,该值与 volumes 中 items.path 的值相同
containers:
......
volumeMounts:
- mountPath: /etc/nginx/nginx.conf # 挂载到哪里
name: config-volume # 使用哪个 configmap 或 secret
subPath: etc/nginx/nginx.conf # 与 volumes.[0].items.path 相同
volumes:
- configMap:
name: nginx-conf # configMap 名字
items: # subPath 配置
key: nginx.conf # configMap 中的文件名
path: etc/nginx/nginx.conf # subPath 路径
[root@k8s-master config]# kubectl edit deploy nginx-deploy
deployment.apps/nginx-deploy edited
[root@k8s-master config]# kubectl get po # 正常运行起来了
NAME READY STATUS RESTARTS AGE
nginx-deploy-747f54c94b-4h86h 1/1 Terminating 0 9m46s
nginx-deploy-c57c8cd87-q554h 1/1 Running 0 8s
test-configfile-po 0/1 Completed 0 13d
# 再次进入到容器中,查看配置文件
[root@k8s-master config]# kubectl exec -it nginx-deploy-c57c8cd87-q554h -- sh
# cd /etc/nginx
# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
可以看到此时,其他的配置文件也都存在,没有被覆盖
四、配置的热更新
我们通常会将项目的配置文件作为 configmap 然后挂载到 pod,那么如果更新 configmap 中的配置,会不会更新到 pod 中呢?
这得分成几种情况:
默认方式:会更新,更新周期是更新时间 + 缓存时间
subPath:不会更新
变量形式:如果 pod 中的一个变量是从 configmap 或 secret 中得到,同样也是不会更新的
对于 subPath 的方式,我们可以取消 subPath 的使用,将配置文件挂载到一个不存在的目录,避免目录的覆盖,然后再利用软连接的形式,将该文件链接到目标位置
但是如果目标位置原本就有文件,可能无法创建软链接,此时可以基于前面讲过的 postStart 操作执行删除命令,将默认的吻技安删除即可
1、 通过 edit 命令直接修改 configmap
2、 通过 replace 替换
由于 configmap 我们创建通常都是基于文件创建,并不会编写 yaml 配置文件,因此修改时我们也是直接修改配置文件,而 replace 是没有 --from-file 参数的,因此无法实现基于源配置文件的替换,此时我们可以利用下方的命令实现
# 该命令的重点在于 --dry-run 参数,该参数的意思打印 yaml 文件,但不会将该文件发送给 apiserver,再结合 -oyaml 输出 yaml 文件就可以得到一个配置好但是没有发给 apiserver 的文件,然后再结合 replace 监听控制台输出得到 yaml 数据即可实现替换
kubectl create cm --from-file=nginx.conf --dry-run -oyaml | kubectl replace -f-
视频参考:https://www.bilibili.com/video/BV1MT411x7GH?spm_id_from=333.788.player.switch&vd_source=d94e478a38d57da19b28f12887099880&p=58
五、不可变的 Secret 和 ConfigMap
对于一些敏感服务的配置文件,在线上有时是不允许修改的,此时在配置 configmap 时可以设置 immutable: true 来禁止修改