24、Kubernetes 配置管理与安全部署实践

Kubernetes 配置管理与安全部署实践

1. 配置文件清理

在处理 Kubernetes 的 YAML 配置文件时,有些内容可以删除以简化配置。如果计划在多个命名空间使用配置,建议删除 metadata -> namespace 字段,这样能在当前命名空间部署配置,避免意外更新指定命名空间的对象。另外, metadata 部分的 uid resourceVersion selfLink creationTimestamp 以及整个 status 部分也可移除,这些字段在部署上下文之外意义不大,移除可避免版本控制中的混淆。

2. 以代码方式管理 Kubernetes 配置

将配置视为代码,提交到版本控制系统,就可以像处理代码一样对生产系统配置进行版本管理,例如查看版本历史、回滚提交。对于提交的配置,也应进行同行评审,因为配置对运行系统的影响与代码同样重要。

大的互联网公司常采用这种模式,如 Google 的多数服务在单个代码仓库中开发和部署,服务配置与代码相邻,代码和服务遵循相同的代码审查实践,但批准合并的工程师列表可能不同。不过,并非必须将配置和代码存于同一仓库,可根据自身工程实践调整。

这里介绍一种将 Kubernetes 配置存储在 Git 中的示例:使用单个 Git 仓库表示单个集群中部署的所有 Kubernetes 对象,仓库中为每个 Kubernetes 命名空间创建一个文件夹,文件夹中存放该命名空间对象的 YAML 文件。另一种选择是为每个命名空间使用单独的分支,能方便从测试环境到生产环境合并更改,但可能会导致混乱。

以下是示例目录布局:

/_debug # 存储所有开发者使用的调试脚本的目录
/_cluster # 集群配置,如命名空间配置文件,仅在集群创建时使用
/staging # 测试环境配置文件夹
/production # 生产环境配置文件夹

每个目录与一个 Kubernetes 命名空间映射,这种 1:1 的映射允许使用 kubectl apply -f . 命令将目录中的所有更改部署到活动命名空间,克隆环境只需复制整个文件夹并部署到新的命名空间。

工作流程如下:
1. 对部署环境的配置进行更改。
2. 提交这些更改。
3. 使用 kubectl 设置当前命名空间。
4. 在匹配的目录中运行 kubectl apply -f . 更新实时状态。

3. 安全部署配置

简单地检出仓库并运行 kubectl apply -f . 可能会导致将错误的配置部署到错误的命名空间,为避免这种情况,可以采取以下措施:

3.1 添加检查脚本

编写脚本检查当前命名空间是否与目录名匹配,以下是示例脚本:

# gitops_check.sh
#!/bin/bash
CURRENT_DIR=`echo "${PWD##*/}"`
CURRENT_NAMESPACE=`kubectl config view --minify -o=jsonpath='{.contexts[0].context.namespace}'`
if [ "$CURRENT_DIR" != "$CURRENT_NAMESPACE" ]; then
    >&2 echo "Wrong namespace (currently $CURRENT_NAMESPACE but $CURRENT_DIR expected)"
    exit 1
fi
exit 0

然后在其他脚本中使用该检查脚本,例如:

# rollout.sh
#!/bin/sh
if [ $(../gitops_check.sh; echo $?) != 0 ]; then exit 1; fi
kubectl apply -f .

要使这些脚本正常工作,确保配置文件中不直接指定 metadata -> namespace 字段。

3.2 使用部署管道

部署管道是基于代码仓库触发运行的一组函数,例如“当代码推送到配置仓库时,将配置部署到 Kubernetes 集群”。使用管道可确保部署的配置与提交的一致,如果操作员需要在部署后进行额外更改,在配置代码仓库中修改并推送代码,再次触发管道部署。

对于 GKE 用户,可使用 Cloud Build 实现部署管道,设置步骤如下:
1. 为 Cloud Build 服务账户配置 IAM 权限,使其能在 GKE 集群上操作。
2. 创建新的触发器,设置为在配置仓库推送时触发。
3. 在仓库中添加 Cloud Build 配置文件,并在触发器中引用。

以下是 Cloud Build 配置文件示例:

# cloudbuild-deploy.yaml
steps:
- name: 'gcr.io/cloud-builders/kubectl'
  id: Deploy
  args:
  - 'apply'
  - '-f'
  - '$FOLDER'
  env:
  - 'CLOUDSDK_COMPUTE_ZONE=us-west1-a'
  - 'CLOUDSDK_CONTAINER_CLUSTER=my-cluster'
3.3 使用 GitOps 操作员

使用 GitOps 操作员可进一步改进部署方法,如 Flux。它是运行在集群中的代码循环,持续使集群中运行的配置与配置仓库中的配置一致,相比部署管道,能在出现差异时进行额外的协调。

4. 管理 Kubernetes 中的秘密数据

在 Kubernetes 中,有些敏感数据如数据库密码和 API 密钥等不适合直接存储在代码仓库中,Kubernetes 提供了 Secrets 对象来安全地存储这些秘密数据。

4.1 字符串类型的秘密数据

如果你之前在部署配置中使用明文环境变量来存储密码等秘密数据,现在可以将其迁移到 Secrets 对象中。例如,有一个值为 secret_value 的秘密数据,可将其封装到一个 Kubernetes Secret 对象中:

# StringSecrets/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secrets-production
type: Opaque
stringData:
  SECRET_KEY: secret_value
  ANOTHER_KEY: another_secret_value

Secrets 可以通过两种方式提供给 Pod:作为文件或作为环境变量。对于简单的字符串类型的秘密数据,通常使用环境变量的方式。以下示例展示了如何在 Deployment 中使用 Secrets 作为环境变量:

