使用 Azure Pipelines 和 Google Kubernetes Engine 创建 CI/CD 流水线

Last reviewed 2022-11-29 UTC

本教程介绍如何使用 Azure PipelinesGoogle Kubernetes Engine (GKE)、Google Container Registry 为 ASP.NET MVC Web 应用创建持续集成/持续部署 (CI/CD) 流水线。在本教程中,您可以在两个示例应用之间进行选择:

  • 使用 .NET 6.0 并在 Linux 上运行的 ASP.NET Core Web 应用
  • 使用.NET Framework 4 并在 Windows 上运行的 ASP .NET MVC Web 应用

CI/CD 流水线使用两个独立的 GKE 集群,一个用于开发,一个用于生产,如下图所示。

CI/CD 流水线的概念图,展示开发者和最终用户如何与应用交互

在流水线的开端,开发者将提交对示例代码库的更改。此操作会触发流水线创建一个发布并将其部署到开发集群。然后,发布管理员可以提升该发布,以便将其部署到生产集群中。

本教程适用于开发者和 DevOps 工程师。本教程假定您具备 Microsoft .NET、Azure Pipelines、GKE 的基本知识。本教程还要求您对 Azure DevOps 帐号具有管理访问权限。

目标

  • 将 Google Container Registry 连接到 Azure Pipelines 以发布 Docker 映像。
  • 准备 .NET 示例应用以部署到 GKE 中。
  • 无需使用旧版身份验证即可安全地针对 GKE 进行身份验证。
  • 使用 Azure Pipelines 发布管理来编排 GKE 部署。

费用

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

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

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

查看 Azure DevOps 价格页面,了解使用 Azure DevOps 时可能需要支付的所有费用。

准备工作

通常建议使用不同的项目来处理开发工作负载与生产工作负载,这样就能分别授予 Identity and Access Management (IAM) 角色与权限。为简单起见,本教程使用一个项目来处理两个 GKE 群集,一个集群用于开发环境,另一个用于生产环境。

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

    转到“项目选择器”

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

  3. 确保您拥有 Azure DevOps 帐号并具有管理员访问权限。 如果您还没有 Azure DevOps 帐号,可以在 Azure DevOps 首页上注册一个。

创建 Azure DevOps 项目

