使用 Jenkins 持续部署到 Google Kubernetes Engine

本教程介绍如何使用 Jenkins 和 Google Kubernetes Engine (GKE) 设置持续交付流水线,如下图所示。

Jenkins 持续交付架构。

目标

  • 了解示例应用。
  • 将应用部署到 GKE。
  • 将代码上传到 Cloud Source Repositories。
  • 在 Jenkins 中创建部署流水线。
  • 部署开发环境。
  • 部署 Canary 版本。
  • 部署生产环境。

费用

本教程使用 Google Cloud 的以下收费组件:

  • Compute Engine
  • Google Kubernetes Engine
  • Cloud Build

您可以使用价格计算器根据本教程中您的预计使用情况来估算费用。GCP 新用户可能有资格免费试用

准备工作

  1. 登录您的 Google 帐号。

    如果您还没有 Google 帐号,请注册一个新帐号

  2. 在 Cloud Console 的项目选择器页面上,选择或创建 Cloud 项目。

    转到项目选择器页面

  3. 确保您的 Google Cloud 项目已启用结算功能。 了解如何确认您的项目已启用结算功能

  4. 启用 Compute Engine, GKE, and Cloud Build API。

    启用 API

准备环境

  1. 完成在 GKE 上设置 Jenkins 教程。 确保您在 GKE 中安装的 Jenkins 是在安装运行。

  2. 在 Cloud Shell 中,克隆示例代码:

    git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes
    cd continuous-deployment-on-kubernetes/sample-app
    
  3. cluster-admin 角色应用于 Jenkins 服务帐号:

    kubectl create clusterrolebinding jenkins-deploy \
        --clusterrole=cluster-admin --serviceaccount=default:cd-jenkins
    

    在本教程中,Jenkins 服务帐号需要 cluster-admin 权限才能创建应用所需的 Kubernetes 命名空间和任何其他资源。对于生产用途,您应该为必要的各项权限编目,并将其分别应用于服务帐号。

了解应用

您将在持续部署流水线中部署示例应用 gceme。该应用使用 Go 语言编写,位于代码库的 sample-app 目录中。当您在 Compute Engine 实例上运行 gceme 二进制文件时,应用会在信息卡片中显示实例的元数据。

gceme 信息卡片

该应用通过支持两种操作模式来模拟微服务:

  • 在后端模式下,gceme 侦听端口 8080 并以 JSON 格式返回 Compute Engine 实例元数据。

  • 在前端模式下,gceme 查询后端 gceme 服务,并在用户界面中显示 JSON 格式的查询结果。

    gceme 架构

前端模式和后端模式支持两个额外的网址:

  • /version 打印正在运行的版本。
  • /healthz 报告应用的运行状况。在前端模式下,如果后端可以访问,则运行状况会显示为 OK

将示例应用部署到 Kubernetes

使用描述部署环境的清单文件将 gceme 前端和后端部署到 Kubernetes。这些文件使用的是本教程后面更新的默认映像。

将应用部署到两个环境中。

  • 生产环境。您的用户访问的实际网站。

  • Canary 环境。容量较小的网站,可接收一定比例的用户流量。使用此环境可以在将软件发布到实际环境之前通过实时流量对软件进行健全性检查。

首先,将您的应用部署到生产环境中,以使用工作代码为流水线设定种子。

  1. 创建 Kubernetes 命名空间以从逻辑上隔离生产部署:

    kubectl create ns production
    
  2. 创建 Canary 和生产部署和服务:

    kubectl --namespace=production apply -f k8s/production
    kubectl --namespace=production apply -f k8s/canary
    kubectl --namespace=production apply -f k8s/services
    
  3. 对生产环境前端进行纵向扩容:

    kubectl --namespace=production scale deployment gceme-frontend-production --replicas=4
    
  4. 检索生产服务的外部 IP。您可能需要几分钟才能看到负载平衡器的 IP 地址。

    kubectl --namespace=production get service gceme-frontend
    

    该过程完成后,IP 地址将显示在 EXTERNAL-IP 列中。

    NAME             TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
    gceme-frontend   LoadBalancer   10.35.254.91   35.196.48.78   80:31088/TCP   1m
    
  5. 将前端服务负载平衡器的 IP 存储在环境变量中:

    export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=production services gceme-frontend)
    
  6. 通过在浏览器中打开前端外部 IP 地址,确认两个服务都正常运行。

  7. 打开一个单独的终端并轮询生产端点的 /version 网址,以便在下一部分中观察滚动更新。

    while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1;  done
    

