使用 kpt 管理云基础架构

Last reviewed 2023-03-15 UTC

本教程介绍 Google 提供的开源工具 kpt,它可让您对 Kubernetes 配置(也称为清单)进行操作,包括打包、拉取、更新和修改。如果您想要在配置和这些配置上的操作之间保持完全隔离,kpt 可以替代基于模板的工具。使用 kpt,您可以重复使用和共享处理配置(修改或检查)的代码。

本教程还介绍了如何将 kpt 与其他 Google 解决方案(如 Config SyncGKE Enterprise 安全蓝图)结合使用。无论您是与 Kubernetes 合作的开发者,还是管理基于 Kubernetes 的平台的平台工程师,本教程都可以让您了解如何在您自己的 Kubernetes 相关工作流中使用 kpt。本教程假定您熟悉 Kubernetes 和 Google Cloud。

云基础架构的声明式配置是 IT 行业中确立的良好做法。它引入了底层系统的强大抽象结构。这种抽象使您不必管理底层配置细节和依赖项。因此,与命令式方法(例如在图形和命令行界面中执行的操作)相比,声明式配置具有优势。

Kubernetes 资源模型在使声明式配置方法成为主流方面发挥着重要作用。因为 Kubernetes API 本质上是完全声明性的,所以您只需告诉 Kubernetes 您想要什么,而不是如何实现您想要的。Kubernetes API 使您可以将配置(无论是期望的还是实际的)与配置操作(添加、移除和修改对象)完全分开。换句话说,在 Kubernetes 资源模型中,配置是数据,而不是代码。

配置与操作的这种分离具有许多优点:人员和自动化系统可以理解和使用配置,并且修改配置的软件易于重复使用。此分离也可让您轻松实现 GitOps 方法(如使用 Cloud Build 实现 GitOps 形式的持续交付教程中所述)。

在本教程中,您将使用 kpt 探索配置声明与配置操作的分离。本教程重点介绍了 kpt 的以下功能:

  • 软件包管理:下载和更新 Kubernetes 配置软件包。
  • 函数:运行任意一段代码以修改或验证您的配置。
  • 函数流水线:软件包作者包含在软件包中的一组函数。
  • 资源管理:应用、更新和删除与 Kubernetes 集群中配置对应的资源。

目标

  • 创建 Google Kubernetes Engine (GKE) 集群。
  • 使用 kpt 下载一组现有的 Kubernetes 配置。
  • 使用 kpt 函数自定义配置。
  • 将您的配置应用到 GKE 集群。
  • 使用 kpt 拉取配置的一些上游更改。
  • 在实际场景中使用 kpt 强化 GKE 集群。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

  • Google Kubernetes Engine

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  5. 确保您的 Google Cloud 项目已启用结算功能

  6. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

    Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。

  7. 将 Cloud Shell 配置为使用您的项目:

    gcloud config set project PROJECT_ID
    
  8. 在 Cloud Shell 中,启用 Google Kubernetes Engine 和 Cloud Source Repositories API:

    gcloud services enable container.googleapis.com \
       sourcerepo.googleapis.com
    

完成本教程后,您可以通过删除您创建的资源来避免继续计费。如需了解详情,请参阅清理

创建 GKE 集群

在本部分中,您将创建 GKE 集群,以便在本教程的后面部分中部署配置。

  1. 在 Cloud Shell 中创建一个 GKE 集群:

    gcloud container clusters create kpt-tutorial \
       --num-nodes=1 --machine-type=n1-standard-4 \
       --zone=us-central1-a --enable-network-policy
    
  2. 验证您有权访问该集群。以下命令返回有关集群中一个或多个节点的信息。

    kubectl get nodes
    

应用 kpt 软件包

