将工作负载从 Azure DevOps 管道部署到私有的 Amazon EKS - AWS 规范指引

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

将工作负载从 Azure DevOps 管道部署到私有的 Amazon EKS

Mahendra Revanasiddappa,Amazon Web Services

Summary

此模式演示了如何实现从 Azure DevOps 管道到私有亚马逊 Elastic Kubernetes Service (Amazon EKS) 集群的持续集成和持续交付 (CI/CD)。此模式解决了组织在通过过渡至 Amazon EKS 集群的私有 API 服务器端点来增强其安全态势时所面临的一项关键挑战。

公有端点会直接向互联网公开 Kubernetes API 服务器,从而可能会扩大恶意行为者的攻击面。切换到私有端点后,仅限在客户的虚拟私有云(VPC)内访问集群的控制面板。

尽管将 Amazon EKS 集群过渡到私有 API 终端节点可以显著增强安全性,但它会给 Azure DevOps 等外部 CI/CD 平台带来连接挑战。只能从集群的 VPC 或对等网络中访问私有端点。因此,在 AWS 私有网络之外运行的标准微软托管的 Azure DevOps 代理无法直接访问 Kubernetes API 服务器。这就破坏了依赖于在这些代理上运行的工具(例如 kubectl 或 Helm)的典型部署工作流,因为它们无法与集群建立连接。

为了克服这个问题,这种模式展示了一种有效的方法,即在私有 Amazon EKS 集群中使用自托管 Azure DevOps 代理。该解决方案提供了卓越的成本优化、运营效率和可扩展性,同时保留了安全要求。这种方法特别有利于寻求在不影响性能或安全性的前提下简化多云 DevOps 流程的企业。

先决条件和限制

先决条件

  • 活跃 AWS 账户的.

  • AWS Command Line Interface (AWS CLI) 版本 2.13.17 或更高版本,已安装。

  • kubectl 版本 1.25.1 或更高版本,已安装

  • 已创建私有 Amazon EKS 集群版本 1.24 或更高版本,具有创建命名空间、密钥和部署的权限

  • Amazon EKS 集群中的工作节点具有互联网的出站连接,因此在其上运行的 Azure DevOps 代理可以连接到 Azure DevOps 代理池。

  • GitHub 账户已创建

  • 创建了一个有权配置服务连接的 Azure DevOps 项目,这些连接是 Azure Pipelines 与外部或远程服务之间经过身份验证的连接。

  • 为上一点中描述的 Azure DevOps 项目安装的 1.15 或更高 AWS Toolkit for Azure DevOps 版本。有关安装说明,请参阅 Visual Studio Marketplace 中的 AWS Toolkit for Azure DevOps

限制

架构

此模式会创建以下内容:

  • 亚马逊 ECR 存储库 ——亚马逊弹性容器注册表 (Amazon ECR) Registry 存储库将 Docker 映像与 Azure DevOps 代理和部署的示例应用程序一起存储。

  • Azure DevOps 代理池-Azure DevOps 自托管代理池注册在私有 Amazon EKS 集群上运行的代理。

  • IAM 角色-Azure 服务连接的 AWS Identity and Access Management (IAM) 角色,用于为在私有 Amazon EKS 集群上运行的代理提供所需的访问权限。

  • Azure DevOps 服务连接-Azure DevOps 账户中的服务连接,用于使用 IAM 角色,为管道作业提供访问所需的访问权限 AWS 服务。

下图显示了在私有 Amazon EKS 集群上部署自托管 Azure DevOps 代理并在同一集群上部署示例应用程序的架构。

在私有 Amazon EKS 集群上部署自托管的 Azure DevOps 代理和示例应用程序。

下图显示了如下工作流:

  1. 将自托管的 Azure DevOps 代理部署为在 Amazon EKS 集群中的部署。

  2. Azure DevOps 代理使用个人访问令牌 (PAT) 进行身份验证,连接到 Azure DevOps 帐户上的代理池。

  3. Azure Pipelines 使用 GitHub 存储库中的代码配置要部署的管道。

  4. 该管道可在代理池中的代理上运行,其中该代理池可管道配置中进行配置。Azure DevOps 代理通过不断轮询到 Azure DevOps 帐户来获取管道的作业信息。

  5. Azure DevOps 代理在管道作业中构建 Docker 映像,并将该映像推送到 Amazon ECR 存储库。

  6. Azure DevOps 代理将示例应用程序部署到名为的命名webapp空间中的私有 Amazon EKS 集群上。

