MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Kubernetes 中 ConfigMap 和 Secret 的使用技巧

2023-08-266.8k 阅读

Kubernetes 基础概念回顾

在深入探讨 ConfigMap 和 Secret 的使用技巧之前,先简要回顾一下 Kubernetes 的一些基础概念。Kubernetes,常简称为 K8s,是一个开源的容器编排平台,用于自动化容器化应用的部署、扩展和管理。它将多个容器组合成逻辑单元,以便于管理和发现,这些逻辑单元称为 Pod。Pod 是 Kubernetes 中最小的可部署和可管理的计算单元,一个 Pod 可以包含一个或多个紧密相关的容器。

Kubernetes 中的服务(Service)则是对一组提供相同功能的 Pod 的抽象,并为它们提供一个统一的访问入口。通过 Service,应用程序的客户端可以无需关心 Pod 的实际位置和数量变化,始终通过一个稳定的 IP 地址和端口来访问服务。

ConfigMap 概述

ConfigMap 是 Kubernetes 提供的一种机制,用于将配置数据从容器镜像中解耦出来。在传统的应用开发中,配置信息常常硬编码在代码或者镜像中,这使得在不同环境(如开发、测试、生产)中部署应用时需要重新构建镜像。而 ConfigMap 的出现解决了这一问题,它允许我们将配置信息以键值对的形式存储在 Kubernetes 集群中,然后在创建 Pod 时将这些配置信息注入到容器内。

ConfigMap 可以包含多种类型的数据,例如环境变量、命令行参数、配置文件等。这使得应用程序的配置能够根据不同的环境进行灵活调整,而无需修改容器镜像。

创建 ConfigMap

创建 ConfigMap 有多种方式,下面将详细介绍几种常见的方法。

使用 kubectl create configmap 命令

这是最直接的创建 ConfigMap 的方式。假设我们有一个简单的配置文件 app.properties,内容如下:

database.url=jdbc:mysql://localhost:3306/mydb
database.username=root
database.password=password

我们可以使用以下命令基于这个文件创建 ConfigMap:

kubectl create configmap app-config --from-file=app.properties

上述命令会创建一个名为 app-config 的 ConfigMap,其中 app.properties 文件的内容会被解析为 ConfigMap 的数据。

如果要从多个文件创建 ConfigMap,可以继续添加 --from-file 参数,例如:

kubectl create configmap app-config --from-file=app.properties --from-file=logging.properties

也可以直接从命令行指定键值对来创建 ConfigMap,例如:

kubectl create configmap app-config --from-literal=key1=value1 --from-literal=key2=value2

使用配置文件创建 ConfigMap

除了使用命令行创建,我们还可以通过编写 YAML 或 JSON 格式的配置文件来创建 ConfigMap。以下是一个 YAML 格式的 ConfigMap 配置文件示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  database.url: jdbc:mysql://localhost:3306/mydb
  database.username: root
  database.password: password

使用以下命令创建 ConfigMap:

kubectl apply -f configmap.yaml

这种方式的优点在于可以将 ConfigMap 的定义纳入版本控制,便于团队协作和环境部署的一致性。

在 Pod 中使用 ConfigMap

创建好 ConfigMap 后,就可以在 Pod 中使用它了。在 Pod 中使用 ConfigMap 主要有两种方式:作为环境变量和作为配置文件挂载。

作为环境变量使用 ConfigMap

假设我们有一个名为 app 的 Pod,想要将前面创建的 app-config ConfigMap 中的数据作为环境变量注入到容器中。可以在 Pod 的 YAML 配置文件中如下定义:

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app-container
    image: myapp:latest
    env:
    - name: DATABASE_URL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: database.url
    - name: DATABASE_USERNAME
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: database.username
    - name: DATABASE_PASSWORD
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: database.password

在上述配置中,通过 valueFrom.configMapKeyRef 字段将 ConfigMap 中的键值对映射为容器的环境变量。这样,在容器内部就可以通过 $DATABASE_URL$DATABASE_USERNAME$DATABASE_PASSWORD 等环境变量来获取配置信息。

作为配置文件挂载使用 ConfigMap

有时,应用程序需要读取配置文件来启动。我们可以将 ConfigMap 挂载为容器内的文件。以下是将 app-config ConfigMap 挂载为 /etc/config 目录下的 app.properties 文件的示例:

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app-container
    image: myapp:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

在上述配置中,通过 volumeMountsvolumes 字段将 app-config ConfigMap 挂载到容器的 /etc/config 目录下。此时,在容器内的 /etc/config/app.properties 文件中就可以看到 ConfigMap 中的配置内容。

ConfigMap 使用技巧

部分更新 ConfigMap

在实际应用中,有时只需要更新 ConfigMap 中的部分数据。由于 ConfigMap 是 Kubernetes 的资源对象,我们可以使用 kubectl edit 命令来直接编辑 ConfigMap。例如,要更新 app-config ConfigMap 中的 database.password 字段:

kubectl edit configmap app-config