在本部分中,您将使用 kpt 下载一组配置,对其进行自定义,并将其应用到您在上一部分中创建的集群。 kpt 应安装在 Cloud Shell 环境中。如果不是,请使用以下命令进行安装:

  1. 在 Cloud Shell 中,安装 kpt:

    sudo apt update && sudo apt-get install google-cloud-sdk-kpt
    
  2. 下载一组示例配置。如需了解详情,请参阅 kpt pkg get

    kpt pkg get https://github.com/GoogleContainerTools/kpt.git/package-examples/wordpress@v0.9
    

    上述命令会下载 kpt GitHub 代码库中提供的 wordpress 示例软件包,其版本标记为 v0.9

  3. 检查软件包内容:kpt pkg tree

    kpt pkg tree wordpress
    

    输出如下所示:

    Package "wordpress"
    ├── [Kptfile]  Kptfile wordpress
    ├── [service.yaml]  Service wordpress
    ├── deployment
    │   ├── [deployment.yaml]  Deployment wordpress
    │   └── [volume.yaml]  PersistentVolumeClaim wp-pv-claim
    └── Package "mysql"
        ├── [Kptfile]  Kptfile mysql
        ├── [deployment.yaml]  PersistentVolumeClaim mysql-pv-claim
        ├── [deployment.yaml]  Deployment wordpress-mysql
        └── [deployment.yaml]  Service wordpress-mysql
    

    该软件包包含两个软件包,分别为顶层的 wordpress 和子软件包 wordpress/mysql,这两个软件包都包含元数据文件 KptfileKptfile 仅由 kpt 本身使用,包含有关软件包的上游源代码、自定义和验证的数据。

  4. 更新软件包的标签

    软件包作者添加了一个渲染流水线,通常用于传达预期的自定义内容。

    less wordpress/Kptfile
    

    内容应如下所示:

    apiVersion: kpt.dev/v1
    kind: Kptfile
    metadata:
      name: wordpress
    upstream:
      type: git
      git:
        repo: https://github.com/GoogleContainerTools/kpt
        directory: /package-examples/wordpress
        ref: v0.9
      updateStrategy: resource-merge
    upstreamLock:
      type: git
      git:
        repo: https://github.com/GoogleContainerTools/kpt
        directory: /package-examples/wordpress
        ref: package-examples/wordpress/v0.9
        commit: b9ea0bca019dafa9f9f91fd428385597c708518c
    info:
      emails:
        - kpt-team@google.com
      description: This is an example wordpress package with mysql subpackage.
    pipeline:
      mutators:
        - image: gcr.io/kpt-fn/set-labels:v0.1
          configMap:
            app: wordpress
      validators:
        - image: gcr.io/kpt-fn/kubeval:v0.3
    

    您可以使用自己喜欢的编辑器将 set-label 函数的参数从 app: wordpress 更改为 app: my-wordpress

  5. 使用您偏爱的代码编辑器修改 MySQL 部署 wordpress/mysql/deployment.yaml,以更改 MySQL 版本。此外,如需进一步增强安全性,请将 MYSQL_ROOT_PASSWORD 变量更改为 MYSQL_PASSWORD,并添加以下变量:

    • MYSQL_USER
    • MYSQL_RANDOM_ROOT_PASSWORD
    • MYSQL_DATABASE

    之前:

    [...]
      containers:
        - name: mysql
          image: mysql:5.6
          ports:
            - name: mysql
              protocol: TCP
              containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password
    [...]
    

    之后:

    [...]
      containers:
        - name: mysql
          image: mysql:8.0
          ports:
            - name: mysql
              protocol: TCP
              containerPort: 3306
          env:
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password
            - name: MYSQL_RANDOM_ROOT_PASSWORD
              value: '1'
            - name: MYSQL_USER
              value: wordpress
            - name: MYSQL_DATABASE
              value: wordpress
    [...]
    
  6. 使用您偏爱的代码编辑器修改 Wordpress 部署 wordpress/deployment/deployment.yaml,以更改 Wordpress 版本并添加 WORDPRESS_DB_USER 变量。

    之前:

    [...]
      containers:
        - name: wordpress
          image: wordpress:6.1-apache
          ports:
            - name: wordpress
              protocol: TCP
              containerPort: 80
          env:
            - name: WORDPRESS_DB_HOST
              value: wordpress-mysql
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password
    [...]
    

    之后:

    [...]
      containers:
        - name: wordpress
          image: wordpress:4.8-apache
          ports:
            - name: wordpress
              protocol: TCP
              containerPort: 80
          env:
            - name: WORDPRESS_DB_HOST
              value: wordpress-mysql
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password
            - name: WORDPRESS_DB_USER
              value: wordpress
    [...]
    

    与仅通过参数运行的工具不同,kpt 允许您使用编辑器直接修改文件,然后仍合并上游更新。您可以直接修改 deployment.yaml,而无需编写补丁程序或在流水线中创建函数。

  7. 使用 sample-annotation: sample-value 为配置添加注解。

    kpt fn eval wordpress --image gcr.io/kpt-fn/set-annotations:v0.1 \
      -- sample-annotation=sample-value
    

    输出应类似如下:

    [RUNNING] "gcr.io/kpt-fn/set-annotations:v0.1"
    [PASS] "gcr.io/kpt-fn/set-annotations:v0.1"
    

    如需查看新注解,您可以检查任何配置值,一个简单的例子是 wordpress/service.yaml

    在此示例中,我们以软件包作者未曾计划的方式使用函数进行了自定义。kpt 能够支持声明式和命令式函数执行,从而适用于广泛的场景。

    如果此软件包是使用基础架构即代码开发的,我们需要转到软件包的来源并在该处修改代码。

  8. 运行流水线,并通过 kpt 使用 kubeval 验证更改。

    kpt fn render wordpress
    

    软件包作者在流水线中包含了验证步骤:

    ...
    validators:
        - image: gcr.io/kpt-fn/kubeval:v0.3
    

    此渲染流水线的成功输出如下所示:

    Package "wordpress/mysql":
    [RUNNING] "gcr.io/kpt-fn/set-labels:v0.1"
    [PASS] "gcr.io/kpt-fn/set-labels:v0.1" in 1.3s
    
    Package "wordpress":
    [RUNNING] "gcr.io/kpt-fn/set-labels:v0.1"
    [PASS] "gcr.io/kpt-fn/set-labels:v0.1" in 1.3s
    [RUNNING] "gcr.io/kpt-fn/kubeval:v0.3"
    [PASS] "gcr.io/kpt-fn/kubeval:v0.3" in 3.7s
    
    Successfully executed 3 function(s) in 2 package(s).
    

    此步骤是使用 Kubernetes 资源模型的好处的一个示例:由于您的配置在此知名模型中表示,您可以使用现有的 Kubernetes 工具(例如 kubeval)。

  9. 检查本地配置版本和上游配置之间的区别:

    kpt pkg diff wordpress
    
  10. 初始化软件包以进行部署:

    kpt live init wordpress
    

    上述命令用于构建软件包中的配置清单。此外,当您从软件包中移除配置时,kpt 会使用清单来删减配置。如需了解详情,请参阅 kpt live

  11. 创建包含 MySQL 密码的 Secret:

    kubectl create secret generic mysql-pass --from-literal=password=foobar
    
  12. 将配置应用到您的 GKE 集群。

    kpt live apply wordpress
    

    输出如下所示:

    installing inventory ResourceGroup CRD.
    inventory update started
    inventory update finished
    apply phase started
    service/wordpress apply successful
    service/wordpress-mysql apply successful
    deployment.apps/wordpress apply successful
    deployment.apps/wordpress-mysql apply successful
    persistentvolumeclaim/mysql-pv-claim apply successful
    persistentvolumeclaim/wp-pv-claim apply successful
    apply phase finished
    reconcile phase started
    service/wordpress reconcile successful
    service/wordpress-mysql reconcile successful
    deployment.apps/wordpress reconcile pending
    deployment.apps/wordpress-mysql reconcile pending
    persistentvolumeclaim/mysql-pv-claim reconcile pending
    persistentvolumeclaim/wp-pv-claim reconcile pending
    persistentvolumeclaim/wp-pv-claim reconcile successful
    persistentvolumeclaim/mysql-pv-claim reconcile successful
    deployment.apps/wordpress-mysql reconcile successful
    deployment.apps/wordpress reconcile successful
    reconcile phase finished
    inventory update started
    inventory update finished
    apply result: 6 attempted, 6 successful, 0 skipped, 0 failed
    reconcile result: 6 attempted, 6 successful, 0 skipped, 0 failed, 0 timed out
    
  13. 等待几分钟,然后验证一切是否按预期运行:

    kpt live status wordpress
    

    输出如下所示:

    inventory-88521939/deployment.apps/default/wordpress is Current: Deployment is available. Replicas: 1
    inventory-88521939/persistentvolumeclaim/default/wp-pv-claim is Current: PVC is Bound
    inventory-88521939/service/default/wordpress-mysql is Current: Service is ready
    inventory-88521939/persistentvolumeclaim/default/mysql-pv-claim is Current: PVC is Bound
    inventory-88521939/deployment.apps/default/wordpress-mysql is Current: Deployment is available. Replicas: 1
    inventory-88521939/service/default/wordpress is Current: Service is ready
    

