Kubernetes ConfigMap vs Secret

服务器

浏览数:138

2020-6-16

场景对比

  • Secret:当你想要存储一些敏感数据时使用Secret,例如(passwords, OAuth tokens, ssh keys, credentials等)
  • ConfigMap : 当需要存储一些非敏感配置数据时可以使用ConfigMap,例如应用程序的ini,json等配置文件。

ConfigMap:

创建ConfigMap

kind: ConfigMap
apiVersion: v1
metadata:
  name: example-config
  namespace: default
data:
  example.property.1: hello        #key-value形式,key规则必须满足dns域名规则。value为字符串。
  example.property.2: world
  example.property.file: |-        #配置文件使用方式,直接把文件内容放入value即可
    property.1=value-1
    property.2=value-2
    property.3=value-3

使用方式:

1.填充环境变量

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: example-config     #需要使用的ConfigMap名称,必须已经存在
              key: example.property.1  #对应ConfigMap data 的key
  restartPolicy: Never

设置结果

SPECIAL_LEVEL_KEY=hello

2.设置容器启动命令行参数

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: example-config
              key: example.property.1
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: example-config
              key: example.property.2
  restartPolicy: Never

运行结果:

hello world

3.挂载ConfigMap到文件

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh","-c","ls -l /etc/config/path/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: example-config
        items:
        - key: example.property.1
          path: path/one/example.property.1
        - key: example.property.2
          path: path/two/example.property.2
        - key: example.property.file
          path: path/file/example.property.file
  restartPolicy: Never

创建的文件如下:

└── path
    ├── file
    │   └── example.property.file
    ├── one
    │   └── example.property.1
    └── two
        └── example.property.2
        
#cat example.property.1          hello
#cat example.property.2          world
#cat example.property.file  
    property.1=value-1
    property.2=value-2
    property.3=value-3    

注意:

  • ConfigMap必须在使用之前被创建,如果引用了一个不存在的configMap,将会导致Pod无法启动
  • ConfigMap只能被相同namespace内的应用使用。
3.1挂载ConfigMap到单个文件:

假设我的项目结构如下(项目路径为/usr/local):

.
├── Dockerfile
├── Makefile
├── app.conf
├── controllers
│   └── pod.go
└── main.go

我只想把app.conf文件从ConfigMap挂载进来,其他文件保持不变,现在应该怎么做呢? 好,我们开始。

假设我的ConfigMap如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: test-cfgmap
data:
  app.conf: file data
  • 第一种方式:

可以使用下面的定义文件使用ConfigMap:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd-plus-cfgmap
spec:
  containers:
  - image: ubuntu
    name: bash
    volumeMounts:
    - mountPath: /usr/local/app.conf
      name: cfgmap
      subPath: app.conf
  volumes:
  - name: cfgmap
    configMap:
      name: test-cfgmap

注意,这种方式使用ConfigMap, ConfigMap的key、 volumeMounts.mountPath和volumeMounts.subPath名称一定要保持一致,否则会挂载不成功。

  • 第二种方式:
apiVersion: v1
kind: Pod
metadata:
  name: test-pd-plus-cfgmap
spec:
  containers:
  - image: ubuntu
    name: bash
    volumeMounts:
    - mountPath: /usr/local/app.conf
      name: cfgmap
      subPath: app.conf
  volumes:
  - name: cfgmap
    configMap:
      name: test-cfgmap
      items:
      - key: app.conf
        path: app.conf

注意,这种方式使用ConfigMap,就不再要求 ConfigMap的key跟挂载的文件名必须一致,但需要在items指定key和path对应关系。

  • 其它方式:

当然,如果你愿意,你也可以挂载ConfigMap到一个其它路径,然后通过软连接的方式链接到你需要的文件。

实际使用例子(Redis配置):

例如当我们需要按照如下配置来启动Redis

maxmemory 2mb
maxmemory-policy allkeys-lru

首先,让我们来创建一个ConfigMap:

apiVersion: v1
data:
  redis-config: |
    maxmemory 2mb
    maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
  name: example-redis-config
  namespace: default