这会打开默认的文本编辑器,让我们修改 ConfigMap 的 YAML 定义。修改保存后,Kubernetes 会自动更新 ConfigMap。

另外,也可以使用 kubectl patch 命令来进行部分更新。例如,将 database.password 更新为新的值:

kubectl patch configmap app-config -p '{"data": {"database.password": "newpassword"}}'

ConfigMap 与多环境配置

在不同的环境(如开发、测试、生产)中,应用程序的配置可能会有所不同。我们可以通过创建多个 ConfigMap 来满足这一需求。例如,创建一个用于开发环境的 app-config-dev 和一个用于生产环境的 app-config-prod

在部署时,根据环境选择对应的 ConfigMap。例如,在开发环境的 Deployment 中使用 app-config-dev

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-dev
  template:
    metadata:
      labels:
        app: app-dev
    spec:
      containers:
      - name: app-container
        image: myapp:latest
        env:
        - name: DATABASE_URL
          valueFrom:
            configMapKeyRef:
              name: app-config-dev
              key: database.url
        - name: DATABASE_USERNAME
          valueFrom:
            configMapKeyRef:
              name: app-config-dev
              key: database.username
        - name: DATABASE_PASSWORD
          valueFrom:
            configMapKeyRef:
              name: app-config-dev
              key: database.password

在生产环境的 Deployment 中使用 app-config-prod,这样就实现了多环境的灵活配置。

ConfigMap 与 Helm 集成

Helm 是 Kubernetes 的包管理器,它可以帮助我们更方便地管理和部署复杂的应用程序。在 Helm Chart 中,可以很好地集成 ConfigMap。

在 Chart 的 values.yaml 文件中,可以定义 ConfigMap 的相关配置。例如:

configMap:
  data:
    database.url: jdbc:mysql://prod-db:3306/mydb
    database.username: produser
    database.password: prodpassword

然后在 templates/configmap.yaml 文件中定义 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "mychart.fullname" . }}-config
data:
  {{- range $key, $value := .Values.configMap.data }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}

这样,通过 Helm 安装 Chart 时,会根据 values.yaml 中的配置创建相应的 ConfigMap。而且,通过修改 values.yaml 文件,可以很方便地更新 ConfigMap 的配置,再通过 helm upgrade 命令进行升级。

Secret 概述

Secret 与 ConfigMap 类似,也是用于存储和管理配置信息,但不同的是,Secret 主要用于存储敏感信息,如密码、密钥、证书等。Kubernetes 会对 Secret 进行加密存储,并在使用时以安全的方式将其注入到容器中,以防止敏感信息的泄露。

与 ConfigMap 一样,Secret 也以键值对的形式存储数据,并且可以在 Pod 中以环境变量或文件挂载的方式使用。

创建 Secret

与 ConfigMap 类似,创建 Secret 也有多种方式。

使用 kubectl create secret 命令

可以通过 kubectl create secret 命令从文件、字面量等创建 Secret。例如,假设我们有一个私钥文件 private.key 和一个证书文件 cert.crt,要创建一个包含这些文件的 Secret:

kubectl create secret tls my-tls-secret --cert=cert.crt --key=private.key

上述命令会创建一个类型为 tls 的 Secret,用于存储 TLS 证书和私钥。

如果要创建一个普通的 Secret 来存储用户名和密码,可以使用以下命令:

kubectl create secret generic my-secret --from-literal=username=admin --from-literal=password=adminpass

这里创建了一个通用类型(generic)的 Secret,其中包含 usernamepassword 两个键值对。

使用配置文件创建 Secret

同样,也可以通过编写 YAML 配置文件来创建 Secret。以下是一个通用类型 Secret 的 YAML 示例:

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: YWRtaW4=
  password: YWRtaW5wYXNz

注意,这里的数据值需要进行 base64 编码。可以使用以下命令进行编码:

echo -n "admin" | base64
echo -n "adminpass" | base64

使用 kubectl apply -f secret.yaml 命令创建 Secret。

在 Pod 中使用 Secret

在 Pod 中使用 Secret 的方式与 ConfigMap 类似,也可以作为环境变量或配置文件挂载。

作为环境变量使用 Secret

假设我们有一个名为 myapp 的 Pod,要将 my-secret Secret 中的数据作为环境变量注入:

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
  - name: myapp-container
    image: myapp:latest
    env:
    - name: USERNAME
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: username
    - name: PASSWORD
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: password

通过 valueFrom.secretKeyRef 字段将 Secret 中的键值对映射为容器的环境变量。

作为配置文件挂载使用 Secret

my-secret Secret 挂载为容器内的文件示例如下:

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
  - name: myapp-container
    image: myapp:latest
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
  volumes:
  - name: secret-volume
    secret:
      secretName: my-secret

这样,Secret 中的数据会被挂载到容器的 /etc/secret 目录下,以文件的形式存在,文件名即为 Secret 的键名。

Secret 使用技巧

Secret 的更新与滚动升级

