使用 Jenkins 在 Compute Engine 上进行分布式构建


本教程将介绍如何执行以下操作:

  • 创建 Jenkins 持续集成系统,以使用 Compute Engine 中的按需 Jenkins 代理运行构建。
  • 将构建工件存储在 Cloud Storage 中。
  • 应用生命周期政策,将 Cloud Storage 中较旧的构建工件移动到价格较低的存储方式中。

架构

下图展示了教程架构。

显示服务账号如何通过 Compute Engine 将工件推送到 Cloud Storage 的架构。

在该图中,Jenkins 中添加了一个服务账号,Jenkins 可通过该账号创建代理实例并将工件推送到 Cloud Storage 进行长期存储。Jenkins 在运行构建时即时预配实例。随着构建工件的老化,它们会在各种存储类别之间移动,以限制保留费用。

目标

  • 使用 Packer 创建基本映像,以运行 Jenkins 构建。
  • 使用 Cloud Marketplace 预配 Jenkins。
  • 配置 Jenkins,以部署临时构建代理。
  • 将构建工件上传到 Cloud Storage。
  • 配置生命周期政策,以优化 Cloud Storage 费用。

费用

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

  • Compute Engine
  • Cloud Storage

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

请使用价格计算器根据您的预计使用情况来估算费用。

准备工作

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

    转到“项目选择器”

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

  4. 启用 Compute Engine API。

    启用 API

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

    转到“项目选择器”

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

  7. 启用 Compute Engine API。

    启用 API

设置环境

在本部分中,您将配置完成本教程所需的基础架构和身份。您可以从 Cloud Shell 内部执行本教程的其余步骤。

打开 Cloud Shell

配置 IAM

创建 身份和访问权限管理 (IAM) 服务账号以将权限委派给 Jenkins。通过此账号,Jenkins 可以将数据存储在 Cloud Storage 中,并启动 Compute Engine 中的实例。Jenkins 在临时实例中运行构建,并将构建工件存储在 Cloud Storage 中。

创建服务账号

  1. 创建服务账号:

    gcloud iam service-accounts create jenkins --display-name jenkins
  2. 将服务账号电子邮件地址和您的当前 Google Cloud 项目 ID 存储在环境变量中,以供后续命令使用:

    export SA_EMAIL=$(gcloud iam service-accounts list \
        --filter="displayName:jenkins" --format='value(email)')
    export PROJECT=$(gcloud info --format='value(config.project)')
  3. 将以下角色与您的服务账号绑定:

    gcloud projects add-iam-policy-binding $PROJECT \
        --role roles/storage.admin --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/compute.instanceAdmin.v1 \
        --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/compute.networkAdmin \
        --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/compute.securityAdmin \
        --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/iam.serviceAccountActor \
        --member serviceAccount:$SA_EMAIL

下载服务账号密钥

现在,您已经为服务账号授予了相应的权限,接下来需要创建并下载其密钥。请将密钥保存在安全的位置。在稍后的步骤中,当您配置 JClouds 插件以使用 Compute Engine API 进行身份验证时,将用到此密钥。

  1. 创建密钥文件:

    gcloud iam service-accounts keys create jenkins-sa.json --iam-account $SA_EMAIL
  2. 在 Cloud Shell 中,点击更多 ,然后点击下载文件

  3. 输入 jenkins-sa.json

  4. 点击下载以在本地保存文件。

创建 Jenkins 代理映像

接下来,您将创建一个可重复使用的 Compute Engine 映像,它包含作为 Jenkins 执行程序运行所需的软件和工具。

为 Cloud Shell 创建 SSH 密钥

在本教程的后面部分中,您将使用 Packer 构建映像,此操作需要使用 ssh 命令与构建实例进行通信。如需启用 SSH 访问权限,请在 Cloud Shell 中创建并上传 SSH 密钥:

  1. 创建 SSH 密钥对。如果已存在一个密钥对,则此命令将使用该密钥对;否则,它会创建一个新的密钥对:

    ls ~/.ssh/id_rsa.pub || ssh-keygen -N ""
  2. 将 Cloud Shell SSH 公钥添加到项目的元数据中:

    gcloud compute project-info describe \
        --format=json | jq -r '.commonInstanceMetadata.items[] | select(.key == "ssh-keys") | .value' > sshKeys.pub
    echo "$USER:$(cat ~/.ssh/id_rsa.pub)" >> sshKeys.pub
    gcloud compute project-info add-metadata --metadata-from-file ssh-keys=sshKeys.pub

创建基准映像

