K8S 快速入门(十二)实战篇:配置 ConfigMap&Secret
一、configMap官方文档 ConfigMap1. 动机我们经常都需要为我们的应用程序配置一些特殊的数据,比如密钥、Token 、数据库连接地址或者其他私密的信息。你的应用可能会使用一些特定的配置文件进行配置,比如settings.py文件,或者我们可以在应用的业务逻辑中读取环境变量或者某些标志来处理配置信息。我们要做到这个,有好多种方案,比如:我们可以直接在打包镜像的时候写在应用配置文件里面
一、ConfigMap
1. 动机
我们经常都需要为我们的应用程序配置一些特殊的数据,比如密钥、Token 、数据库连接地址或者其他私密的信息。你的应用可能会使用一些特定的配置文件进行配置,比如settings.py文件,或者我们可以在应用的业务逻辑中读取环境变量或者某些标志来处理配置信息。我们要做到这个,有好多种方案,比如:
- 我们可以直接在打包镜像的时候写在应用配置文件里面,但是这种方式的坏处显而易见而且非常明显。
- 我们可以在配置文件里面通过 env 环境变量传入,但是这样的话我们要修改 env 就必须去修改 yaml 文件,而且需要重启所有的 container 才行。
通过env设置不同的环境,使用不同的yaml配置文件。ENV 设置环境变量
- 我们可以在应用启动的时候去数据库或者某个特定的地方拿,没问题!但是第一,实现起来麻烦;第二,如果配置的地方变了怎么办?
当然还有别的方案,但是各种方案都有各自的问题。
而且,还有一个问题就是,如果说我的一个配置,是要多个应用一起使用的,以上除了第三种方案,都没办法进行配置的共享,就是说我如果要改配置的话,那得一个一个手动改。假如我们有 100 个应用,就得改 100 份配置,以此类推……
kubernetes 对这个问题提供了一个很好的解决方案,就是用 ConfigMap 和 Secret。
有很多种方案可以将项目 和 项目的配置解耦:
configMap就是让项目镜像 和 配置、环境变量、配置文件等配置数据 解耦,保证镜像的可移植性
- ConfigMap功能在kubernetes1.2版本中引入,许多应用程序会从配置文件,命令行参数或环境变量中读取配置信息,
ConfigAPI给我们提供了向容器中注入配置信息的机制
,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。 - ConfigMap对像是一系列配置的集合,k8s会将这一集合注入到对应的Pod对像中,并为容器成功启动使用。注入的方式一般有两种,
一种是挂载存储卷,一种是传递变量
。ConfigMap被引用之前必须存在,属于名称空间级别,不能跨名称空间使用,内容明文显示。ConfigMap内容修改后,对应的pod必须重启或者重新加载配置(支持热更新的应用,不需要重启)。 - Secret类似于ConfigMap,是用Base64加密,密文显示,一般存放敏感数据。一般有两种创建方式,一种是使用kubectl create创建,一种是用Secret配置文件。
2. 应用场景
应用场景:镜像往往是一个应用的基础,还有很多需要自定义的参数或配置,例如资源的消耗、日志的位置级别等等,这些配置可能会有很多,因此不能放入镜像中,Kubernetes中提供了Configmap来实现向容器中提供配置文件或环境变量来实现不同配置,从而实现了镜像配置与镜像本身解耦,使容器应用做到不依赖于环境配置。
向容器传递参数:
Docker | Kubernetes | 描述 |
---|---|---|
ENTRYPOINT | command | 容器中的可执行文件 |
CMD | args | 需要传递给可执行文件的参数 |
Kubernetes如果需要向容器传递参数,可以在Yaml文件中通过command和args或者环境变量的方式实现。(不使用configMap的场景)
apiVersion: v1
kind: Pod
metadata:
name: print-greeting
spec:
containers:
- name: env-print-demo
image: hub.kaikeba.com/java12/bash:v1
env: #添加了一个环境变量
- name: GREETING
value: "Warm greetings to"
- name: HONORIFIC
value: "The Most Honorable"
- name: NAME
value: "Kubernetes"
command: ["echo"] #执行echo命令
args: ["$(GREETING) $(HONORIFIC) $(NAME)"] #命令中传入了这些参数,引用的就是上面env中定义的
# 创建后,命令 echo Warm greetings to The Most Honorable Kubernetes 将在容器中运行,也就是环境变量中的值被传递到了容器中。
# 查看pod就可以看出
kubectl logs podname
等待一会儿时间后,看到STATUS是Completed,Ready是0/1,pod中的容器已经结束了
因为我们yaml文件里就要求容器运行以后只执行一条指令,执行完成后就结束了
现在测试的这种情况是将配置数据和yaml资源文件耦合在一起了,接下来我们使用configMap分离
3. 创建ConfigMap
3.1 help文档
通过hepl命令可以查看configmap的用法:
[root@k8s-master-155-221 configmap]# kubectl create configmap --help
......
Aliases:
configmap, cm #可以使用cm替代
Examples:
# Create a new configmap named my-config based on folder bar
kubectl create configmap my-config --from-file=path/to/bar #从目录创建 文件名称为键 文件内容为值
# Create a new configmap named my-config with specified keys instead of file basenames on disk
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt #从文件创建 key1为键 文件内容为值
# 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 #直接命令行给定,键为key1 值为config1
# 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 #从文件创建 文件名为键 文件内容为值
# Create a new configmap named my-config from an env file
kubectl create configmap my-config --from-env-file=path/to/bar.env
3.2 使用目录创建
# 指定目录
ls /docs/user-guide/configmap
# 创建game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
# ui.propertes
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
# 创建configmap ,指令
# game-config-1 :configmap的名称
# --from-file:指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl create configmap game-config-1 --from-file=docs/user-guide/configmap/properties
# 查看configmap文件
kubectl get cm
# 查看详细信息 -o 指定输出格式为yaml
kubectl get cm game-config -o yaml
kubectl describe cm
data就是数据区,存放的就是配置文件,key就是文件名,后面"|"后跟的就是配置文件内容,这个是yaml语法
清空环境
3.3 根据文件创建
只需要指定为一个文件就可以从单个文件中创建ConfigMap
# 指定创建的文件即可
kubectl create configmap game-config-2 --from-file=/docs/user-guide/configmap/game.properties
#查看
kubectl get cm game-config-2 -o yaml
--from-file
这个参数可以使用多次,可以分别指定game.properties,ui.propertes,效果和指定整个目录是一样的。
3.4 文字创建
# 使用--from-literal 方式直接创建configmap
# Create the ConfigMap
kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2
# Get the ConfigMap Details for my-config
kubectl get configmaps my-config -o yaml
使用文字方式创建,利用 --from-literal
参数传递配置信息,该参数可以使用多次。
3.5 直接方法(yaml文件方式创建)
ConfigMap 是一个 API 对象, 让你可以存储其他对象所需要使用的配置。 和其他 Kubernetes 对象都有一个 spec 不同的是,ConfigMap 使用
data
和binaryData
字段。这些字段能够接收键-值对作为其取值。data
和binaryData
字段都是可选的。data
字段设计用来保存 UTF-8 字节序列,而binaryData
则 被设计用来保存二进制数据。
ConfigMap 的名字必须是一个合法的 DNS 子域名。
data
或binaryData
字段下面的每个键的名称都必须由字母数字字符或者 -、_ 或 . 组成。在data
下保存的键名不可以与在binaryData
下 出现的键名有重叠。
从 v1.19 开始,你可以添加一个 immutable 字段到 ConfigMap 定义中,创建 不可变更的 ConfigMap。
# 直接通过配置文件的方式创建
apiVersion: v1
data:
game.properties: |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kind: ConfigMap
metadata:
name: game-config
namespace: default
4. pod中应用
你可以使用四种方式来使用 ConfigMap 配置 Pod 中的容器:
- 容器 entrypoint 的命令行参数
- 容器的环境变量
- 在只读卷里面添加一个文件,让应用来读取
- 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap
这些不同的方法适用于不同的数据使用方式。 对前三个方法,kubelet 使用 ConfigMap 中的数据在 Pod 中启动容器。
第四种方法意味着你必须编写代码才能读取 ConfigMap 和它的数据。然而, 由于你是直接使用 Kubernetes API,因此只要 ConfigMap 发生更改,你的 应用就能够通过订阅来获取更新,并且在这样的情况发生的时候做出反应。 通过直接进入 Kubernetes API,这个技术也可以让你能够获取到不同的名字空间 里的 ConfigMap。
先创建两个configMap
# 创建configMap, special.how: very 键名:键值
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
# 创建第二个configMap
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
清空环境,删除之前操作创建的configmap:
创建configMap:
4.1 第一种方式: 在pod中使用ConfigMap来替代环境变量
- valueFrom -> configMapKeyRef
- envFrom -> configMapRef
# 第一种方式: 在pod中使用configmap配置,使用ConfigMap来替代环境变量
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: hub.kaikeba.com/library/myapp:v1
command: ["/bin/sh", "-c", "env"] #容器一但运行会执行命令/bin/sh -c env,会在控制台打印一下
env: # 第一种导入方式:在env中导入
- name: SPECIAL_LEVEL_KEY # name是当前容器环境变量的key
valueFrom: # 通过valueFrom
configMapKeyRef:
name: special-config # name是要引入哪个configMap的name
key: special.how # key是要引入该configMap中的哪个key
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
envFrom: # 第二种导入方式,直接使用envFrom导入
- configMapRef:
name: env-config
restartPolicy: Never
# 查看日志可以发现,环境变量注入到了容器中了,打印env就结束了
kubectl logs test-pod
清除环境:
4.2 第二种方式:用ConfigMap设置命令行参数
用作命令行参数,将 ConfigMap 用作命令行参数时,需要先把 ConfigMap 的数据保存在环境变量中,然后通过 $(VAR_NAME) 的方式引用环境变量.
#第二种方式:用ConfigMap设置命令行参数
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: hub.kaikeba.com/java12/myapp:v1
command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] # 命令行中通过${}获取环境变量参数
env:
- name: SPECIAL_LEVEL_KEY
valueFrom: # 通过valueFrom引入
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
restartPolicy: Never
4.3 第三种方式:通过数据卷挂载ConfigMap
在数据卷里面使用这个ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容
,即在 Pod 中将 ConfigMap 当做文件使用。
关于数据卷的详细内容将在下一节详细说
# 第三种方式:通过数据卷挂载ConfigMap
apiVersion: v1
kind: Pod
metadata:
name: test-pod3
spec:
containers:
- name: test-container
image: hub.kaikeba.com/library/myapp:v1
command: [ "/bin/sh", "-c", "sleep 600s" ]
volumeMounts: # 挂载数据卷
- name: config-volume # 指定数据卷名
mountPath: /etc/config # 表示把conifg-volume数据卷挂载到容器的/etc/config目录下
volumes: # 定义数据卷
- name: config-volume #给数据卷起名
configMap: #数据卷挂载configmap
name: special-config #挂载的configmap名字
restartPolicy: Never
登录容器查看/etc/config目录下是否挂载成功
清除环境:
4.4 被挂载的 ConfigMap 内容会被自动更新:
# ConfigMap的热更新
apiVersion: v1
kind: ConfigMap
metadata:
name: log-config
namespace: default
data:
log_level: INFO
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: hub.kaikeba.com/java12/myapp:v1
ports:
- containerPort: 80
volumeMounts: # 挂载数据卷
- name: config-volume
mountPath: /etc/config # 挂载到容器的/etc/config目录下
volumes:
- name: config-volume
configMap: # 数据卷挂载了上面的ConfigMap
name: log-config
# 修改ConfigMap
kubectl edit configmap log-config
# 修改log-level的值为DEBUG等待大概10秒钟时间,再次查看环境变量的值
修改configMap中数据:
等待一会儿时间:
清除环境:
二、Secret
1. 理解Secret
Secret对象存储数据的方式是以键值方式存储数据,在Pod资源进行调用Secret的方式是通过环境变量或者存储卷的方式进行访问数据
,解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。
另外,Secret对象的数据存储和打印格式为Base64编码的字符串,因此用户在创建Secret对象时,也需要提供该类型的编码格式的数据。在容器中以环境变量或存储卷的方式访问时,会自动解码为明文格式。
需要注意的是,如果是在Master节点上,Secret对象以非加密的格式存储在etcd中,所以需要对etcd的管理和权限进行严格控制。
要使用 Secret,Pod 需要引用 Secret。 Pod 可以用三种方式之一来使用 Secret:
- 作为挂载到一个或多个容器上的 卷 中的文件。
- 作为容器的环境变量
- 由 kubelet 在为 Pod 拉取镜像时使用
Secret 对象的名称必须是合法的 DNS 子域名。 在为创建 Secret 编写配置文件时,你可以设置 data 与/或 stringData 字段。 data 和 stringData 字段都是可选的。data 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,你可以选择设置 stringData 字段,其中可以使用任何字符串作为其取值。
2. Secret 的类型
在创建 Secret 对象时,你可以使用 Secret 资源的 type 字段,或者与其等价的 kubectl 命令行参数(如果有的话)为其设置类型。 Secret 的类型用来帮助编写程序处理 Secret 数据。
Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。
内置类型 | 用法 |
---|---|
Opaque | 用户定义的任意数据 base64编码格式的Secret,用来存储密码、密钥、信息、证书等,类型标识符为generic; |
kubernetes.io/service-account-token | 服务账号令牌 用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中; |
kubernetes.io/dockercfg | ~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson | ~/.docker/config.json 文件的序列化形式 用来存储私有docker registry的认证信息,类型标识为docker-registry |
kubernetes.io/basic-auth | 用于基本身份认证的凭据 |
kubernetes.io/ssh-auth | 用于 SSH 身份认证的凭据 |
kubernetes.io/tls | 用于 TLS 客户端或者服务器端的数据 用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。 |
bootstrap.kubernetes.io/token | 启动引导令牌数据 |
通过为 Secret 对象的 type 字段设置一个非空的字符串值,你也可以定义并使用自己 Secret 类型。如果 type 值为空字符串,则被视为 Opaque 类型。 Kubernetes 并不对类型的名称作任何限制。不过,如果你要使用内置类型之一, 则你必须满足为该类型所定义的所有要求。
3. Service Account
Kubernetes 在创建 Pod 时会自动创建一个服务账号 Secret 并自动修改你的 Pod 以使用该 Secret。该服务账号令牌 Secret 中包含了访问 Kubernetes API 所需要的凭据。
Service Account 用来访问kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中。
Service Account 不需要我们自己去管理的,此证书是由kubernetes自己来进行维护管理的。
# 创建pod
kubectl run my-nginx --image=hub.kaikeba.com/java12/nginx:v1
# 查看证书
kubctl exec -it podName -- sh
# 进入证书目录/run/secrets/kubernetes.io/serviceaccount查看即可
ca.crt
namespace
token
4. Opaque Secret
4.1 创建示例
当 Secret 配置文件中未作显式设定时,默认的 Secret 类型是 Opaque。 当你使用 kubectl 来创建一个 Secret 时,你会使用 generic
子命令来标明 要创建的是一个 Opaque 类型 Secret。
Opaque类型的数据一个map类型,要求value是base64编码格式
# base64对用户名,密码加密效果演示
echo -n "admin" | base64
YWRtaW4=
echo -n "abcdefgh" | base64
YWJjZGVmZ2g=
加密演示:
看到多次加密结果都是一样的,破解很容易
# secret.yaml配置文件方式
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: YWJjZGVmZ2g=
username: YWRtaW4=
4.2 使用方式一:作为挂载到一个或多个容器上的 卷 中的文件
# 将secret挂载到volume中
apiVersion: v1
kind: Pod
metadata:
name: secret-test
labels:
name: secret-test
spec:
volumes: # 引入一个数据卷
- name: secrets
secret: # 挂载指定的secret
secretName: mysecret
containers:
- image: hub.kaikeba.com/java12/myapp:v1
name: db
volumeMounts:
- name: secrets
mountPath: "/etc/secrets" # 容器挂载数据卷,挂载到/etc/secrets目录下
readOnly: true
看到创建的是加密的,但是容器里面显示的是明文的
清除环境
4.3 使用方式二:作为容器的环境变量
# 将secret导出到环境变量中
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: secret-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-1
image: hub.kaikeba.com/java12/myapp:v1
ports:
- containerPort: 80
env: # 设置环境变量
- name: TEST_USER
valueFrom:
secretKeyRef: # 核心在这里 secretKeyRef
name: mysecret
key: username
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
更多推荐
所有评论(0)