当 Secret 中的敏感信息需要更新时,例如密码修改,我们需要谨慎处理。如果直接更新 Secret,使用该 Secret 的 Pod 不会自动获取新的 Secret 内容。为了让 Pod 使用新的 Secret,需要进行滚动升级。

假设我们已经更新了 my-secret Secret 中的 password 字段。对于 Deployment 管理的 Pod,可以使用以下命令触发滚动升级:

kubectl rollout restart deployment myapp-deployment

这会终止旧的 Pod,并创建新的 Pod,新的 Pod 会使用更新后的 Secret。

Secret 与 TLS 证书管理

在 Kubernetes 中,TLS 证书的管理是一个重要的方面。通过 Secret 可以方便地管理 TLS 证书。例如,在创建 Ingress 资源时,常常需要关联 TLS Secret 来实现 HTTPS 访问。

假设我们有一个 my-tls-secret Secret 包含 TLS 证书和私钥,在 Ingress 配置中可以这样使用:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  tls:
  - hosts:
    - mydomain.com
    secretName: my-tls-secret
  rules:
  - host: mydomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-service
            port:
              number: 80

这样,Ingress 会使用 my-tls-secret 中的证书来提供 HTTPS 服务。

Secret 的安全注意事项

虽然 Kubernetes 对 Secret 进行了加密存储,但在使用过程中仍需注意安全。首先,在创建和编辑 Secret 时,要确保操作环境的安全性,避免敏感信息泄露。其次,对于 Secret 的访问权限要严格控制,只有需要使用 Secret 的 Pod 所在的 ServiceAccount 才应具有访问权限。

可以通过 Kubernetes 的 RBAC(Role - Based Access Control)机制来管理 Secret 的访问权限。例如,创建一个只允许特定 ServiceAccount 访问 my-secret Secret 的 Role 和 RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: my-secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["my-secret"]
  verbs: ["get", "watch", "list"]

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-secret-reader-binding
subjects:
- kind: ServiceAccount
  name: myapp-serviceaccount
  namespace: default
roleRef:
  kind: Role
  name: my-secret-reader
  apiGroup: rbac.authorization.k8s.io

通过上述配置,只有 myapp-serviceaccount 可以访问 my-secret Secret,增强了 Secret 的安全性。

ConfigMap 和 Secret 的对比与选择

数据类型

ConfigMap 适合存储非敏感的配置信息,如应用程序的配置参数、环境变量等。而 Secret 专门用于存储敏感信息,如密码、密钥、证书等。

存储和传输

Kubernetes 对 Secret 进行加密存储,在传输到节点时也会进行加密。而 ConfigMap 则以明文形式存储和传输,所以如果配置信息包含敏感内容,绝不能使用 ConfigMap。

使用场景

如果是一些通用的、不需要保密的配置,如数据库连接字符串(假设数据库密码已通过 Secret 单独管理)、日志级别等,可以使用 ConfigMap。而对于认证信息、加密密钥等敏感数据,必须使用 Secret。

高级应用场景

动态配置更新

在一些场景下,应用程序需要在运行时动态获取配置更新,而无需重启。对于 ConfigMap 和 Secret,虽然 Pod 不会自动感知它们的变化,但可以通过一些额外的机制实现动态更新。

例如,对于基于 Java 的应用程序,可以使用 Spring Cloud Config 与 Kubernetes 集成。Spring Cloud Config 可以从 ConfigMap 或 Secret 中获取配置,并通过 Spring Cloud Bus 实现配置的动态刷新。

在 Kubernetes 中,可以通过创建一个 Sidecar 容器来监控 ConfigMap 或 Secret 的变化。当检测到变化时,Sidecar 容器可以通过某种方式通知主容器重新加载配置,例如通过发送信号或者调用主容器的 API。

多租户配置管理

在多租户的 Kubernetes 环境中,不同租户可能需要不同的配置。可以利用 ConfigMap 和 Secret 来实现多租户的配置管理。

为每个租户创建独立的 ConfigMap 和 Secret,在租户的 Pod 中引用对应的配置。例如,租户 A 的 Pod 引用 tenant-a-config ConfigMap 和 tenant-a-secret Secret,租户 B 的 Pod 引用 tenant-b-config ConfigMap 和 tenant-b-secret Secret。

通过这种方式,可以实现不同租户之间配置的隔离和定制化,同时利用 Kubernetes 的资源管理和安全机制来保障配置的安全性和可管理性。

总结

ConfigMap 和 Secret 是 Kubernetes 中非常重要的配置管理工具,它们分别适用于不同类型的配置数据。通过合理地使用 ConfigMap 和 Secret,结合多种创建、使用和管理技巧,可以实现应用程序配置的灵活管理、安全存储以及动态更新。无论是简单的单环境应用还是复杂的多租户、多环境部署,ConfigMap 和 Secret 都能提供有效的配置解决方案,帮助我们更好地管理容器化应用在 Kubernetes 集群中的运行。在实际应用中,需要根据具体的业务需求和安全要求,谨慎选择和使用这两种工具,以确保应用程序的稳定运行和数据安全。