下一步是使用 Packer 为构建代理创建基准虚拟机 (VM) 映像,这些映像在 Jenkins 中充当临时构建执行程序。最基本的 Jenkins 代理只需要安装 Java。您可以自定义映像,方法是在 Packer 配置的 provisioners 部分中添加 shell 命令,或添加其他 Packer 预配工具

  1. 在 Cloud Shell 中,下载并解压缩 Packer 的最新版本。以下示例使用的是 Packer 1.7.10。您可以访问 Hashicorp 网站,查看是否有较新的版本:

    wget https://releases.hashicorp.com/packer/1.7.10/packer_1.7.10_linux_amd64.zip
    unzip packer_1.7.10_linux_amd64.zip
  2. 为 Packer 映像构建创建配置文件:

    export PROJECT=$(gcloud info --format='value(config.project)')
    cat > jenkins-agent.json <<EOF
    {
      "builders": [
        {
          "type": "googlecompute",
          "project_id": "$PROJECT",
          "source_image_family": "ubuntu-2004-lts",
          "source_image_project_id": "ubuntu-os-cloud",
          "zone": "us-central1-a",
          "disk_size": "50",
          "image_name": "jenkins-agent-{{timestamp}}",
          "image_family": "jenkins-agent",
          "ssh_username": "ubuntu"
        }
      ],
      "provisioners": [
        {
          "type": "shell",
          "inline": ["sudo apt-get update && sudo apt-get install -y default-jdk"]
        }
      ]
    }
    EOF
    
  3. 通过运行 Packer 构建映像:

    ./packer build jenkins-agent.json

    构建完成后,磁盘映像的名称将以 jenkins-agent-[TIMESTAMP] 格式显示,其中 [TIMESTAMP] 是构建开始的纪元时间。

    ==> Builds finished. The artifacts of successful builds are:
    --> googlecompute: A disk image was created: jenkins-agent-1612997575
    

安装 Jenkins

在本部分中,您将使用 Cloud Marketplace 预配 Jenkins 实例。您可以自定义该实例,以使用您在上一部分中创建的代理映像。

  1. 转到 Jenkins 的 Cloud Marketplace 解决方案

  2. 点击启动

  3. 机器类型字段更改为 4 vCPUs 15 GB Memory, n1-standard-4

    Jenkins 部署的机器类型选择。

  4. 点击部署,待 Jenkins 实例完成预配。完成后,您将看到如下内容:

    Jenkins 已部署。

  5. 点击网址链接,在浏览器中打开 Jenkins 实例。

  6. 使用详细信息窗格中显示的管理员用户管理员密码登录 Jenkins。

    “详细信息”窗格,其中包含凭据和其他部署详情。

现在,您便可以使用您的 Jenkins 实例。

配置 Jenkins 插件

Jenkins 要求插件在 Compute Engine 中创建按需代理,并在 Cloud Storage 中存储工件。您需要安装并配置这些插件。

安装插件

  1. 在 Jenkins 界面中,选择 Manage Jenkins
  2. 点击 Manage Plugins
  3. 点击 Available 标签页。
  4. 使用 Filter 栏找到以下插件,然后勾选其旁边的复选框:

    • Compute Engine 插件
    • Cloud Storage 插件

    在下图中,Cloud Storage 插件处于选中状态:

    Cloud Storage 插件。

  5. 点击 Download now and install after restart

  6. 点击 Restart Jenkins when installation is complete and no jobs are running 复选框。Jenkins 将会重启并完成插件安装。

创建插件凭据

您需要为新插件创建 Google Credentials

  1. 再次登录 Jenkins,然后点击管理 Jenkins
  2. 点击 Credentials
  3. 点击存储下的 Jenkins
  4. 在界面的主窗格中,点击全局凭据(不受限制)
  5. 创建 Google 凭据:

    1. 点击 Add Credentials
    2. Kind 设置为 Google Service Account from private key
    3. Project Name 字段中,输入您的 Google Cloud 项目 ID。
    4. 点击 Choose file
    5. 选择之前从 Cloud Shell 下载的 jenkins-sa.json 文件。
    6. 点击 OK

      JSON 密钥凭据。

  6. 点击 Jenkins

配置 Compute Engine 插件

您可以使用用于预配代理实例的凭据来配置 Compute Engine 插件。

  1. 点击 Manage Jenkins
  2. 点击 Manage Nodes and Clouds
  3. 点击 Configure Clouds
  4. 点击 Add a new Cloud
  5. 点击 Compute Engine
  6. 设置以下设置,并将 [YOUR_PROJECT_ID] 替换为您的 Google Cloud 项目 ID:

    • Namegce
    • Project ID[YOUR_PROJECT_ID]
    • Instance Cap8
  7. Service Account Credentials 下拉列表中选择相应服务账号。该账号以 Google Cloud 项目 ID 的形式列出。

配置 Jenkins 实例

现在,Compute Engine 插件已配置完毕,接下来您可以针对自己偏好的各种构建配置来进行 Jenkins 实例的配置。

  1. Configure Clouds 页面上,针对 Instance Configurations 点击 Add
  2. 输入以下常规设置:

    • Nameubuntu-2004
    • DescriptionUbuntu agent
    • Labelsubuntu-2004
  3. Location 设置中,输入以下内容:

    • Region<us-central1
    • Zoneus-central1-f
  4. 点击 Advanced

  5. Machine ConfigurationMachine Type 部分,选择 n1-standard-1

  6. Networking 下,选择以下设置:

    • Network:保留默认设置。
    • Subnetwork:保留默认设置。
    • 选择 Attach External IP?
  7. Boot Disk 设置中,选择以下内容:

    • 对于 Image project,请选择您的 Google Cloud 项目。
    • 对于 Image name,请选择之前使用 Packer 构建的映像。
  8. 点击 Save 以保留配置更改。

    适用于 Jenkins 的 Compute Engine 配置。

