Kubernetes配置管理

TOC

ConfigMap

许多应用经常会有从配置文件、命令行参数或者环境变量中读取一些配置信息的需求,这些配置信息我们肯定不会直接写死到应用程序中,这样不方便修改配置

1.ConfigMap编写语法格式

kind: ConfigMap  
apiVersion: v1  
metadata:  
name: cm-demo  
namespace: default  
data:
  data1: |
    ...
  data2: >
    ...
  data3: value

我们可以在data的下面进行编写配置我们所需要的内容,上面我们可以看到三种编写的格式,它们的区别如下:
|:yaml中表示保留换行,每行的缩进和行尾空白都会被去掉,而额外的缩进会被保留。

data1: |
  我是第一行
  我是第二行
    我是第三行
      我是第四行
  我是第五行
#转化为JSON如下
{"lines": "我是第一行\n我是第二行\n  我是第三行\n     我是第四行\n我是第五行"}

>:号,用来表示折叠换行,只有空白行才会被识别为换行,原来的换行符都会被转换成空格。

data2: >
  我是第一行
  我也是第一行
  我仍是第一行

  我是第二行
  我也是第二行
#转化为JSON如下
{"lines": "我是第一行 我也是第一行 我仍是第一行\n我是第二行 我也是第二行"}

2.ConfigMap的使用

资源清单编写如下:

#configmap-test.yaml
kind: ConfigMap
apiVersion: v1
metadata:
  name: config-test
  namespace: default