更新本地软件包

在本节中,您将使用上游软件包的一些更改来更新软件包的本地版本。

  1. 为您的配置创建 Git 代码库,并配置您的电子邮件地址和名称。您需要一个本地 Git 代码库才能更新软件包。请将 YOUR_EMAIL 替换为您的电子邮件地址,将 YOUR_NAME 替换为您的名称。

    cd wordpress/
    git init -b main
    git config user.email "YOUR_EMAIL"
    git config user.name "YOUR_NAME"
    
  2. 提交配置:

    git add .
    git commit -m "First version of Wordpress package"
    cd ..
    
  3. 更新本地软件包。在此步骤中,您将从上游拉取 v0.10 版本。

    kpt pkg update wordpress@v0.10
    
  4. 查看上游的更新会应用到您的本地软件包:

    cd wordpress/
    git diff
    

    在此示例中,更新已将 Wordpress 部署卷从 3Gi 更改为 4Gi。您也可以查看自己的更改。

  5. 提交所做的更改:

    git commit -am "Update to package version v0.10"
    
  6. 应用新版本的软件包:

    kpt live apply .
    

移除资源和软件包

由于 kpt 会跟踪它创建的资源,因此当您从软件包中删除资源时,kpt 可能会从集群中删减资源。它也可以从集群中完全移除软件包。在本部分中,您将从软件包中移除资源,然后移除软件包。

  1. 从软件包中移除 service.yaml 文件:

    git rm service.yaml
    git commit -m "Remove service"
    
  2. 应用更改,然后验证 kpt 是否删减了 wordpress 服务:

    kpt live apply .
    kubectl get svc
    
  3. 从集群中移除软件包的其余内容,然后验证集群中是否没有剩余内容:

    kpt live destroy .
    kubectl get deployment
    