创建 Jenkins 作业以测试配置

将 Jenkins 配置为在触发需要具有 ubuntu-2004 标签的代理的作业时自动启动实例。创建一个可以测试配置是否按预期工作的作业。

  1. 点击 Jenkins 界面中的 Create new job
  2. 输入 test 作为项名称。
  3. 点击 Freestyle project,然后点击OK
  4. 选中 Execute concurrent builds if necessaryRestrict where this project can run 复选框。
  5. Label Expression 字段中,输入 ubuntu-2004
  6. 构建部分中,点击添加构建步骤
  7. 点击执行 Shell
  8. 在命令框中,输入测试字符串:

    echo "Hello world!"

    在 Jenkins 的命令框中输入的“Hello World”。

  9. 点击 Save

  10. 点击 Build Now 以开始构建。

    立即构建。

将构建工件上传到 Cloud Storage

您可能需要存储构建工件,以供将来进行分析或测试。 您可以配置一项 Jenkins 作业,以生成工件并将其上传到 Cloud Storage。构建日志会上传到同一个存储分区。

  1. 在 Cloud Shell 中,为工件创建存储分区:

    export PROJECT=$(gcloud info --format='value(config.project)')
    gsutil mb gs://$PROJECT-jenkins-artifacts
  2. 在 Jenkins 界面的作业列表中,点击 test

  3. 点击 Configure

  4. Build 下,将 Command 文本字段设置为以下内容:

    env > build_environment.txt
  5. Post-build Actions 下,点击 Add post-build action

  6. 点击 Cloud Storage Plugin

  7. Storage Location 字段中,输入工件路径,并将 [YOUR_PROJECT_ID] 替换为您的 Google Cloud 项目 ID:

    gs://[YOUR_PROJECT_ID]-jenkins-artifacts/$JOB_NAME/$BUILD_NUMBER
  8. 点击 Add Operation

  9. 点击 Classic Upload

  10. File Pattern 字段中,输入 build_environment.txt

  11. Storage Location 字段中,输入存储路径,并将 [YOUR_PROJECT_ID] 替换为您的 Google Cloud 项目 ID:

    gs://[YOUR_PROJECT_ID]-jenkins-artifacts/$JOB_NAME/$BUILD_NUMBER

    Cloud Storage 插件的构建后操作。

  12. 点击 Save

  13. 点击 Build Now 以开始新的构建。此构建会在您之前预配的 Compute Engine 实例上运行。构建完成后,它会将工件文件 build_environment.txt 上传到已配置的 Cloud Storage 存储分区。

  14. 在 Cloud Shell 中,使用 gsutil 查看构建工件:

    export PROJECT=$(gcloud info --format='value(config.project)')
    gsutil cat gs://$PROJECT-jenkins-artifacts/test/2/build_environment.txt

配置对象生命周期管理

您通常会访问最近的构建工件。为了节省不常访问的对象的费用,请使用对象生命周期管理功能将工件从高性能存储类别转移到费用低廉、极为持久的存储类别。

  1. 在 Cloud Shell 中,创建生命周期配置文件,以便在 30 天后将所有对象转移到 Nearline 存储空间,并在 365 天后将 Nearline 对象转移到 Coldline 存储空间。

    cat > artifact-lifecycle.json <<EOF
    {
    "lifecycle": {
      "rule": [
      {
        "action": {
          "type": "SetStorageClass",
          "storageClass": "NEARLINE"
        },
        "condition": {
          "age": 30,
          "matchesStorageClass": ["MULTI_REGIONAL", "STANDARD", "DURABLE_REDUCED_AVAILABILITY"]
        }
      },
      {
        "action": {
          "type": "SetStorageClass",
          "storageClass": "COLDLINE"
        },
        "condition": {
          "age": 365,
          "matchesStorageClass": ["NEARLINE"]
        }
      }
    ]
    }
    }
    EOF
  2. 将配置文件上传到工件存储分区:

    export PROJECT=$(gcloud info --format='value(config.project)')
    gsutil lifecycle set artifact-lifecycle.json gs://$PROJECT-jenkins-artifacts

清除数据

  1. 删除仍在运行的所有 Jenkins 代理:

    gcloud compute instances list --filter=metadata.jclouds-group=ubuntu-2004 --uri | xargs gcloud compute instances delete
  2. 使用 Cloud Deployment Manager 删除 Jenkins 实例:

    gcloud deployment-manager deployments delete jenkins-1
  3. 删除 Cloud Storage 存储分区:

    export PROJECT=$(gcloud info --format='value(config.project)')
    gsutil -m rm -r gs://$PROJECT-jenkins-artifacts
  4. 删除服务账号:

    export SA_EMAIL=$(gcloud iam service-accounts list --filter="displayName:jenkins" --format='value(email)')
    gcloud iam service-accounts delete $SA_EMAIL

后续步骤