# StringSecrets/deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: timeserver
spec:
  replicas: 1
  selector:
    matchLabels:
      pod: timeserver-pod
  template:
    metadata:
      labels:
        pod: timeserver-pod
    spec:
      containers:
      - name: timeserver-container
        image: docker.io/wdenniss/timeserver:4
        env:
        - name: AVATAR_ENDPOINT # 普通的非秘密环境变量
          value: http://robohash-internal
        - name: SECRET_KEY # 从 Secret 中获取值的环境变量
          valueFrom:
            secretKeyRef:
              name: secrets-production
              key: SECRET_KEY

要验证配置是否生效,可以创建 Deployment 和 Secret,然后通过以下命令查看 Pod 中的环境变量:

$ kubectl get pods
$ kubectl exec <POD_NAME> -- env

你应该能在输出中看到 SECRET_KEY=secret_value

4.2 Base64 编码的秘密数据

在编写本文时,Kubernetes 文档和其他资料中经常展示使用 Base64 编码的秘密数据(使用 data 键而非 stringData )。这并非为了安全(Base64 是编码而非加密),而是为了表示在 YAML 中不兼容的数据。

以下是之前示例的 Base64 编码表示:

# Base64Secrets/secret-base64.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secrets-production
type: Opaque
data:
  SECRET_KEY: c2VjcmV0X3ZhbHVlCg==

在任何 *nix 系统上,可以使用以下命令进行 Base64 编码和解码:

$ echo "secret_value" | base64
c2VjcmV0X3ZhbHVlCg==
$ echo "c2VjcmV0X3ZhbHVlCg==" | base64 -D
secret_value

可以在同一个配置文件中同时包含 data stringData ,也可以在每个 Kubernetes Secret 对象中存储多个秘密数据。以下是一个包含多个秘密数据的示例:

# Base64Secrets/secrets-multiple.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secrets-production
type: Opaque
stringData:
  SECRET_KEY: secret_value
  ANOTHER_KEY: another_value
data:
  ENCODED_KEY: VGhpcyBzdHJpbmcKbWlnaHQgYmUgaGFyZCB0byByZXByZXNlbnQgaW4gWUFNTCDwn5iFCg==

从服务器检索的秘密数据是以 Base64 编码存储的,需要进行解码才能获取明文值。

4.3 文件类型的秘密数据

有时候,你可能需要将秘密数据以文件的形式提供给应用程序。Kubernetes 同样支持这种场景。

例如,有一个私钥文件,可将其存储在 Secrets 中。以下是使用 YAML 表示私钥文件的示例:

# FileSecrets/secret_file.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-files
type: Opaque
stringData:
  example.key: |
    -----BEGIN RSA PRIVATE KEY-----
    MIGsAgEAAiEA4TneQFg/UMsVGrAvsm1wkonC/5jX+ykJAMeNffnlPQkCAwEAAQIh
    ANgcs+MgClkXFQAP0SSvmJRmnRze3+zgUbN+u+rrYNRlAhEA+K0ghKRgKlzVnOxw
    qltgTwIRAOfb8LCVNf6FAdD+bJGwHycCED6YzfO1sONZBQiAWAf6Am8CEQDIEXI8
    fVSNHmp108UNZcNLAhEA3hHFV5jZppEHHHLy4F9Dnw==
    -----END RSA PRIVATE KEY-----

如果你觉得处理 YAML 语法比较繁琐,也可以使用 Base64 编码文件数据:

# FileSecrets/secret_file_base64.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-files
type: Opaque
data:
  example.key: LS0tLS1CRUdJTiBSU0EgU...SBLRVktLS0tLQo=

使用 kubectl 可以更自动化地创建 Secrets 文件:

$ kubectl create secret generic secret-files --from-file=example.key=./example.key --dry-run=client -o yaml

--dry-run=client -o yaml 表示不会实际在服务器上创建 Secret ,而是将其输出为 YAML 格式,方便你将其保存到配置文件中,后续使用 kubectl apply -f filename.yaml 应用到服务器。

创建 Secrets 后,可以将其挂载到指定的文件夹中。以下示例将 secret-files 挂载到 /etc/config 文件夹:

# 挂载 Secret 到指定文件夹的示例配置
# 这里省略了 Deployment 等其他部分,仅展示挂载 Secret 的关键部分
spec:
  containers:
  - name: my-container
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/config
  volumes:
  - name: secret-volume
    secret:
      secretName: secret-files

总结

通过以上方法,你可以更安全、高效地管理 Kubernetes 中的配置和秘密数据。在配置管理方面,采用配置即代码的方式,结合部署管道和 GitOps 操作员,确保部署的配置与代码仓库中的一致。在秘密数据管理方面,利用 Kubernetes 的 Secrets 对象,将敏感数据与配置分离,避免数据泄露风险。同时,根据不同类型的秘密数据(字符串、Base64 编码、文件),选择合适的存储和使用方式。

流程图

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(对部署环境配置更改):::process --> B(提交更改):::process
    B --> C(使用 kubectl 设置当前命名空间):::process
    C --> D(运行 kubectl apply -f . 更新实时状态):::process
    D --> E{是否有额外更改}:::process
    E -->|是| F(在配置代码仓库修改并推送):::process
    F --> D
    E -->|否| G(部署完成):::process

表格

管理方面 方法 描述
配置管理 配置即代码 将配置提交到版本控制系统,进行版本管理和同行评审
配置管理 部署管道 基于代码仓库触发,确保部署配置与提交一致
配置管理 GitOps 操作员 持续协调集群与仓库配置,处理差异
秘密数据管理 字符串类型 将明文秘密数据封装到 Secret 对象,通过环境变量使用
秘密数据管理 Base64 编码 处理在 YAML 中不兼容的数据,需解码获取明文
秘密数据管理 文件类型 将秘密文件存储在 Secret 中,挂载到指定文件夹
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值