下面我们来创建一个Pod来使用它:

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: kubernetes/redis:v1
    env:
    - name: MASTER
      value: "true"
    ports:
    - containerPort: 6379
    volumeMounts:
    - mountPath: /redis-master
      name: config
  volumes:
    - name: config
      configMap:
        name: example-redis-config
        items:
        - key: redis-config
          path: redis.conf     #指定生成的配置文件名称

当我们创建完Pod后,进入它: 生成的配置文件如下:

redis-master
`-- redis.conf -> ..data/redis.conf

我们发现在redis-master 目录下生成了一个文件redis.conf ,对应我们上面path定义的文件名。输出一下redis.conf内容:

maxmemory 2mb
maxmemory-policy allkeys-lru

下面我们看一下redis的配置:

$ kubectl exec -it redis redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "2097152"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"

符合我们的预期。

注意: 虽然使用configMap可以很方便的把我们配置文件放入到容器中,但一定注意配置文件的大小,(尽量控制在1M以内)更不能滥用ConfigMap,否则可能会给apiserver和etcd造成较大压力,影响整个集群。

Secret:

当需要使用一些敏感的配置,比如密码,证书等信息时,建议使用Secret。

创建Secret

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=     
  password: MWYyZDFlMmU2N2Rm

注意: Secret 的value必须经过base64, 以上明文为: username: admin password: 1f2d1e2e67df ,可以直接使用 echo -n “1f2d1e2e67df” | base64 进行base64,或者到这里可以进行base64加密解密

使用方式:

1.挂载到文件

apiVersion: v1
kind: Pod
metadata:
  name: mypod
  namespace: default
spec:
  containers:
  - image: redis
    name: mypod
    volumeMounts:
    - mountPath: /etc/foo
      name: foo
      readOnly: true
  volumes:
  - name: foo
    secret:
      defaultMode: 420      #0644默认文件权限,由于json文件不支持八进制,使用json时应使用十进制
      secretName: mysecret

运行结果:在/etc/foo/目录下生成两个文件username和password

foo/
|-- password -> ..data/password
`-- username -> ..data/username
#cat username       admin
#cat password      1f2d1e2e67df

注意: 自动更新: 当Secrets被更新时,已经挂载的pod不会立即更新,而要等待kubelete检查周期,kubelet会定期检查secret变化并更新它。

2.通过环境变量使用

apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
    - name: mycontainer
      image: redis
      env:
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: mysecret   #指定secret名称
              key: username    #要使用的key
        - name: SECRET_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password
$ echo $SECRET_USERNAME
admin
$ echo $SECRET_PASSWORD
1f2d1e2e67df

3.拉取镜像

apiVersion: v1
kind: Secret
metadata:
  name: image-test-secret
  namespace: default
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: ew0KCSJhdXRocyI6IHsNCgkJImltYWdlLXRlc3QiOiB7DQoJCQkiYXV0aCI6ICJjbTl2ZERweWIyOTAiLA0KCQkJImVtYWlsIjogIiINCgkJfQ0KCX0NCn0=

加密部分的明文为:

{
	"auths": {
		"image-test": {
			"auth": "cm9vdDpyb290",   #  密文为"root:rootbase64"的结果
			"email": ""
		}
	}
}

部署文件使用如下:

apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: default
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: image-test-secret

实际使用例子(挂载证书文件):

kind: Secret
apiVersion: v1
metadata:
  name: client-certs
  namespace: default
data:
  ca.pem: *** #实际使用请替换成经过base64加密后的内容
  kubernetes.pem: ***
  kubernetes-key.pem: ***

使用deployment部署:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis
        ports:
          - containerPort: 8080
        volumeMounts:
        - mountPath: /etc/kubernetes/certs
          name: my-certs
      volumes:
        - name: my-certs
          secret:
            secretName: client-certs
            items:
            - key: ca.pem
              path: ca.pem
            - key: kubernetes.pem
              path: kubernetes.pem
            - key: kubernetes-key.pem
              path: kubernetes-key.pem
      imagePullSecrets:
        - name: image-test-secret

作者:WilhelmGuo