容器化应用配置方式
configMap,secret是k8s上2种特殊的存储卷,功能:被pod挂载,为pod提供非敏感和敏感的配置信息或文件;
针对容器化容器,其配置方式通常有以下5种方式:
- 命令行传参:启动容器时,docker run image-name [command...] [args..]
- 环境变量传参:启动容器时,docker run xx -e var1=v1 -e var2=v2 ...
- 配置文件打入镜像:不像命令行和环境变量传参,直接传递较为简单的kv类型的配置信息,可以传递整个文件
- 借助普通存储卷挂在节点上预先放置的配置文件:可传递整个文件,但考虑到pod的动态性,需要集群中每个节点都放置一份配置文件显然不够灵活
- k8s的特殊卷:configmap和secret:借助这2种存储卷,可以将配置文件,证书,密钥等敏感信息都创建为标准k8s资源,从而在pod中引用,以存储卷方式引用,或envFrom字段以环境变量方式引入
命令行参数配置应用
docker:entrypoint和cmd
制作docker镜像时,entrypoint分别代表,启动为容器时要运行的程序和其参数;
k8s:command和args
定义pod中containers字段时,其中command和args分别代表,传递给容器的,要其运行的程序和其参数;可覆盖镜像中写好的程序和程序参数
覆盖关系图示:
- pod中的command和args都定义时,分别覆盖镜像中的entrypoint和cmd
- pod中只定义了commnd时,覆盖镜像中的entrypoint和cmd,只运行定义的command
- pod中只定义了args时,将覆盖镜像中的cmd参数,args作为entrypoint的参数
- pod中的command和args都未定义时,采用镜像中默认的entrypoint和cmd
示例
pod中定义了command和args
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: b1
image: busybox
command:
- httpd
args:
- -f
httpd -f 覆盖了busybox镜像中定义的/bin/sh -c
[root@client pod]# kubectl exec pod1 -c b1 -i -t -- /bin/sh -il
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 httpd -f
35 root 0:00 /bin/sh -il
39 root 0:00 ps -ef
pod中定义了args
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: b1
image: busybox
args:
- httpd
- -f
传递的args,作为busybox镜像的entrypoint程序的参数 /bin/sh -c httpd -f
相当于在shell窗口,执行了httpd -f命令,效果和上面的pod相当
[root@client pod]# kubectl exec pod2 -i -t -- /bin/sh -il
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 httpd -f
5 root 0:00 /bin/sh -il
9 root 0:00 ps -ef
环境变量配置应用
定义pod中容器时,可以通过env字段,向其中传递环境变量,环境变量可以被直接引用,也可以通过entrypoint脚本,将其传递到应用的配置文件中,尤其适合云原生应用在容器中执行;
语法:
[root@client pod]# kubectl explain pods.spec.containers.env.
KIND: Pod
VERSION: v1
name <string> -required-
Name of the environment variable. Must be a C_IDENTIFIER.
value <string>
Variable references $(VAR_NAME) are expanded using the previous defined
environment variables in the container and any service environment
variables. If a variable cannot be resolved, the reference in the input
string will be unchanged. The $(VAR_NAME) syntax can be escaped with a
double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,
regardless of whether the variable exists or not. Defaults to "".
valueFrom <Object>
Source for the environment variable's value. Cannot be used if value is not
empty.
env的值,是对象,列表;
变量名,必选
value valuefrom,二选一
value 直接给定变量值,
valuefrom是选择从别处引如变量,共四类:configmap,secret,或pod的属性信息,或资源配额的上限和下限,见下方
---
[root@client pod]# kubectl explain pods.spec.containers.env.valueFrom.
FIELDS:
configMapKeyRef <Object>
Selects a key of a ConfigMap.
fieldRef <Object>
Selects a field of the pod: supports metadata.name, metadata.namespace,
metadata.labels, metadata.annotations, spec.nodeName,
spec.serviceAccountName, status.hostIP, status.podIP.
resourceFieldRef <Object>
Selects a resource of the container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu,
requests.memory and requests.ephemeral-storage) are currently supported.
secretKeyRef <Object>
Selects a key of a secret in the pod's namespace
1、定义pod文件
采用直接给定变量值,和引用元数据信息变量2种方式;
[root@client pod]# cat pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-env
spec:
containers:
- name: busybox
image: busybox
command:
- httpd
args:
- -f
env:
- name: k1
value: v1
- name: node_name
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: node_ip
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: node_ns
valueFrom:
fieldRef:
fieldPath: metadata.namespace
2、打印pod中容器中的环境变量
[root@client pod]# kubectl exec pod-env printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=pod-env
k1=v1
node_name=node2
node_ip=192.168.80.107
node_ns=default
...
3、环境变量传参的缺陷:
是在运行为pod后,根据yaml中定义,将环境变量注入到容器中,即,容器运行中,环境变量无法动态修改;但configmap可以;
configmap配置应用
configmap优势
对于微服务化的分布式应用,大量的应用模块需要频繁的配置,传统的配置文件方式不适用,配置和应用代码耦合度高,改配置有时会修改代码,例如;多套环境下,就需要修改代码引用不同的配置文件,
configmap和secret解耦了配置和应用代码,允许在多套环境中,定义同名的configmap资源,但其内部内容不同,从而pod应用中利用configmap名称调用的configmap,无需做任何修改;
configmap对象,把配置数据,以键值对方式存储其中,pod或其他k8s组件,可以以环境变量、存储卷挂载,2种方式引用;
configmap创建
语法:
kubectl create confimap CONFIG_NAME DADA_SOURCE
data_source是指将要存储到configmap中的数据源,存储形式为键值对,类型有:1、命令行给定kv对,2、指定包含数据的文件,3、指定包含数据文件的目录
[root@client ~]# kubectl create configmap -h
Create a configmap based on a file, directory, or specified literal value.
A single configmap may package one or more key/value pairs.
When creating a configmap based on a file, the key will default to the basename of the file, and the value will default
to the file content. If the basename is an invalid key, you may specify an alternate key.
When creating a configmap based on a directory, each file whose basename is a valid key in the directory will be
packaged into the configmap. Any directory entries except regular files are ignored (e.g. subdirectories, symlinks,
devices, pipes, etc).
Aliases:
configmap, cm
...
基于命令创建
命令行方式,适合量比较少的kv数据
# Create a new configmap named my-config with key1=config1 and key2=config2
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
1,创建
|
|
2,查看
|
|
基于文件创建
基于文件创建的方式,configmap中的key默认为文件路径的basename,也可以手动指定其他的值做key,其值就是整个文件的内容,使用于整个配置文件,如nginx.conf
eg:
# Create a new configmap named my-config from the key=value pairs in the file
kubectl create configmap my-config --from-file=path/to/bar
1、创建
[root@client ~]# kubectl create configmap cm1 --from-file=/etc/fstab
configmap/cm1 created
2、查看
|
|
基于目录创建
将所有配置文件放在一个目录,configmap还可以通过--from-file=/path/to/dir来指定一整个目录,一下子为其下包含所有文件,都创建为一个键值对;
实际中,方便一次用一个configmap包含一批配置文件
eg:
# Create a new configmap named my-config based on folder bar
kubectl create configmap my-config --from-file=path/to/bar
1、创建
|
|
2、查看
|
|
使用清单创建
使用清单创建,使用简单的kv类型数据,若数据源来自文件,或目录,倒不如命令行来的直接,为方便保存,可用命令行创建后,用get cmName -o yaml 输出为yaml文件,保存待用
[root@client cm]# kubectl get cm cm1 -o yaml > cm1.yaml
[root@client cm]# cat cm3.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm3
data:
k3: v3
k4: v4
[root@client cm]# kubectl get cm
NAME DATA AGE
cm1 1 30m
cm2 3 21m
cm3 2 3s
my-config 2 46m
[root@client cm]# kubectl get cm cm3 -o yaml
apiVersion: v1
data:
k3: v3
k4: v4
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"k3":"v3","k4":"v4"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"cm3","namespace":"default"}}
creationTimestamp: 2020-11-20T03:17:33Z
name: cm3
namespace: default
resourceVersion: "432712"
selfLink: /api/v1/namespaces/default/configmaps/cm3
uid: ee714da9-2ade-11eb-8f71-000c292d5d7c
configmap使用
configMpa在pod中使用方式:
There are four different ways that you can use a ConfigMap to configure a container inside a Pod:
Inside a container command and args
Environment variables for a container
Add a file in read-only volume, for the application to read
Write code to run inside the Pod that uses the Kubernetes API to read a ConfigMap
第4种方式,支持动态更新configmap和跨ns引用configmap
configMap配置好后,被pod引用方式:1、通过环境变量pods.spec.containers.env.valueFrom.configMapKeyRef
引用;2、通过卷挂载的方式引用;
向pod环境变量传递configmap键值对
定义cm,和pod
|
|
查看,可以看到,变量已经被正常传递给pod的容器中进程
[root@client cm]# kubectl exec pod-with-cm -- ps -ef
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -p 8080 -vv
5 root 0:00 ps -ef
envfrom批量导入configmap中所有键
采用configMapKeyRef一个个引用confimap中定义的键,针对大量键存在时,效率底下,因此可以用envFrom字段,在其中引用configmMapRef,一次导入configmap中所有的key,且可以导入多个configmap一次性,语法如下:
|
|
1、编写yaml
root@client cm]# cat pod-with-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-busybox
data:
httpd_port: "8080"
httpd_log_level: "-vv"
---
apiVersion: v1
kind: Pod
metadata:
name: pod-with-cm
spec:
containers:
- name: b1
image: busybox
command:
- /bin/httpd
args:
- -f
- -p
- $(httpd_port)
- $(httpd_log_level)
envFrom:
- configMapRef:
name: cm-busybox
2、查看容器中环境变量
^C[root@client cm]# kubectl exec pod-with-cm -- printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=pod-with-cm
httpd_log_level=-vv
httpd_port=8080
configmap以挂载卷使用
cm中不仅可以存储一般的kv类型的值,也可以存储整个文件的内容,适用于为pod中容器提供配置文件;其存储方式也是键值,键是文件名,值是整个文件内容;
使用步骤:
- 定义configmap,其中引用一个或多个配置文件,kubectl explain cm.data
- volumes字段引用上步定义好的cm名称, kubectl explain pods.spec.volumes
- 容器中引用上步定义好的volumes名称,kubectl explain pods.spec.containers.volumeMounts
1、挂载cm中所有文件
创建3个文件,模拟3个nginx的虚拟主机的配置文件,默认情况下,引用的confimap中所有的文件都会被挂载到mountPath目录下;
[root@client cm]# mkdir /tmp/nginx_conf_dir/
[root@client cm]# echo host1.conf > /tmp/nginx_conf_dir/host1.conf
[root@client cm]# echo host2.conf > /tmp/nginx_conf_dir/host2.conf
[root@client cm]# echo host3.conf > /tmp/nginx_conf_dir/host3.conf
[root@client cm]# ll /tmp/nginx_conf_dir/
total 12
-rw-r--r-- 1 root root 11 Nov 22 12:09 host1.conf
-rw-r--r-- 1 root root 11 Nov 22 12:09 host2.conf
-rw-r--r-- 1 root root 11 Nov 22 12:09 host3.conf
示例yaml:
|
|
2、指定挂载cm中部分文件
可以利用pods.spec.volumes.configMap.item字段,只挂载cm中部分的文件到mountPath指定的路径下;
示例yaml:
|
|
3、挂载cm文件时,不覆盖原镜像的文件路径下存在的文件
有时需求会是,挂载cm中文件中时,不覆盖mountPath路径下原有文件,而是添加的方式
示例yaml:
|
|
configmap的动态更新
步骤:
- 更新cm中数据
- 容器中进程,重载配置文件
更新cm:
[root@client cm]# kubectl edit cm cm-nginx
configmap/cm-nginx edited
更新了cm之后,还需要容器中进程,重装配置文件才可,如nginx需要nginx -s reload
,容器中若是不支持热重载配置文件的进程仍需要重新启动pod才可更新cm中数据;
采用subPath挂载的cm中文件不更新动态更新
也非2级软链接方式
[root@client cm]# kubectl exec ngx1 -- ls -lA /usr/share/nginx/html/
total 16
-rw-r--r-- 1 root root 494 Oct 27 15:48 50x.html
-rw-r--r-- 0 root root 20 Nov 22 05:40 host1.conf
-rw-r--r-- 0 root root 11 Nov 22 05:40 host2.conf
-rw-r--r-- 1 root root 612 Oct 27 15:48 index.html
默认挂载方式为2级链接方式,支持动态更新
更新cm时,由..data指向一个新的时间点目录即实现了cm的更新,也即容器内文件更新;
[root@client cm]# kubectl exec ngx1 -- ls -lA /usr/share/nginx/html/
total 0
drwxr-xr-x 2 root root 60 Nov 22 05:51 ..2020_11_22_05_51_33.789268335
lrwxrwxrwx 1 root root 31 Nov 22 05:51 ..data -> ..2020_11_22_05_51_33.789268335
lrwxrwxrwx 1 root root 17 Nov 22 05:51 host1.conf -> ..data/host1.conf
lrwxrwxrwx 1 root root 17 Nov 22 05:51 host2.conf -> ..data/host2.conf
lrwxrwxrwx 1 root root 17 Nov 22 05:51 host3.conf -> ..data/host3.conf
configmap注意事项
-
cofigmap是名称空间级别资源,需要同一个ns内部的pod才可引用;
-
以存储卷方式被引用的configmap需要先于pod被创建,同样被引用到的key都要事先创建;否则pod无法正常启动;
-
以环境变量方式被引用的configmap无需先于pod被创建,pod仍可正常启动;
secret配置应用
secret概述
secret和configmap等同,只是secret是用来存储敏感数据,如密码,密钥,证书,令牌等;
secret也是以键值形式,存储数据,且仅仅分发到调用了secret资源的pod所在的节点的内存中,以base64编码,
用途:
- 提供kubelet用于拉取私有仓库时的认证信息
- pod中容器使用的私密信息存储
- tls的证书和key
secret类型:
常用的3种:
[root@client cm]# kubectl create secret -h
Create a secret using specified subcommand.
Available Commands:
docker-registry Create a secret for use with a Docker registry
用户私有仓库认证信息的
generic Create a secret from a local file, directory or literal value
从命令行,文件,目录中导入数据
tls Create a TLS secret
保存tls证书和key的
完整类型:https://kubernetes.io/docs/concepts/configuration/secret/
Builtin Type | Usage |
---|---|
Opaque |
arbitrary user-defined data |
kubernetes.io/service-account-token |
service account token |
kubernetes.io/dockercfg |
serialized ~/.dockercfg file |
kubernetes.io/dockerconfigjson |
serialized ~/.docker/config.json file |
kubernetes.io/basic-auth |
credentials for basic authentication |
kubernetes.io/ssh-auth |
credentials for SSH authentication |
kubernetes.io/tls |
data for a TLS client or server |
bootstrap.kubernetes.io/token |
bootstrap token data |
创建secret
命令式创建
1、命令行方式创建mysql用户密码
[root@client cm]# kubectl create secret generic auth-mysql --from-literal=user=root --from-literal=password=mysql
secret/auth-mysql created
[root@client cm]# kubectl get secrets
NAME TYPE DATA AGE
auth-mysql Opaque 2 23s
类型为generic/Opaque,编码为base64,
[root@client cm]# kubectl get secrets auth-mysql -o yaml
apiVersion: v1
data:
password: bXlzcWw=
user: cm9vdA==
kind: Secret
metadata:
creationTimestamp: 2020-11-22T06:14:52Z
name: auth-mysql
namespace: default
resourceVersion: "477205"
selfLink: /api/v1/namespaces/default/secrets/auth-mysql
uid: 0851f310-2c8a-11eb-9e9a-000c292d5d7c
type: Opaque
[root@client cm]# echo bX1zcWw= | base64 -d
m}sql[root@client cm]#
其中base64编码不能起到加密效果;
2、命令行方式从文件导入数据
[root@client cm]# kubectl create secret generic fil1 --from-file=s1=/etc/hosts
secret/fil1 created
[root@client cm]# kubectl get secret fil1 -o yaml
apiVersion: v1
data:
s1: MTI3LjAuMC4xICAgbG9jYWxob3N0IGxvY2FsaG9zdC5sb2NhbGRvbWFpbiBsb2NhbGhvc3Q0IGxvY2FsaG9zdDQubG9jYWxkb21haW40Cjo6MSAgICAgICAgIGxvY2FsaG9zdCBsb2NhbGhvc3QubG9jYWxkb21haW4gbG9jYWxob3N0NiBsb2NhbGhvc3Q2LmxvY2FsZG9tYWluNgoxOTIuMTY4LjgwLjEwMSBtYXN0ZXIKMTkyLjE2OC44MC4xMDYgbm9kZTEKMTkyLjE2OC44MC4xMDcgbm9kZTIKMTkyLjE2OC44MC4xMDggbm9kZTMKMTkyLjE2OC44MC4xMDIgY2xpZW50Cg==
kind: Secret
metadata:
creationTimestamp: 2020-11-22T06:19:43Z
name: fil1
namespace: default
resourceVersion: "477647"
selfLink: /api/v1/namespaces/default/secrets/fil1
uid: b5f59d68-2c8a-11eb-9e9a-000c292d5d7c
type: Opaqu
3、命令行方式,创建tls类型的secrets,存储key和证书
生成证书,私钥
[root@client cm]# (umask 077;openssl genrsa -out nginx.key 2048)
Generating RSA private key, 2048 bit long modulus
.........................................................................................+++
............................+++
e is 65537 (0x10001)
[root@client cm]# openssl req -new -x509 -key nginx.key -out nginx.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=www.ilinux.io
创建为tls类型的secrets
Usage:
kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file
[--dry-run] [options]
Use "kubectl options" for a list of global command-line options (applies to all
commands).
[root@client cm]# kubectl create secret tls nginx-cert --cert=./nginx.crt --key=./nginx.key secret/nginx-cert created
[root@client cm]# kubectl get secret
NAME TYPE DATA AGE
auth-mysql Opaque 2 12m
default-token-q6vpk kubernetes.io/service-account-token 3 11d
fil1 Opaque 1 7m18s
nginx-cert kubernetes.io/tls 2 6s
注意:key会统计转为tls.key 和 tls.cert
清单式创建
同样secret的清单式创建反到不如命令行来的简便,可以用命令创建后再输出为yaml文件,用于留档使用;
[root@client secret]# vim s1.yaml
[root@client secret]# cat s1.yaml
apiVersion: v1
kind: Secret
metadata:
name: s1
stringData:
user: wang
pass: linux
type: Opaque
stringdata和data不同的是,后者只能接收base64编码后的键值数据,用户还需手动编码一下;
[root@client secret]# kubectl apply -f s1.yaml
secret/s1 created
[root@client secret]# kubectl get secret s1
NAME TYPE DATA AGE
s1 Opaque 2 8s
[root@client secret]# kubectl get secret s1 -o yaml
apiVersion: v1
data:
pass: bGludXg=
user: d2FuZw==
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"s1","namespace":"default"},"stringData":{"pass":"linux","user":"wang"},"type":"Opaque"}
secret以存储卷使用
secret可以以环境变量和存储卷方式注入到pod中,但环境变量方式存在安全隐患,如环境变量可能会打印到日志中,被子进程继承,因此推荐采用存储卷方式:
1、定义pod
[root@client secret]# vim nginx-with-ssl.yaml
[root@client secret]# kubectl apply -f nginx-with-ssl.yaml
pod/nginx-with-ssl created
[root@client secret]# cat nginx-with-ssl.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-ssl
spec:
containers:
- name: n1
image: nginx:alpine
volumeMounts:
- name: cert
mountPath: /etc/nginx/conf.d/ssl/
volumes:
- name: cert
secret:
secretName: nginx-cert
2、查看
[root@client secret]# kubectl exec nginx-with-ssl -- ls /etc/nginx/conf.d/ssl
tls.crt
tls.key
3、之后,在configmap中引用该处的证书和私钥,即可完成nginx的https配置
imagePullSecret
提供私有仓库的认证信息方式:
- 创建docker-registry类型的secret,在pod中引用;
- 创建docker-registry类型的secret,然后在service-account引用,此后,所有以该service-account运行的pod都可通过私有仓库认证;
imagePullsecret字段引用了docker-registry类型的secret,用于拉取私有镜像仓库的镜像时提供的认证信息;
1、创建docker-registry类型的secret
[root@client secret]# kubectl create secret docker-registry reg1 --docker-username=wang --docker-password=linux --docker-email=wang@gmail.com
secret/reg1 created
[root@client secret]# kubectl get secret reg1 -o yaml
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ3YW5nIiwicGFzc3dvcmQiOiJsaW51eCIsImVtYWlsIjoid2FuZ0BnbWFpbC5jb20iLCJhdXRoIjoiZDJGdVp6cHNhVzUxZUE9PSJ9fX0=
kind: Secret
metadata:
creationTimestamp: 2020-11-22T07:29:36Z
name: reg1
namespace: default
resourceVersion: "483608"
selfLink: /api/v1/namespaces/default/secrets/reg1
uid: 78f26a73-2c94-11eb-9e9a-000c292d5d7c
type: kubernetes.io/dockerconfigjson
[root@client secret]# kubectl get secret reg1
NAME TYPE DATA AGE
reg1 kubernetes.io/dockerconfigjson 1 21s
2、在pod时引用即可
[root@client secret]# cat nginx-with-ssl.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-ssl
spec:
imagePullSecrets:
- name: reg1
小结:
- 总结了配置容器应用的方式:
- 定义pod时,定义启动为容器时命令行传参,command和args字段
- 定义pod时,定义env环境变量字段,可有entrypoint脚本注入到配置文件中
- 配置文件打入镜像
- 将节点预先放置的配置文件以普通存储卷挂载给pod
- configmap和secret