您可以使用 Azure DevOps 来管理源代码、运行构建和测试以及将部署编排到 GKE。首先,在 Azure DevOps 帐号中创建一个项目。

  1. 转到 Azure DevOps 首页 (https://dev.azure.com/YOUR_AZURE_DEVOPS_ACCOUNT_NAME)。
  2. 点击新建项目
  3. 输入项目名称,例如 CloudDemo
  4. 可见性设置为私有,然后点击创建
  5. 创建项目后,点击左侧菜单中的存储库
  6. 点击导入,从 GitHub 创建 dotnet-docs-samples 代码库分支,然后设置以下值:
    • 代码库类型Git
    • 克隆网址https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git
  7. 点击导入

    导入流程完成后,您将看到 dotnet-docs-samples 代码库的源代码。

将 Azure Pipelines 连接到 Google Container Registry

您必须先将 Azure Pipelines 连接到 Container Registry,然后才能为 CloudDemo 应用设置持续集成。此连接允许 Azure Pipelines 将容器映像发布到 Container Registry。

设置一个服务帐号用于发布映像

在您的项目中创建 Google Cloud 服务帐号

  1. 打开 Google Cloud 控制台。

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

    激活 Cloud Shell

  3. 为了节省输入项目 ID 和 Compute Engine 区域选项的时间,请运行以下命令以设置默认配置值:

    gcloud config set project PROJECT_ID
    gcloud config set compute/zone us-central1-a
    

    PROJECT_ID 替换为项目的 ID。

  4. 在项目中启用 Container Registry API:

    gcloud services enable containerregistry.googleapis.com
    
  5. 创建一个服务帐号,供 Azure Pipelines 用于发布 Docker 映像:

    gcloud iam service-accounts create azure-pipelines-publisher \
        --display-name="Azure Pipelines Publisher"
    
  6. 向服务帐号授予 Storage Admin IAM 角色 (roles/storage.admin),以允许 Azure Pipelines 推送到 Container Registry:

    AZURE_PIPELINES_PUBLISHER=azure-pipelines-publisher@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member serviceAccount:$AZURE_PIPELINES_PUBLISHER \
        --role roles/storage.admin
    
  7. 生成服务帐号密钥:

    gcloud iam service-accounts keys create azure-pipelines-publisher.json \
        --iam-account $AZURE_PIPELINES_PUBLISHER
    
    tr -d '\n' < azure-pipelines-publisher.json > azure-pipelines-publisher-oneline.json
    
  8. 查看服务帐号密钥文件的内容:

    echo $(<azure-pipelines-publisher-oneline.json)
    

    执行以下步骤之一时,需要用到服务帐号密钥。

为 Google Container Registry 创建服务连接

在 Azure Pipelines 中,为 Container Registry 创建新的服务连接:

  1. 在 Azure DevOps 菜单中,选择项目设置,然后选择管道 > 服务连接
  2. 点击 Create service connection
  3. 从列表中选择 Docker 注册表,然后点击下一步
  4. 在对话框中,为以下字段输入值:
    • Registry typeOthers
    • Docker Registryhttps://gcr.io/PROJECT_ID,注意将 PROJECT_ID 替换为您的项目名称(例如 https://gcr.io/azure-pipelines-test-project-12345)。
    • Docker ID_json_key
    • 密码:粘贴 azure-pipelines-publisher-oneline.json 的内容。
    • 服务连接名称gcr-tutorial
  5. 点击保存以创建连接。

持续构建

您现可使用 Azure Pipelines 来设置持续集成。对于推送到 Git 代码库的每个提交项,Azure Pipelines 都会构建代码并将构建工件打包到 Docker 容器中。随后,容器会被发布到 Container Registry。

该代码库已包含以下 Dockerfile:

.NET/Linux

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

FROM mcr.microsoft.com/dotnet/aspnet:6.0
EXPOSE 8080

#------------------------------------------------------------------------------
# Copy publishing artifacts.
#------------------------------------------------------------------------------

WORKDIR /app
COPY CloudDemo.MvcCore/bin/Release/net6.0/publish/ /app/

ENV ASPNETCORE_URLS=http://0.0.0.0:8080

#------------------------------------------------------------------------------
# Run application in Kestrel.
#------------------------------------------------------------------------------

ENTRYPOINT ["dotnet", "CloudDemo.MvcCore.dll"]

.NET Framework/Windows

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
EXPOSE 80
SHELL ["powershell", "-command"]

#------------------------------------------------------------------------------
# Add LogMonitor so that IIS and Windows logs are emitted to STDOUT and can be
# picked up by Docker/Kubernetes.
#
# See https://github.com/microsoft/windows-container-tools/wiki/Authoring-a-Config-File
# for details.
#------------------------------------------------------------------------------

ADD https://github.com/microsoft/windows-container-tools/releases/download/v1.1/LogMonitor.exe LogMonitor/
ADD LogMonitorConfig.json LogMonitor/

#------------------------------------------------------------------------------
# Copy publishing artifacts to webroot.
#------------------------------------------------------------------------------

ADD CloudDemo.Mvc/bin/Release/PublishOutput/ c:/inetpub/wwwroot/

#------------------------------------------------------------------------------
# Configure IIS using the helper functions from deployment.ps1.
#------------------------------------------------------------------------------

ADD deployment.ps1 /
RUN . /deployment.ps1; \
	Install-Iis; \
	Register-WebApplication -AppName "CloudDemo"; \
	Remove-Item /deployment.ps1

#------------------------------------------------------------------------------
# Run IIS, wrapped by LogMonitor.
#------------------------------------------------------------------------------

ENTRYPOINT ["C:\\LogMonitor\\LogMonitor.exe", "C:\\ServiceMonitor.exe", "w3svc"]

您现在可以创建使用 YAML 语法的新流水线:

  1. 使用 Visual Studio 或命令行 git 客户端克隆新的 Git 代码库并查看 main 分支。
  2. 在代码库的根目录中,创建一个名为 azure-pipelines.yml 的文件。
  3. 将以下代码复制到该文件中:

    .NET/Linux

    resources:
    - repo: self
      fetchDepth: 1
    pool:
      vmImage: ubuntu-20.04
    trigger:
    - main
    variables:
      TargetFramework: 'net6.0'
      BuildConfiguration: 'Release'
      DockerImageName: 'PROJECT_ID/clouddemo'
    steps:
    - task: DotNetCoreCLI@2
      displayName: Publish
      inputs:
        projects: 'applications/clouddemo/netcore/CloudDemo.MvcCore.sln'
        publishWebProjects: false
        command: publish
        arguments: '--configuration $(BuildConfiguration) --framework=$(TargetFramework)'
        zipAfterPublish: false
        modifyOutputPath: false
    - task: CmdLine@1
      displayName: 'Lock image version in deployment.yaml'
      inputs:
        filename: /bin/bash
        arguments: '-c "awk ''{gsub(\"CLOUDDEMO_IMAGE\", \"gcr.io/$(DockerImageName):$(Build.BuildId)\", $0); print}'' applications/clouddemo/netcore/deployment.yaml > $(build.artifactstagingdirectory)/deployment.yaml"'
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact'
      inputs:
        PathtoPublish: '$(build.artifactstagingdirectory)'
    - task: Docker@2
      displayName: 'Login to Container Registry'
      inputs:
        command: login
        containerRegistry: 'gcr-tutorial'
    - task: Docker@2
      displayName: 'Build and push image'
      inputs:
        Dockerfile: 'applications/clouddemo/netcore/Dockerfile'
        command: buildAndPush
        repository: '$(DockerImageName)'
    

    .NET Framework/Windows

    resources:
    - repo: self
      fetchDepth: 1
    pool:
      vmImage: windows-2019     # Matches WINDOWS_LTSC in GKE
      demands:
      - msbuild
      - visualstudio
    trigger:
    - master
    variables:
      Solution: 'applications/clouddemo/net4/CloudDemo.Mvc.sln'
      BuildPlatform: 'Any CPU'
      BuildConfiguration: 'Release'
      DockerImageName: 'PROJECT_ID/clouddemo'
    steps:
    - task: NuGetCommand@2
      displayName: 'NuGet restore'
      inputs:
        restoreSolution: '$(Solution)'
    - task: VSBuild@1
      displayName: 'Build solution'
      inputs:
        solution: '$(Solution)'
        msbuildArgs: '/p:DeployOnBuild=true /p:PublishProfile=FolderProfile'
        platform: '$(BuildPlatform)'
        configuration: '$(BuildConfiguration)'
    - task: PowerShell@2
      displayName: 'Lock image version in deployment.yaml'
      inputs:
        targetType: 'inline'
        script: '(Get-Content applications\clouddemo\net4\deployment.yaml) -replace "CLOUDDEMO_IMAGE","gcr.io/$(DockerImageName):$(Build.BuildId)" | Out-File -Encoding ASCII $(build.artifactstagingdirectory)\deployment.yaml'
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact'
      inputs:
        PathtoPublish: '$(build.artifactstagingdirectory)'
    - task: Docker@2
      displayName: 'Login to Container Registry'
      inputs:
        command: login
        containerRegistry: 'gcr-tutorial'
    - task: Docker@2
      displayName: 'Build and push image'
      inputs:
        Dockerfile: 'applications/clouddemo/net4/Dockerfile'
        command: buildAndPush
        repository: '$(DockerImageName)'
    
    

    PROJECT_ID 替换为您的项目名称,然后保存该文件。

  4. 提交您的更改并将其推送到 Azure Pipelines。

    Visual Studio

    1. 打开团队资源管理器,然后点击主页图标。
    2. 点击更改
    3. 输入类似 Add pipeline definition 的提交消息。
    4. 点击全部提交并推送

    命令行

    1. 暂存所有已修改的文件:

      git add -A
      
    2. 将更改提交到本地代码库:

      git commit -m "Add pipeline definition"
      
    3. 将更改推送到 Azure DevOps:

      git push
      
  5. 在 Azure DevOps 菜单中,选择流水线,然后点击 创建流水线

  6. 选择 Azure Repos Git

  7. 选择您的代码库。

  8. 查看流水线 YAML页面上,点击运行

    系统会触发新的构建。构建流程可能需要大约六分钟时间才能完成。

  9. 如需验证映像是否已发布到 Container Registry,请在 Google Cloud 控制台中切换到您的项目,选择 Container Registry > 映像,然后点击 clouddemo

    系统会显示一个映像以及此映像的标记。该标记与 Azure Pipelines 中运行的构建的数字 ID 相对应。

持续部署

现在,Azure Pipelines 会自动构建代码并为每个提交项发布 Docker 映像,因此您可以专注于部署工作。

与其他一些持续集成系统不同,Azure Pipelines 对构建和部署进行了区分,并为所有与部署相关的任务提供了一组标记为“版本管理”的专用工具。

Azure Pipelines 版本管理围绕以下概念构建:

  • “版本”是指构成应用特定版本的一组工件,通常是构建流程的结果。
  • “部署”是指提取一个发布并将其部署到特定环境的流程
  • 一次部署会执行一组“任务”,这些任务可分组为多个“作业”
  • 使用“阶段”可以将流水线分段,并可将部署编排到多个环境,例如开发和测试环境

CloudDemo 构建流程产生的主要工件是 Docker 映像。但是,由于 Docker 映像已发布到 Container Registry,不在 Azure Pipelines 的处理范围内。 因此,映像不适合作为版本的定义。

若要部署到 Kubernetes,您还需要一个清单,它类似于材料清单。此清单不仅定义了 Kubernetes 应该创建和管理的资源,还指定了要使用的 Docker 映像的确切版本。Kubernetes 清单非常适合用作定义 Azure Pipelines 版本管理中的版本的工件。

配置 Kubernetes 部署

如需在 Kubernetes 中运行 CloudDemo,您需要以下资源:

  • 一个 Deployment,它定义运行由构建生成的 Docker 映像的单个 pod。
  • 一个让负载均衡器能够访问该 pod 的 NodePort 服务
  • 一个 Ingress,用于通过 Cloud HTTP(S) 负载均衡器将应用公开到公共互联网。

代码库已包含以下 Kubernetes 清单,用于定义这些资源:

.NET/Linux

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

apiVersion: v1
kind: Service
metadata:
  name: clouddemo-netcore
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: clouddemo-netcore
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: clouddemo-netcore
spec:
  defaultBackend:
    service:
      name: clouddemo-netcore
      port:
        number: 80

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clouddemo-netcore
spec:
  replicas: 2
  selector:
    matchLabels:
      app: clouddemo-netcore
  template:
    metadata:
      labels:
        app: clouddemo-netcore
    spec:
      containers:
      - name: clouddemo-netcore
        image: CLOUDDEMO_IMAGE
        ports:
          - containerPort: 8080
        livenessProbe:      # Used by deployment controller
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:     # Used by Ingress/GCLB
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 5
        resources:
          limits:
            memory: 1024Mi
          requests:
            memory: 256Mi

.NET Framework/Windows

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

apiVersion: v1
kind: Service
metadata:
  name: clouddemo-net4
  annotations:
    cloud.google.com/neg: '{"ingress": false}' # Disable NEG

spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    app: clouddemo-net4
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: clouddemo-net4
spec:
  defaultBackend:
    service:
      name: clouddemo-net4
      port:
        number: 80

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clouddemo-net4
spec:
  replicas: 2
  selector:
    matchLabels:
      app: clouddemo-net4
  template:
    metadata:
      labels:
        app: clouddemo-net4
    spec:
      nodeSelector:
        kubernetes.io/os: windows
      containers:
      - name: clouddemo-net4
        image: CLOUDDEMO_IMAGE
        ports:
          - containerPort: 80
        livenessProbe:      # Used by deployment controller
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 120
          periodSeconds: 5
        readinessProbe:     # Used by Ingress/GCLB
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
        resources:
          limits:
            memory: 1024Mi
          requests:
            memory: 256Mi

设置开发和生产环境

在返回 Azure Pipelines 版本管理之前,您需要创建 GKE 集群。

创建 GKE 集群

  1. 返回到 Cloud Shell 实例。

  2. 为您的项目启用 GKE API:

    gcloud services enable container.googleapis.com
  3. 使用以下命令创建开发集群。请注意,这可能需要几分钟才能完成:

    .NET/Linux

    gcloud container clusters create azure-pipelines-cicd-dev --enable-ip-alias
    

    .NET Framework/Windows

    gcloud container clusters create azure-pipelines-cicd-dev --enable-ip-alias
    
    gcloud container node-pools create azure-pipelines-cicd-dev-win \
        --cluster=azure-pipelines-cicd-dev \
        --image-type=WINDOWS_LTSC \
        --no-enable-autoupgrade \
        --machine-type=n1-standard-2
    
  4. 使用以下命令创建生产集群。请注意,这可能需要几分钟才能完成:

    .NET/Linux

    gcloud container clusters create azure-pipelines-cicd-prod --enable-ip-alias
    

    .NET Framework/Windows

    gcloud container clusters create azure-pipelines-cicd-prod --enable-ip-alias
    
    gcloud container node-pools create azure-pipelines-cicd-prod-win \
        --cluster=azure-pipelines-cicd-prod \
        --image-type=WINDOWS_LTSC \
        --no-enable-autoupgrade \
        --machine-type=n1-standard-2
    

将 Azure Pipelines 连接到开发集群

就像您可以使用 Azure Pipelines 连接到 Container Registry 之类的外部 Docker 注册表一样,Azure Pipelines 也支持集成外部 Kubernetes 集群。

您可以使用 Google Cloud 服务帐号向 Container Registry 进行身份验证,但 Azure Pipelines 不支持使用 Google Cloud 服务帐号进行 GKE 身份验证。必须改用 Kubernetes 服务帐号

如需将 Azure Pipelines 连接到开发集群,必须先创建一个 Kubernetes 服务帐号。

  1. 在 Cloud Shell 中,连接到开发集群:

    gcloud container clusters get-credentials azure-pipelines-cicd-dev
  2. 为 Azure Pipelines 创建 Kubernetes 服务帐号:

    kubectl create serviceaccount azure-pipelines-deploy
  3. 为 Azure Pipelines 创建包含令牌凭据的 Kubernetes Secret:

    kubectl create secret generic azure-pipelines-deploy-token --type=kubernetes.io/service-account-token --dry-run -o yaml \
      | kubectl annotate --local -o yaml -f - kubernetes.io/service-account.name=azure-pipelines-deploy \
      | kubectl apply -f -
    
  4. 通过创建集群角色绑定将 cluster-admin 角色分配给服务帐号:

    kubectl create clusterrolebinding azure-pipelines-deploy --clusterrole=cluster-admin --serviceaccount=default:azure-pipelines-deploy
  5. 确定集群的 IP 地址:

    gcloud container clusters describe azure-pipelines-cicd-dev --format=value\(endpoint\)
    

    您稍后将用到此地址。

  6. 在 Azure DevOps 菜单中,选择 Project settings,然后选择 Pipelines > Service connections

  7. 点击 New service connection

  8. 选择 Kubernetes,然后点击 Next

  9. 进行以下设置。

    • Authentication methodService account
    • Server URLhttps://PRIMARY_IP。 将 PRIMARY_IP 替换为您之前确定的 IP 地址。
    • Secret:您之前创建的 Kubernetes Secret。如需获取 Secret,请运行以下命令,复制 Secret,然后将 Secret 复制到 Azure 页面中。
      kubectl get secret azure-pipelines-deploy-token -o yaml
    • Service connection nameazure-pipelines-cicd-dev
  10. 点击保存

将 Azure Pipelines 连接到生产集群

如需将 Azure Pipelines 连接到生产集群,您可以采用相同的方法。

  1. 在 Cloud Shell 中,连接到生产集群:

    gcloud container clusters get-credentials azure-pipelines-cicd-prod
  2. 为 Azure Pipelines 创建 Kubernetes 服务帐号:

    kubectl create serviceaccount azure-pipelines-deploy
  3. 通过创建集群角色绑定将 cluster-admin 角色分配给服务帐号:

    kubectl create clusterrolebinding azure-pipelines-deploy --clusterrole=cluster-admin --serviceaccount=default:azure-pipelines-deploy
  4. 确定集群的 IP 地址:

    gcloud container clusters describe azure-pipelines-cicd-prod --format=value\(endpoint\)
    

    您稍后将用到此地址。

  5. 在 Azure DevOps 菜单中,选择 Project settings,然后选择 Pipelines > Service connections

  6. 点击 New service connection

  7. 选择 Kubernetes,然后点击 Next

  8. 进行以下设置:

    • Authentication methodService account
    • Server URLhttps://PRIMARY_IP。 将 PRIMARY_IP 替换为您之前确定的 IP 地址。
    • Secret:在 Cloud Shell 中运行以下命令并复制输出结果:
      kubectl get secret $(kubectl get serviceaccounts azure-pipelines-deploy -o custom-columns=":secrets[0].name") -o yaml
    • Service connection nameazure-pipelines-cicd-prod
  9. 点击保存

配置版本流水线

设置 GKE 基础架构后,返回 Azure Pipelines 设置自动部署,其中包括以下内容:

  • 部署到开发环境。
  • 在开始部署到生产环境之前请求手动审批。
  • 部署到生产环境。

创建版本定义

首先,创建一个新的版本定义。

  1. 在 Azure DevOps 菜单中,选择 Pipelines > Releases
  2. 点击 New pipeline
  3. 从模板列表中,选择 Empty job
  4. 当系统提示您输入阶段名称时,请输入 Development
  5. 在屏幕顶部,将版本命名为 CloudDemo-KubernetesEngine
  6. 在流水线图中,点击工件旁边的添加
  7. 选择 Build 并添加以下设置:

    • Source typeBuild
    • Source (build pipeline):选择构建定义(应该只有一个选项)
    • Default versionLatest
    • Source Aliasmanifest
  8. 点击添加

  9. 项目框中,点击持续部署触发器(闪电图标)来添加部署触发器。

  10. 持续部署触发器下,将开关设置为已启用

  11. 点击保存

  12. 如果需要,请输入注释,然后点击确定来进行确认。

    该流水线会显示如下内容。

    Azure Pipelines 中更新流水线的屏幕截图

部署到开发集群

创建发布定义后,您现在可以配置针对 GKE 开发集群的部署。

  1. 在菜单中,切换到 Tasks 标签页。
  2. 点击 Agent job 并配置以下设置:

    • Agent poolAzure Pipelines
    • Agent specificationubuntu-18.04
  3. Agent job 旁边,点击 Add a task to agent job 以向阶段添加步骤。

  4. 选择 Deploy to Kubernetes 任务,然后点击 Add

  5. 点击新添加的任务并配置以下设置:

    • Display nameDeploy
    • Actiondeploy
    • Kubernetes service connectionazure-pipelines-cicd-dev
    • Namespacedefault
    • StrategyNone
    • Manifestsmanifest/drop/deployment.yaml
  6. 点击保存

  7. 如果需要,请输入注释,然后点击确定来进行确认。

部署到生产集群

最后,配置针对 GKE 生产集群的部署。

  1. 在菜单中,切换到 Pipeline 标签。
  2. 在“阶段”框中,选择添加 > 新阶段
  3. 从模板列表中,选择 Empty job
  4. 当系统提示您输入阶段名称时,请输入 Production
  5. 点击新创建阶段的闪电形图标。
  6. 进行以下设置:

    • 选择触发器After stage
    • 阶段Dev
    • Pre-deployment approvals:(启用)
    • Approvers:选择您自己的用户名。

    流水线现在应如下所示:

    Azure Pipelines 中更新流水线的屏幕截图

  7. 切换到 Tasks 标签页。

  8. 将鼠标悬停在 Tasks 标签页上,然后选择 Tasks > Production

  9. 点击 Agent job 并配置以下设置:

    • Agent poolAzure Pipelines
    • Agent specificationubuntu-18.04
  10. 点击 Add a task to agent job 以向阶段添加步骤。

  11. 选择 Deploy to Kubernetes 任务,然后点击 Add

  12. 点击新添加的任务并配置以下设置:

    • Display nameDeploy
    • Actiondeploy
    • Kubernetes service connectionazure-pipelines-cicd-prod
    • Namespacedefault
    • StrategyNone
    • Manifestsmanifest/drop/deployment.yaml
  13. 点击保存

  14. 如果需要,请输入注释,然后点击确定来进行确认。

运行流水线

现在您已经配置了整个流水线,接下来可通过更改源代码来测试该流水线:

  1. 在本地计算机上,从您之前克隆的 Git 代码库中打开 Index.cshtml 文件:

    .NET/Linux

    文件位于 applications\clouddemo\netcore\CloudDemo.MvcCore\Views\Home\

    .NET Framework/Windows

    文件位于 applications\clouddemo\net4\CloudDemo.Mvc\Views\Home\

  2. 在第 26 行中,将 ViewBag.Title 的值从 Home Page 更改为 This app runs on GKE

  3. 提交您的更改并将其推送到 Azure Pipelines。

    Visual Studio

    1. 打开团队资源管理器,然后点击主页图标。
    2. 点击更改
    3. 输入类似 Change site title 的提交消息。
    4. 点击全部提交并推送

    命令行

    1. 暂存所有已修改的文件:

      git add -A
      
    2. 将更改提交到本地代码库:

      git commit -m "Change site title"
      
    3. 将更改推送到 Azure Pipelines:

      git push
      
  4. 在 Azure DevOps 菜单中,选择管道。系统会触发构建。

  5. 构建完成后,选择管道 > 发布。系统会启动发布流程。

  6. 点击 Release-1 打开详细信息页面,等待 Development 阶段的状态切换为 Succeeded

  7. 在 Google Cloud 控制台中,选择 Kubernetes Engine > Service 和 Ingress > Ingress

  8. 找到 azure-pipelines-cicd-dev 集群的 Ingress 服务,并等待其状态切换为正常。这可能需要几分钟。

  9. 打开同一行的前端列中的链接。您可能会先看到一个错误,因为负载均衡器在几分钟后才能使用。待其准备就绪后,观察 CloudDemo 是否已部署并正在使用自定义标题。

  10. 在 Azure Pipelines 中,点击 Prod 阶段下方的 Approve 按钮,以将部署提升到生产环境。

    如果您没有看到该按钮,则可能需要先批准或拒绝以前的版本。

  11. 必要时,请输入注释,然后点击 Approve 进行确认。

  12. 等待 Prod 环境的状态切换到 Succeeded。您可能需要在浏览器中手动刷新页面才能看到此信息。

  13. 在 Google Cloud 控制台中,刷新 Service 和 Ingress 页面。

  14. 找到 azure-pipelines-cicd-prod 集群的 Ingress 服务,并等待其状态切换为正常。这可能需要几分钟。

  15. 打开同一行的前端列中的链接。同样,您可能会先看到一个错误,因为负载均衡器在几分钟后才能使用。待其准备就绪后,您会再次看到显示自定义标题的 CloudDemo 应用,而这次在生产集群中运行。

清理

学完本教程后,请删除您创建的实体,避免日后再为这些实体付费。

删除 Azure Pipelines 项目

如需删除 Azure Pipelines 项目,请参阅 Azure DevOps Services 文档。删除 Azure Pipelines 项目会导致所有源代码更改丢失。

删除 Google Cloud 开发和项目

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

    转到“管理资源”

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

后续步骤