data:
  mysql.conf: |
    host=100.100.10.101
    port=3306
  redis.conf: |
    host=100.100.10.102
    port=6379
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  volumes:
    - name: config-volume
      configMap:
        name: config-test
  containers:
    - name: test
      image: busybox
      command: [ "/bin/sh", "-c", "cat /etc/config/redis.conf" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config/redis.conf
        subPath: redis.conf

使用apply创建并查看test容器的日志

[root@master ~]# kubectl apply -f configmap-test.yaml
configmap/config-test created
pod/test created
[root@master ~]# kubectl logs test
host=100.100.10.102
port=6379

我们也可以在ConfigMap值被映射的数据卷里去控制路径

#configmap-test2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test2
spec:
  volumes:
    - name: config-volume
      configMap:
        name: config-test
        items:
        - key: mysql.conf
          path: test/msyql.conf
  containers:
    - name: test2
      image: busybox
      command: ["/bin/sh","-c","cat /etc/config/test/msyql.conf"]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config

再使用apply创建并查看test2容器的日志

[root@master ~]# kubectl apply -f configmap-test2.yaml
pod/test2 created
[root@master ~]# kubectl logs test2
host=100.100.10.101
port=3306

注意:在使用ConfigMap的时候应该先用volumes声明挂载,再挂载到容器中使用!!!

3.通过命令来创建ConfigMap

#创建名为my-config,从/etc/nginx/conf.d目录下的文件获取内容
kubectl create configmap my-config --from-file=/etc/nginx/conf.d
#创建名为my-config,data1的内容从/etc/mysql.conf文件获取,data2的内容从/etc/redis.conf文件获取
kubectl create configmap my-config --from-file=data1=/etc/mysql.conf --from-file=data2=/etc/redis.conf

Secret

用来保存敏感信息,例如密码、OAuth令牌和ssh key等等,将这些信息放在Secret中比放在Pod的定义中或者Docker镜像中要更加安全和灵活。

Secret的分类:

  • Opaque Secret(base64 编码格式的 Secret,用来存储密码、密钥等;但数据也可以通过 base64 –decode 解码得到原始数据,所有加密性很弱。)
  • dockerconfigjson(用来存储私有 docker registry 的认证信息,~/.docker/config.json 文件的序列化形式)
  • basic-auth(用于基本身份认证的凭据)
  • ssh-auth(用于 SSH 身份认证的凭据)
  • tls(该类型用来存放证书及其相关密钥,通常用在 TLS 场合。此类数据主要提供给 Ingress 资源,用以校验 TLS 链接)
  • service-account-token(用于 ServiceAccount, ServiceAccount 创建时 Kubernetes 会默认创建一个对应的 Secret 对象,Pod 如果使用了 ServiceAccount,对应的 Secret 会自动挂载到 Pod 目录 /run/secrets/kubernetes.io/serviceaccount 中)

1.Opaque Secret

该Secret资源包含两种健值对:data和stringData,data用来存储 base64 编码的任意数据,stringData允许 Secret 使用未编码的字符串。它们的值必须由字母、数字、-,_ 或 . 组成。
例如创建一个用户名为 admin,密码为 test123的Secret对象:

echo -n "admin" | base64
YWRtaW4=
echo -n "test123" | base64
dGVzdDEyMw==

资源清单编写如下:

# secret-opaque.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: dGVzdDEyMw==

创建secret资源并查看

[root@master ~]# kubectl apply -f secret-demo.yaml
secret/mysecret created
[root@master ~]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
default-token-gmh9l    kubernetes.io/service-account-token   3      1d
mysecret               Opaque                                2      43s
[root@master ~]# kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  7 bytes
username:  5 bytes
[root@master ~]# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  password: dGVzdDEyMw==
  username: YWRtaW4=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"dGVzdDEyMw==","username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2023-10-17T09:17:38Z"
  name: mysecret
  namespace: default
  resourceVersion: "382393338"
  uid: a044c521-7a2a-478b-a9aa-5a7ffcfe4d60
type: Opaque

环境变量使用

资源清单编写如下:

#secret-test1.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: secret-test1
spec:
  template:
    spec:
      containers:
      - name: secret-test1
        image: busybox
        command: [ "/bin/sh", "-c", "env" ]
        env:
        - name: USERNAME
          valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
        - name: PASSWORD
          valueFrom:
          secretKeyRef:
            name: mysecret
            key: password

创建资源对象并查看日志

[root@master ~]# kubectl apply -f secret-test1.yaml
job.batch/secret-test1 created
[root@master ~]# kubectl logs secret-test1-2jh8r
USERNAME=admin
PASSWORD=test123

这里能够看到有 USERNAME 和 PASSWORD 两个环境变量输出出来

挂载使用

资源清单编写如下:

#secret-test2.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: secret-test2
spec:
  template:
    spec:
      volumes:
      - name: secrets
        secret:
          secretName: mysecret
      containers:
      - name: secret-test2
        image: busybox
        command: [ "/bin/sh", "-c", "ls /etc/secrets" ]
        volumeMounts:
        - name: secrets
          mountPath: /etc/secrets

创建资源对象并查看日志

[root@master ~]# kubectl apply -f secret-test2.yaml
job.batch/secret-test2 created
[root@master ~]# kubectl logs secret-test2-hq9sm
password
username

这里我们能够看到 Secret 把两个 key 挂载成了两个对应的文件

2.dockerconfigjson

该Secret资源可以用来创建用户作为docker仓库的认证,从而拉取镜像。
使用命令创建

kubectl create secret docker-registry mytest --docker-server=docker.registry.com --docker-username=admin --docker-password=password --docker-email=registry@email.com

除了上面的方法,还可以指定文件的方式来创建镜像仓库认证信息

kubectl create secret generic mytest --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson

创建好了之后查看Secret列表以及两个Secret的详细信息:

# 查看Secret列表
[root@master ~]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
default-token-gmh9l    kubernetes.io/service-account-token   3      1d
mytest                 kubernetes.io/dockerconfigjson        1      2m53s
mytest1                kubernetes.io/dockerconfigjson        1      7s

#查看第一种方式创建的secret,名为mytest
[root@master ~]# kubectl describe secret mytest
Name:         mytest
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  135 bytes
[root@master ~]#  kubectl get secret mytest -o yaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJkb2NrZXIucmVnaXN0cnkuY29tIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6InBhc3N3b3JkIiwiZW1haWwiOiJyZWdpc3RyeUBlbWFpbC5jb20iLCJhdXRoIjoiWVdSdGFXNDZjR0Z6YzNkdmNtUT0ifX19
kind: Secret
metadata:
  creationTimestamp: "2023-10-18T03:48:00Z"
  name: mytest
  namespace: default
  resourceVersion: "382782494"
  uid: 1828f509-b9c6-4678-b2d6-6a6bd73fd98e
type: kubernetes.io/dockerconfigjson

#查看第二种方式创建的secret,名为mytest
[root@master ~]# kubectl describe secret mytest1
Name:         mytest1
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  151 bytes
[root@master ~]#  kubectl get secret mytest1 -o yaml
apiVersion: v1
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS0xLmRvY2tlci5pbyI6IHt9LAoJCSJzd3IuY24tc291dGgtMS5teWh1YXdlaWNsb3VkLmNvbSI6IHt9Cgl9LAoJImNyZWRzU3RvcmUiOiAiZGVza3RvcCIsCgkiY3VycmVudENvbnRleHQiOiAiZGVza3RvcC1saW51eCIKfQ==
kind: Secret
metadata:
  creationTimestamp: "2023-10-18T03:50:46Z"
  name: mytest1
  namespace: default
  resourceVersion: "382783463"
  uid: f796fdce-47c0-4d9f-8ce1-32aad942e037
type: kubernetes.io/dockerconfigjson

之后,做一个base64的解码,查看data.dockerconfigjson里面的数据:

# mytest的base64解码数据
[root@master ~]# echo eyJhdXRocyI6eyJkb2NrZXIucmVnaXN0cnkuY29tIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6InBhc3N3b3JkIiwiZW1haWwiOiJyZWdpc3RyeUBlbWFpbC5jb20iLCJhdXRoIjoiWVdSdGFXNDZjR0Z6YzNkdmNtUT0ifX19 |base64 -d
{"auths":{"docker.registry.com":{"username":"admin","password":"password","email":"registry@email.com","auth":"YWRtaW46cGFzc3dvcmQ="}}}

# mytest1的base64解码数据
[root@master ~]# echo ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS0xLmRvY2tlci5pbyI6IHt9LAoJCSJzd3IuY24tc291dGgtMS5teWh1YXdlaWNsb3VkLmNvbSI6IHt9Cgl9LAoJImNyZWRzU3RvcmUiOiAiZGVza3RvcCIsCgkiY3VycmVudENvbnRleHQiOiAiZGVza3RvcC1saW51eCIKfQ== |base64 -d
{
	"auths": {
		"registry-1.docker.io": {},
		"swr.cn-south-1.myhuaweicloud.com": {}
	},
	"credsStore": "desktop",
	"currentContext": "desktop-linux"
}

从镜像仓库拉取镜像
资源清单编写如下:

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
  - name: foo
    image: docker.registry.com/test/test:v1
  imagePullSecrets:
  - name: mytest

3.basic-auth

该Secret时用来存放基本身份认证所需的凭证信息,该Secret的data字段必须包含以下两个键值对:

  • username:用于身份认证的用户名
  • password:用于身份认证的密码或令牌
    当键值对为base64编码的字符串时,资源清单编写如下:
# secret-basic.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-basic-auth
type: kubernetes.io/basic-auth
Data:
  username: YWRtaW4=
  password: dGVzdDEyMw==

当键值对为明文形式内容时,资源清单编写如下:

# secret-basic.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
  username: admin
  password: test123

4.ssh-auth

该Secret时用来存放SSH身份认证中所需要的凭据。
资源清单编写如下:

# secret-ssh.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: |
          MIIEpQIBAAKCAQEAulqb/Y ...

data下的值都为base64编码,具体内容需要base64解码之后查看

5.tls

该Secret时用来存放证书以及相关密钥(通常在TLS场合使用),主要提供给Ingress资源使用。
使用命令通过读取cert和key文件来创建:

kubectl create secret tls my-tls-secret \
  --cert=/secret/cert/file \
  --key=/secret/key/file

注意:用于--cert的公钥证书必须是.PEM编码的(Base64编码的DER格式),且与--key所给定的私钥匹配。
也可以通过yaml创建,资源清单编写如下:

# secret-tls.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-tls
type: kubernetes.io/tls
data:
  tls.crt: |
        LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVRRENDQX ...
  tls.key: |
        LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUU ...

data下的值都为base64编码,具体内容需要base64解码之后查看

6.service-account-token

该Secret在k8s创建时会默认创建一个,如下:

[root@master ~]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
default-token-gmh9l    kubernetes.io/service-account-token   3      1d

我们随便查看一个pod的详细信息:

[root@master ~]# kubectl get pod nginx-664b67cc86-fzbwv -o yaml
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-zhdd8
      readOnly: true
  ......
  serviceAccount: default
  serviceAccountName: default
  volumes:
  - name: kube-api-access-zhdd8
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace

当我们创建pod的时候,如果没有指定ServiceAccount,pod会使用命名空间中名为 default 的ServiceAccount,如上面所示。
还可以看到被Volume挂载到了容器的/var/run/secrets/kubernetes.io/serviceaccount目录下,这里我们挂载了一个downwardAPI来获取 namespace,通过ConfigMap来获取ca.crt证书,然后还有一个serviceAccountToken类型的数据源。
所以默认情况下当前namespace下面的pod会默认使用default这个ServiceAccount,对应的Secret会自动挂载到pod的/var/run/secrets/kubernetes.io/serviceaccount目录中,这样我们就可以在pod里面获取到用于身份认证的信息了。

我们可以使用自动挂载给Pod的ServiceAccount凭据访问API,我们也可以通过在 ServiceAccount 上设置automountServiceAccountToken: false来实现不给ServiceAccount自动挂载 API 凭据,资源清单编写如下:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: serviceaccount-demo
automountServiceAccountToken: false
...

也可以选择不给特定的pod自动挂载API凭据,资源清单编写如下:

apiVersion: v1
kind: Pod
metadata:
  name: serviceaccount-pod
spec:
  serviceAccountName: serviceaccount-demo
  automountServiceAccountToken: false
  ...

注意:如果pod和ServiceAccount都指定了automountServiceAccountToken值,则pod优先于ServiceAccount