工具

工具

其他工具

  • Docker 是一组平台即服务(PaaS)产品,它们使用操作系统级别的虚拟化技术在容器中交付软件。

  • kubectl:针对 Kubernetes 集群运行命令的命令行界面。

代码存储库

最佳实践

操作说明

Task说明所需技能

查找 Azure DevOps 组织指南。

登录你的 Azure DevOps 帐户,然后使用以下 URL 查找组织 GUID:https://dev.azure.com/{DevOps_Org_ID}/_apis/projectCollections?api-version=6.0在网址中,{DevOps_org_ID}替换为你的 Azure DevOps 组织 ID。

AWS DevOps

在 AWS 账户中配置 IdP。

要在中为 Azure 服务连接配置身份提供者 (IdP),请使用以下步骤: AWS 账户

  1. 登录并打开 IAM 控制台,网址为https://console.aws.amazon.com/iam/。 AWS 管理控制台

  2. 在左侧窗格中,选择身份提供者

  3. 选择 Add Provider(添加提供程序)

  4. 选择 OpenID Connect 作为提供者类型

  5. 提供者网址中,输入 Azure DevOps 发行者网址。Azure DevOps 的每个租户都有唯一的OrganizationGUID,通常使用以下格式:https://vstoken.dev.azure.com/{OrganizationGUID}{OrganizationGUID}替换为你的 Azure DevOps 组织 ID。

  6. 对于受众,请输入 api: //Azure ADToken 交易所。这是 Azure 的固定值 DevOps。

  7. 选择 Add Provider(添加提供程序)

  8. 记下新创建的提供商的 ARN,以便您在下一个任务中使用。

有关更多详细信息,请参阅如何 DevOps 使用 OpenID Connect AWS 从 Azure 联合到

AWS DevOps

在 AWS 账户中创建 IAM 策略。

要创建 IAM 策略以向 Azure DevOps 管道使用的 IAM 角色提供所需权限,请使用以下步骤:

  1. 在 IAM 控制台的左侧窗格中,选择策略

  2. 选择创建策略

  3. 对于指定权限,在策略编辑器中,选择 JSON。将默认 JSON 策略替换为以下 JSON:

    { "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": [ "ecr:*", "eks:DescribeCluster", "eks:ListClusters" ], "Resource": "*" } ] }
  4. 选择下一步

  5. 对于策略名称,输入 IAM 策略的名称。此模式使用名称 ADO-policy

  6. 选择创建策略

AWS DevOps

在 AWS 账户中创建 IAM 角色。

要在中为 Azure 服务连接配置 IAM 角色,请使用以下步骤: AWS 账户

  1. 在 IAM 控制台的左侧窗格中,选择角色

  2. 选择创建角色

  3. 对于可信实体类型,选择 Web 身份

  4. 从下拉列表中选择正确的 IdP。IdP 名称以 vstoken.dev.azure.com/{OrganizationGUID} 开头。

  5. 在 “受众” 下拉列表中,选择 api: //Azure ADToken Exchange

  6. 要将此角色限制为仅一个服务连接,请添加一个条件。在条件下,选择添加条件,而对于密钥,选择 vstoken.dev.azure.com/{OrganizationGUID}:sub。在 “状况” 中,选择StringEquals。对于,使用以下格式:sc://{OrganizationName}/{ProjectName}/{ServiceConnectionName}。对于 ServiceConnectionName,使用 aws-sc。您将在下一个任务中创建此服务连接。

  7. 选择下一步

  8. 对于添加权限,选择 ADO-policy,这是您在上一个任务中创建的策略。

  9. 选择下一步,对于角色名称,输入 ado-role。对于选择可信实体,使用以下信任策略:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::{account_id}:oidc-provider/vstoken.dev.azure.com/{OrganizationGUID}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "vstoken.dev.azure.com/{OrganizationGUID}:aud": "api://AzureADTokenExchange", "vstoken.dev.azure.com/{OrganizationGUID}:sub": "sc://{OrganizationName}/{ProjectName}/{ServiceConnectionName}" } } } ] }

