K8S 快速入门(十二)实战篇:配置 ConfigMap&Secret

一、ConfigMap

官方文档 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 需要传递给可执行文件的参数

Dockerfile中EntryPoint和CMD的区别

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 使用 databinaryData 字段。这些字段能够接收键-值对作为其取值。databinaryData 字段都是可选的。data 字段设计用来保存 UTF-8 字节序列,而 binaryData 则 被设计用来保存二进制数据。

ConfigMap 的名字必须是一个合法的 DNS 子域名。

databinaryData 字段下面的每个键的名称都必须由字母数字字符或者 -、_ 或 . 组成。在 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 中的容器:

  1. 容器 entrypoint 的命令行参数
  2. 容器的环境变量
  3. 在只读卷里面添加一个文件,让应用来读取
  4. 编写代码在 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

官方文档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

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41947378/article/details/111358153