使用 kpt 强化 GKE

kpt live 命令不是将软件包应用于 Kubernetes 集群的唯一方法。在本部分中,您将在基本但实际的场景中将 kpt 与 Config Sync 结合使用。借助 Config Sync 工具,您可以通过 Git 代码库集中、统一、以声明方式管理所有 Kubernetes 集群的配置。您在本教程中使用的 GKE Enterprise 包含 Config Sync

GKE Enterprise 安全蓝图为基于 GKE Enterprise 的工作负载提供了一系列预封装的安全设置。在本部分中,您将使用限制流量蓝图(以及它在 GitHub 代码库中的目录)。您使用 kpt 下载 default-deny 软件包。该软件包默认使用 Kubernetes 网络政策来拒绝 GKE 集群中的任何流量(DNS 解析除外)。为了应用配置,您随即将配置提交到 Config Sync Git 代码库。

安装 Config Sync

在本部分中,您将创建 Config Sync 需要的 Git 代码库,然后在 GKE 集群上安装 Config Sync。

  1. 在 Cloud Shell 中,使用 Cloud Source Repositories 为 Config Sync 创建 Git 代码库:

    cd ~
    gcloud source repos create config-management
    
  2. 生成 SSH 密钥对,以向 Git 代码库进行身份验证:

    cd ~
    ssh-keygen -t rsa -b 4096  -N '' \
       -f cloud_source_repositories_key
    
  3. 创建包含 SSH 私钥的 Kubernetes Secret 以访问 Git 代码库:

    kubectl create ns config-management-system && \
    kubectl create secret generic git-creds \
      --namespace=config-management-system \
      --from-file=ssh=cloud_source_repositories_key
    
  4. 显示公钥,然后复制它:

    cat cloud_source_repositories_key.pub
    
  5. 转到 Cloud Source Repositories

    管理 SSH 密钥页面。

  6. 在随后显示的注册 SSH 密钥对话框中,输入以下值:

    1. 密钥名称字段中,输入 config-management
    2. 密钥字段中,粘贴公钥。
    3. 点击注册
  7. 将 Git 代码库克隆到 Cloud Shell:

    gcloud source repos clone config-management
    cd config-management
    git checkout -b main
    
  8. 下载名为 nomos 的 Config Sync 命令行工具。nomos 应安装在 Cloud Shell 环境中。如果不是,请使用以下命令进行安装:

    sudo apt update && sudo apt-get install google-cloud-sdk-nomos
    
  9. 初始化 Config Sync 代码库:

    nomos init
    git add .
    git commit -m "Config Management directory structure"
    git push -u origin main
    
  10. 部署 Config Sync Operator:

    gsutil cp gs://config-management-release/released/latest/config-management-operator.yaml /tmp/config-management-operator.yaml
    kubectl apply -f /tmp/config-management-operator.yaml
    