在策略中,针对以下占位符提供您的信息:

  • {account_id}- AWS 账户 身份证

  • {OrganizationGUID}-Azure DevOps 组织指南

  • {OrganizationName}-Azure DevOps 组织名称

  • {ProjectName}-Azure DevOps 项目名称

  • {ServiceConnectionName}-Azure DevOps 服务连接名称。使用 aws-sc。您将在下一个任务中创建此服务连接。

AWS DevOps

在 Azure DevOps 帐户中创建服务连接。

要配置 Azure 服务连接,请使用以下步骤:

  1. 在你的 Azure DevOps 项目中,选择项目设置服务连接

  2. 选择新建服务连接,选择服务连接的类型为 aws,然后选择下一步

  3. 对于要代入的角色,请输入 IAM 角色 ado-role。在上一个任务在 AWS 账户中创建 IAM 角色中,您已创建了ado-role

  4. 选中使用 OIDC复选框。

  5. 对于服务连接名称,在任务属性中输入 aws-sc

  6. 选择保存

有关更多详细信息,请参阅 Microsoft 文档中的创建服务连接

AWS DevOps

将 IAM 角色添加到 Amazon EKS 配置文件。

IAM 角色必须具有在 Amazon EKS 集群上执行所需操作的必要权限。由于 IAM 角色是一个管道角色,因此该角色必须能够管理集群上几乎所有类型的资源。因此,system:masters 组权限适用于此角色。

要将所需的配置添加到 Kubernetes 内的 aws-auth ConfigMap 中,请使用以下代码:

- groups: - system:masters rolearn: arn:aws:iam::{account_id}:role/ADO-role username: ADO-role

{account_id}用您的 AWS 账户 身份证替换。

有关更多详细,请参阅 Amazon EKS 文档中的Amazon EKS 如何与 IAM 配合使用

AWS DevOps
Task说明所需技能

创建自托管代理池。

要在 Azure DevOps 帐户中配置自托管代理池,请使用以下步骤:

  1. 登录到你的 Azure DevOps 帐户组织。

  2. 选择 Azure DevOps 组织

  3. 选择你的 Azure DevOps 项目。

  4. 选择 Project settings (项目设置)

  5. 选择代理池

  6. 选择添加池

  7. 选择自托管

  8. 对于名称,输入 eks-agent

  9. 选中向所有管道授予访问权限复选框。

  10. 选择创建

有关更多详细信息,请参阅 Microsoft 文档中的创建和管理代理池

Task说明所需技能

创建 Amazon ECR 存储库。

用于在私有 Amazon EKS 集群上部署 Azure DevOps 代理和示例应用程序 (webapp) 的 Docker 映像必须存储在 Amazon ECR 存储库中。要创建 Amazon ECR 存储库,请使用以下步骤:

  1. https://console.aws.amazon.com/ecr/存储库中打开 Amazon ECR 控制台。

  2. 从导航栏中,选择您创建存储库的 AWS 区域

  3. 存储库页面,选择私有存储库,然后选择创建存储库

  4. 对于存储库名称,输入 webapp。要使此模式中的示例应用程序正常运行,Amazon ECR 存储库名称必须使用 webapp。如果您使用了不同的存储库名称,请参阅问题排查

有关更多详细信息,请参阅 Amazon ECR 文档中的创建 Amazon ECR 私有存储库来存储映像

AWS DevOps

创建一个 Dockerfile 来构建 Azure 代理 DevOps 。

创建一个 Dockerfile 来生成安装了 Azure DevOps 代理的 Docker 镜像。将以下内容存储在名为 Dockerfile 的文件中:

FROM ubuntu:22.04 ENV TARGETARCH="linux-x64" RUN apt update && apt upgrade -y && apt install -y curl git jq libicu70 unzip wget RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" RUN unzip awscliv2.zip RUN ./aws/install RUN rm -rf aws awscliv2.zip RUN curl -sSL https://get.docker.com/ | sh RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash RUN mkdir -p azp WORKDIR /azp/ COPY ./start.sh ./ RUN chmod +x ./start.sh RUN useradd -m -d /home/agent agent RUN chown -R agent:agent /azp /home/agent RUN groupadd -f docker RUN usermod -aG docker agent USER agent ENTRYPOINT [ "./start.sh" ]
AWS DevOps

为 Azure DevOps 代理创建脚本。