创建代码库以托管示例应用源代码

接下来,创建 gceme 示例应用的副本并将其推送到 Cloud Source Repositories

  1. 运行以下命令在 Cloud Source Repositories 中创建代码库:

    gcloud source repos create gceme
    
  2. 初始化本地 Git 代码库:

    git init
    git config credential.helper gcloud.sh
    export PROJECT_ID=$(gcloud config get-value project)
    git remote add origin https://source.developers.google.com/p/$PROJECT_ID/r/gceme
    
  3. 为代码库中的 Git 提交设置用户名和电子邮件地址。 将 [EMAIL_ADDRESS] 替换为您的 Git 电子邮件地址,并将 [USERNAME] 替换为您的 Git 用户名。

    git config --global user.email "[EMAIL_ADDRESS]"
    git config --global user.name "[USERNAME]"
    
  4. 添加、提交和推送文件:

    git add .
    git commit -m "Initial commit"
    git push origin master
    

创建流水线

使用 Jenkins 定义和运行流水线,以便对您的 gceme 副本进行测试、构建,并将其部署到 Kubernetes 集群。

添加服务帐号凭据

配置凭据以允许 Jenkins 访问代码库。

  1. 在 Jenkins 用户界面中,点击左侧导航中的凭据
  2. 点击凭据表中的 Jenkins 链接。

    Jenkins 凭据组

  3. 点击全局凭据

  4. 点击左侧导航中的添加凭据

  5. 种类下拉列表中选择元数据中的 Google 服务帐号

  6. 点击确定

现在有两个全局凭据。记下第二个凭据的名称,以便稍后在本教程中使用。

Jenkins 凭据。

创建 Jenkins 作业

接下来,使用 Jenkins 流水线功能配置构建流水线。Jenkins 流水线文件使用类 Groovy 的语法编写。

导航到 Jenkins 用户界面并按照以下步骤配置流水线作业。

  1. 点击界面左上角的 Jenkins 链接。
  2. 点击左侧导航中的新建内容链接。
  3. 将项目命名为 sample-app,选择多分支流水线选项,然后点击确定
  4. 在下一页上,点击添加源并选择 git
  5. 将 Cloud Source Repositories 中 sample-app 代码库的 HTTPS 克隆网址粘贴到项目代码库字段中。将 [PROJECT_ID] 替换为您的项目 ID。

    https://source.developers.google.com/p/[PROJECT_ID]/r/gceme
    
  6. 凭据下拉列表中,选择添加服务帐号时创建的凭据的名称。

  7. 扫描多分支流水线部分中,选择如果不运行则定期扫描框。将间隔值设置为“1分钟”。

  8. 点击保存

    创建 Jenkins 作业设置。

完成这些步骤后,系统将运行名为“Branch indexing”的作业。此元作业标识代码库中的分支,并确保现有分支中未发生更改。如果刷新 Jenkins,master 分支将显示此作业。

第一次运行此作业会失败,直到您在下一步中进行一些代码更改。

修改流水线定义

为 Canary 环境创建一个名为 canary 的分支。

git checkout -b canary

定义该流水线的 Jenkinsfile 容器使用 Jenkins Pipeline Groovy 语法编写。 使用 Jenkinsfile 可以将整个构建流水线表示在与源代码共存的单个文件中。流水线支持强大的功能(如并行化)且需要手动用户批准。

修改 Jenkinsfile,使其包含第 1 行的项目 ID。

部署 Canary 版本

现在您的流水线已配置正确,您可以对 gceme 应用进行更改,并用流水线对其进行测试、打包和部署。

Canary 环境被设置为 Canary 版本。 因此,您的更改将发布到生产负载平衡器后面的一小部分 pod 中。您可以通过维护共享相同标签的多个部署,在 Kubernetes 中实现此目的。对于此应用,gceme-frontend 服务在具有标签 app: gcemerole: frontend 的所有 pod 中实现负载平衡。k8s/frontend-canary.yaml Canary 清单文件将副本设置为 1 并包含 gceme-frontend 服务所需的标签。