配置 Config Sync

  1. 创建 ConfigManagement 自定义资源以配置 Config Sync:

    PROJECT=$(gcloud config get-value project)
    EMAIL=$(gcloud config get-value account)
    cat <<EOF > /tmp/config-management.yaml
    apiVersion: configmanagement.gke.io/v1
    kind: ConfigManagement
    metadata:
      name: config-management
    spec:
      clusterName: kpt-tutorial
      git:
        syncRepo: ssh://${EMAIL}@source.developers.google.com:2022/p/${PROJECT}/r/config-management
        syncBranch: main
        secretType: ssh
    EOF
    kubectl -n config-management-system \
        apply -f /tmp/config-management.yaml
    

    如需了解更多安装选项,请参阅安装 Config Sync 文档

  2. 在 Cloud Shell 中,验证 Config Sync 是否正常运行:

    nomos status --contexts=$(kubectl config current-context)
    

    此命令会返回 SYNCED 状态。Config Sync 初始化可能需要一些时间。如果状态未更新,请等待几分钟,然后重新运行该命令。

应用 GKE Enterprise 安全蓝图

在本部分中,您将使用 kpt 下载限制流量 GKE Enterprise 安全蓝图的 default-deny 软件包。然后,使用 Config Sync 仅将软件包应用于 default 命名空间。

  1. 下载 default-deny 软件包:

    cd ~
    kpt pkg get https://github.com/GoogleCloudPlatform/anthos-security-blueprints.git/restricting-traffic/default-deny ./
    

    您可以浏览软件包的内容:default-deny/Kptfile 文件包含软件包的元数据,而 default-deny/default-deny.yaml 文件包含 Kubernetes NetworkPolicy,它是此蓝图的仅有配置。

  2. 使用 kpt 复制 Config Sync 代码库中软件包的内容,然后添加标签以进行自定义:

    kpt fn source default-deny/ | \
        kpt fn eval - --image=gcr.io/kpt-fn/set-annotations:v0.1 -- \
        anthos-security-blueprint=restricting-traffic | \
        kpt fn sink ~/config-management/namespaces/default/
    

    如本示例中所示,您可以使用管道将 kpt fn 命令连在一起。通过将 kpt fn 命令连在一起,您可以读取配置、根据需要修改配置并写入结果。您可以根据需要将任意数量的 kpt fn 命令连在一起。

  3. 在 Config Sync 代码库中创建 namespace.yaml 文件:

    cat >> ~/config-management/namespaces/default/namespace.yaml <<EOF
    apiVersion: v1
    kind: Namespace
    metadata:
      name: default
    EOF
    

    default 命名空间存在于 GKE 集群中,但 Config Sync 不管理该命名空间。在此步骤中创建目录和文件时,请让 Config Sync 管理该命名空间。如需将该软件包同时应用于多个命名空间,您可以创建抽象命名空间

  4. 验证 Kubernetes NetworkPolicy 是否已写入 Config Sync 代码库,以及是否使用 anthos-security-blueprint: restricting-traffic 进行注解:

    cat config-management/namespaces/default/default-deny.yaml
    

    输出如下所示:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata: # kpt-merge: /default-deny
      name: default-deny
      annotations:
        internal.kpt.dev/upstream-identifier: 'networking.k8s.io|NetworkPolicy|default|default-deny'
        anthos-security-blueprint: restricting-traffic
    spec:
      policyTypes:
      - Ingress
      - Egress
      podSelector: {}
      egress:
      - to:
        - namespaceSelector:
            matchLabels:
              k8s-namespace: kube-system
          podSelector:
            matchExpressions:
            - key: k8s-app
              operator: In
              values: ["kube-dns", "node-local-dns"]
        ports:
        - protocol: TCP
          port: 53
        - protocol: UDP
          port: 53
    
  5. 提交并推送更改:

    cd ~/config-management/
    git add namespaces/default/
    git commit -m "Default deny"
    git push
    
  6. 验证新政策是否已应用:

    kubectl get networkpolicies
    

    如果新政策不存在,请等待几秒钟,然后再次运行该命令。默认情况下,Config Sync 每 15 秒更新一次配置。如果您需要进行一些额外的问题排查,请运行以下命令以获得任何潜在的 Config Sync 错误的相关信息:

    nomos status --contexts=$(kubectl config current-context)
    
  7. 如需测试新政策,请在 default 命名空间中运行的 pod 中获取一个 shell:

    kubectl -n default run -i --tty --rm test \
            --image=busybox --restart=Never -- sh
    
  8. 尝试 ping 8.8.8.8,然后查看它是否未按预期运行:

    ping -c 3 -W 1 8.8.8.8
    

    输出如下所示:

    PING 8.8.8.8 (8.8.8.8): 56 data bytes
    
    --- 8.8.8.8 ping statistics ---
    3 packets transmitted, 0 packets received, 100% packet loss
    
  9. 尝试查询 Kubernetes API 服务器,然后查看它是否未按预期运行:

    wget --timeout=3 https://${KUBERNETES_SERVICE_HOST}
    

    输出如下所示:

    Connecting to 10.3.240.1 (10.3.240.1:443)
    wget: download timed out
    
  10. 退出 pod:

    exit
    

清除数据

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除资源

如果您希望保留在本教程中使用的 Google Cloud 项目,则可以删除 Git 代码库和 GKE 集群。在 Cloud Shell 中,运行以下脚本:

gcloud source repos delete config-management --quiet
gcloud container clusters delete kpt-tutorial \
    --async --quiet --zone=us-central1-a

后续步骤