要创建 start.sh 脚本,请使用以下步骤:

  1. 转到 Microsoft 文档中的创建和构建 Dockerfile 程序,然后滚动到步骤 5。将以下内容保存到 ~/azp-agent-in-docker/start.sh,确认使用 Unix 样式(LF)行尾

  2. 复制脚本的内容,并将其保存在名为 start.sh 的文件中,其中该文件与 Dockerfile 位于同一个目录下。

AWS DevOps

使用 Azure DevOps 代理构建 Docker 镜像。

要创建 Docker 镜像来安装 Azure DevOps 代理,请使用你之前创建的 Dockerfile 来构建镜像。在存储 Dockerfile 的同一个目录中,运行以下命令:

aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com docker build --platform linux/amd64 -t ado-agent:latest . docker tag ado-agent:latest aws_account_id.dkr.ecr.region.amazonaws.com/webapp:latest docker push aws_account_id.dkr.ecr.region.amazonaws.com/webapp:latest

用您的 AWS 账户 ID 替换aws_account_idregion,然后 AWS 区域。

AWS DevOps
Task说明所需技能

生成 Azure 个人访问令牌。

在私有 Amazon EKS 集群上运行的代理需要个人访问令牌 (PAT),这样它才能使用 Azure DevOps 账户进行身份验证。要生成 PAT,请使用以下步骤:

  1. 使用你计划在 Azure DevOps 组织中使用的用户帐户登录 (https://dev.azure.com/{Your_Organization})。

  1. 从您的主页,打开您的用户设置,然后选择个人访问令牌

  2. 选择新令牌

  3. 输入令牌的名称

  4. 选择显示所有范围

  5. 对于代理池,选中读取并管理复选框。

  6. 选择创建

  7. 要在私有 Amazon EKS 集群上创建密钥,请使用以下配置:

apiVersion: v1 kind: Secret metadata: name: azdevops-pat namespace: default type: Opaque stringData: AZP_TOKEN: <PAT Token>
  1. 将配置存储在名为 ado-secret.yaml 的文件中。将 <PAT Token> 替换为您刚刚创建的个人访问令牌。要创建密钥,请运行以下命令:

kubectl create -f ado-secret.yaml

有关更多详细信息,请参阅 Microsoft 文档中的使用个人访问令牌(PAT)注册代理

AWS DevOps

使用 Kubernetes 清单文件以进行代理部署。

要在私有 Amazon EKS 集群上部署 Azure DevOps 代理,请复制以下清单文件并将该文件存储为agent-deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: azure-pipelines-agent-eks labels: app: azure-pipelines-agent spec: replicas: 1 selector: matchLabels: app: azure-pipelines-agent template: metadata: labels: app: azure-pipelines-agent spec: containers: - name: docker image: docker:dind securityContext: privileged: true volumeMounts: - name: shared-workspace mountPath: /workspace - name: dind-storage mountPath: /var/lib/docker env: - name: DOCKER_TLS_CERTDIR value: "" - name: azure-pipelines-agent image: aws_account_id.dkr.ecr.region.amazonaws.com/webapp:latest env: - name: AZP_URL value: "<Azure account URL>" - name: AZP_POOL value: "eks-agent" - name: AZP_TOKEN valueFrom: secretKeyRef: name: azdevops-pat key: AZP_TOKEN - name: AZP_AGENT_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: DOCKER_HOST value: tcp://localhost:2375 volumeMounts: - mountPath: /workspace name: shared-workspace volumes: - name: dind-storage emptyDir: {} - name: shared-workspace emptyDir: {}

aws_account_id<Azure account URL>替换为你的 AWS 账户 ID 和 Azure DevOps 帐户网址。

AWS DevOps

在私有 Amazon EKS 集群上部署代理。

要在私有 Amazon EKS 集群上部署 Azure DevOps 代理,请使用以下命令:

kubectl create -f agent-deployment.tf
AWS DevOps

验证代理是否正在运行。

要验证 Azure DevOps 代理是否正在运行,请使用以下命令:

kubectl get deploy azure-pipelines-agent-eks

该预期输出应该类似于以下所示:

NAME READY UP-TO-DATE AVAILABLE AGE azure-pipelines-agent-eks 1/1 1 1 58s

确认 READY 列已显示 1/1

AWS DevOps

验证代理是否已在 Azure DevOps 代理池中注册。

要验证代理是否已部署在私有 Amazon EKS 集群上并已向代理池 eks-agent 中注册,请使用以下步骤:

  1. 登录到你的 Azure DevOps 组织 (https://dev.azure.com/{Your_Organization})。

  2. 选择 Project settings (项目设置)

  3. 选择代理池

  4. 选择 eks-agent 池,然后检查代理选项卡。

您应该看到列出的代理的状态为 “在线”,并且该代理的名称应以 azure-pipelines-agent-eks-* 开头。

AWS DevOps
Task说明所需技能

将示例应用程序存储库分支到您的 GitHub 账户。

将以下 AWS 示例存储库分支到您的 GitHub 账户:

https://github.com/aws-samples/deploy-kubernetes-resources-to-amazon-eks-using-azure-devops

AWS DevOps

创建管道。

要在你的 Azure DevOps 帐户中创建管道,请使用以下步骤:

  1. 使用你计划在 Azure DevOps 组织中使用的用户帐户登录 (https://dev.azure.com/{Your_Organization})。

  2. 导航到您的项目和管道控制台。

  3. 选择新管道

  4. 对于 “您的代码在哪里”,选择GitHub。

  5. 提供管道连接到您的 GitHub 账户所需的凭证

  6. 选择存储库 deploy-kubernetes-resources-to-amazon-eks-using-azure-devops

  7. 对于配置管道,选择现有 Azure Pipelines YAML 文件

  8. 对于选择现有 YAML 文件,为分支选择,并为路径选择 azure_pipelines.yaml

  9. 选择继续

  10. 审查您的管道 YAML,请将 awsRegionawsEKSClusterName 的输入参数值替换为您的信息:

pool: name: eks-agent #pool: self-hosted # If you are running self-hosted Azure DevOps Agents stages: # Refering the pipeline template, input parameter that are not specified will be added with defaults - template: ./pipeline_templates/main_template.yaml parameters: serviceConnectionName: aws-sc awsRegion: <your region> awsEKSClusterName: <name of your EKS cluster> projectName: webapp
  1. 选择运行

AWS DevOps

验证示例应用程序是否已部署。

管道完成后,检查 Amazon ECR 存储库和 Amazon EKS 集群,进而验证示例应用程序是否已成功部署。

要验证 Amazon ECR 存储库中的构件,请使用以下步骤:

  1. 导航到 webapp Amazon ECR 存储库。

  2. 确认是否存在以下新构件:

  • Docker 映像 – <date>.<build_number>-image

  • Helm 图表 – <date>.<build_number>-helm

例如,20250501.1-image20250501.1-helm

要在命名空间 webapp 中验证私有 Amazon EKS 集群上的部署,请使用以下命令:

kubectl get deploy -n webapp

预期的输出如下所示:

NAME READY UP-TO-DATE AVAILABLE webapp 1/1 1 1

注意:如果这是您首次运行管道,则可能需要对服务连接和代理池执行授权。在 Azure DevOps 管道界面中查找权限请求,然后批准它们以继续。

AWS DevOps

问题排查

问题解决方案

当 Amazon ECR 存储库名称与 webapp 不匹配时,管道失败

示例应用程序希望 Amazon ECR 存储库名称与 azure_pipeline.yml 中的 projectName: webapp 参数相匹配。

要解决此问题,请将您的 Amazon ECR 存储库重命名为 webapp,或更新以下内容:

  • 重命名分叉 GitHub 存储库中的webapp目录以匹配您的 Amazon ECR 存储库名称。

  • 更新 azure_pipeline.yml 中的 projectName 参数,以匹配您的 Amazon ECR 存储库名称。

错误:Kubernetes 集群无法访问:服务器已要求客户端提供凭证

如果您在 Azure Pipelines 的“提取并部署 Helm 图表”步骤中遇到此错误,则根本原因通常源于 Amazon EKS 集群 aws-auth ConfigMap 中的 IAM 角色配置不正确。

要解决此问题,请检查以下操作:

  • 验证 aws-auth ConfigMap 配置。

  • 检查您的 Amazon EKS 集群的身份验证设置:打开 Amazon EKS 控制台、集群详细信息访问配置。确保将身份验证模式设置为 EKS API 和 ConfigMap(而不仅仅是 EKS API)。

相关资源

AWS 博客

AWS 服务 文档

微软文档