目前,您有五分之一的前端 pod 运行 Canary 代码,其他五分之四运行生产代码。这有助于确保在发布至所有 pod 之前,Canary 代码不会对用户产生负面影响。

  1. 打开 html.go 并将 blue 的两个实例替换为 orange
  2. 打开 main.go 并将版本号从 1.0.0 更改为 2.0.0

    const version string = "2.0.0"
    
  3. 接下来,添加这些文件并将其提交到本地代码库:

    git add Jenkinsfile html.go main.go
    git commit -m "Version 2"
    
  4. 最后,将您的更改推送到远程 Git 服务器:

    git push origin canary
    
  5. 将更改推送到 Git 代码库后,导航到 Jenkins 界面,您可以在其中看到您的构建已启动。

    Jenkins 首个构建屏幕。

  6. 构建运行后,点击左侧导航窗格中构建旁边的向下箭头,然后选择控制台输出

    Jenkins 控制台导航。

  7. 跟踪构建的输出几分钟,并观察 kubectl --namespace=production apply... 消息是否开始。开始后,请检查正在轮询生产 /version 网址的终端,并观察某些请求是否开始更改。现在,您已将该更改发布至一部分用户。

  8. 将更改部署到 Canary 环境后,您可以通过将代码与 master 分支合并并将其推送到 Git 服务器,继续将更改发布至其他用户。

    git checkout master
    git merge canary
    git push origin master
    
  9. 大约 1 分钟后,sample-app 文件夹中的 master 作业开始运行。

    Jenkins 主作业。

  10. 点击 master 链接可显示流水线的各个阶段,以及通过/失败信息和时序特征。

    Jenkins 流水线生产环境。

  11. 轮询生产网址以验证新版本 2.0.0 是否已发布,以及是否正在处理来自所有用户的请求。

    export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)
    while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1;  done
    

您可以查看项目中的 Jenkinsfile 以查看工作流。

部署开发分支

有时您需要处理无法直接推送到 Canary 环境的重大更改,因而催生了开发分支,这是开发者在提交代码更改以将其集成到实际网站之前对其进行测试的一组环境。这些环境是应用的缩小版本,但使用与实际环境相同的机制进行部署。

如需从功能分支创建开发环境,可以将该分支推送到 Git 服务器,通过 Jenkins 部署您的环境。在开发场景中,您不应使用公开的负载平衡器。为了帮助保护您的应用,您可以使用 kubectl 代理。此代理使用 Kubernetes API 对自身进行身份验证,并将来自本地机器的请求代理到集群中的服务,而不会将您的服务暴露给互联网。

  1. 创建另一个分支并将其推送到 Git 服务器。

    git checkout -b new-feature
    git push origin new-feature
    

    系统将创建一个新作业,并且您的开发环境正在创建中。作业的控制台输出的底部是访问环境的说明。

  2. 在后台启动代理。

    kubectl proxy &
    
  3. 使用 localhost 验证您的应用是否可供访问:

    curl http://localhost:8001/api/v1/namespaces/new-feature/services/gceme-frontend:80/proxy/
    
  4. 您现在可以将代码推送到此分支以更新您的开发环境。完成后,将您的分支合并回 canary,以将该代码部署到 Canary 环境中。

    git checkout canary
    git merge new-feature
    git push origin canary
    
  5. 如果您确信您的代码不会在生产环境中产生问题,请从 canary 分支合并到 master 分支以启动部署:

    git checkout master
    git merge canary
    git push origin master
    
  6. 用完开发分支后,将其从服务器中删除并从 Kubernetes 集群中删除该环境:

    git push origin :new-feature
    kubectl delete ns new-feature
    

清理

为避免因本教程中使用的资源而导致您的 Google Cloud Platform 帐号产生费用,请执行以下操作:

删除项目

为了避免产生费用,最简单的方法是删除您为本教程创建的项目。

如需删除项目,请执行以下操作:

  1. 在 Cloud Console 中,转到管理资源页面。

    转到“管理资源”页面

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

后续步骤