亚马逊AWS官方博客

在 Kubernetes 上使用 Spinnaker 构建部署管道

 

采用 Jenkins 和 Amazon ECR 的 Spinnaker 管道架构。Spinnaker 是一种持续交付平台,最初由 Netflix 开发,用于快速、可靠地发布软件更改。Spinnaker 使开发人员可以更轻松地专注于编写代码,而无需担心底层的云基础设施。它与 Jenkins 以及其他流行的构建工具无缝集成。

在本博文中,我们将讨论如何安装 Spinnaker 以及如何为在 Kubernetes 上运行的工作负载构建持续交付管道。我们的工作流与以下类似:

 

图中包含了下列步骤:

  1. 开发人员将代码推送到 GitHub。
  2. GitHub 触发 Jenkins。
  3. Jenkins 构建一个 Docker 映像,然后为它添加标签并推送到 Amazon Elastic Container Registry (Amazon ECR)。
  4. Spinnaker 管道将在 Amazon ECR 收到此新 Docker 映像时触发。
  5. 然后 Spinnaker 将执行如下操作:
    1. 使用 Helm 生成 (Bake) Kubernetes 部署文件(开发和生产)。
    2. 将 Kubernetes 部署到开发环境。
    3. 人工判断:我们的管道配置需要人工手动确认,然后才能将应用程序部署到生产环境。它会等待此步骤完成,然后才会继续执行管道。
    4. 将代码部署到生产环境。

先决条件

  1. 一个正在运行的 Kubernetes 集群。如果您还没有运行这样的集群,请使用 eksctl通过一个命令启动并运行 EKS 集群
  2. Kubernetes 集群中至少需要有 8GB 可用内存和 2 个 vCPU 以支持 Spinnaker 微服务。一个 m5.large 实例应该足够满足此要求。
  3. 已在您的计算机上安装、配置和运行 kubectl
  4. 已安装 Helm。如要安装,请遵循 Kubernetes Helm 说明
  5. 已安装 Jenkins。如要安装,请遵循 AWS 上的 Jenkins 文档中的说明。
  6. 已为 Jenkins 安装 DockerAmazon ECR 插件并且正确配置。
  7. 一个 Docker 注册表账户。如果您还没有这样的账户,您可以使用 Amazon ECR,因为我们在本博文中也将这样做。您还可以使用 Docker Hub
  8. 一个身份提供商 (LDAP/SAML/Oauth2)。在本博文中,我们将使用 Active Directory (LDAP) 身份认证机制。如果您还没有身份提供商,请遵循 AWS 托管 Microsoft AD 文档中的说明。

步骤

当所有的先决条件都具备后,您就可以开始设置管道的实际步骤。我们将详细讲解每个步骤,下面概括了我们将要执行的步骤:

  1. 构建一个示例应用程序:Hello world 示例微服务
  2. 使用 Helm 在 EKS 上安装 Spinnaker。
    1. 设置 LDAP/AD 身份验证。
  3. 通过设置入站控制器来暴露 Spinnaker。
  4. 将一个 GitHub 账户添加到 Spinnaker。
  5. 在您的 AWS 账户中配置 Amazon ECR,以便存储 Jenkins 推送的 Docker 映像。
  6. 为 Docker 映像编译和 ECR 推送配置 Jenkins。
  7. 在 Spinnaker 中构建 CI/CD 管道 — 私用来自 GitHub 的 Web-hook 自动化编译,手动批准生产环境部署。
  8. 运行管道并部署应用程序。
  9. 测试。
  10. 清除。

第 1 步:构建示例应用程序

为便于本博文的演示,我们将使用我们的管道将会构建和部署的示例应用程序。请对示例应用程序进行分叉以继续下一步。

此存储库包含一个 Helm 图表,该图表将在 Spinnaker 进行部署时使用。本节剩余部分提到的项目已经为此存储库完成,因此您可以直接使用。如果您使用示例应用程序,则可跳过第 2 步! 否则,如果您使用自己的应用程序:

如果您使用自己的应用程序

如果您倾向于使用自己的应用程序,您将需要创建自己的 Helm 图表并进行封装。请按照以下步骤为您的应用程序创建和封装一个 Helm 图表。

helm 创建示例微服务

打开 sample-microservice/templates/deployment.yaml,然后进行如下更改:

 1.1 添加命名空间

namespace: {{ .Release.Namespace}} 添加到 Helm 模板部署中。这将帮助 Spinnaker 在部署阶段提到的特定命名空间中部署 Kubernetes 部署包

apiVersion: apps/v1beta2
kind: Deployment
metadata:
	name: {{ include "sample-microservice.fullname" . }}
	namespace: {{ .Release.Namespace}}

1.2 更改映像

将 Helm 模板的 deployment.yaml 文件中的 "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 更改为 {{ .Values.image.repository }}(这将让 Spinnaker 替换部署的标签),即从:


    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: {{ .Values.image.repository }}
          imagePullPolicy: "{{ .Values.image.pullPolicy }}:{{ .Values.image.tag}}"

更改为:


    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: {{ .Values.image.repository }}
          imagePullPolicy: {{ .Values.image.pullPolicy }}

通过运行以下命令封装 Helm 图表:

helm package sample-microservice

此命令将创建 Spinnaker 会用到的 sample-microservice-0.1.0.tgz 文件。

第 2 步:使用 Helm 安装 Spinnaker

要使用默认配置安装 Spinnaker,请运行如下命令:

helm install stable/spinnaker --name=spinnaker --namespace=spinnaker

如需了解更多信息,请参阅适用于 GitHub 上的 Spinnaker 的 Helm 图表

在安装过程中,我们来谈谈我们将在本博文中用到的一些 Spinnaker 组件。有关 Spinnaker 的详细架构和组件,请参阅 Spinnaker 参考架构

  1. Deck — 这是用于提供基于浏览器的 UI 的 Spinnaker 前端组件。
  2. Gate — 此服务提供了 Spinnaker REST API,负责服务脚本处理客户端以及来自 Deck 的所有操作。
  3. Halyard — 用于配置、安装和更新 Spinnaker 的 CLI。

Spinnaker 将 Redis 作为缓存基础设施,用于存储与实时执行有关的信息;有关此功能的更多信息请参阅 Spinnaker Redis 配置页面。我们将使用 Helm 图表依赖并且安装在 Kubernetes 集群内部的一个 Redis 安装。对于 Spinnaker 的生产设置,您将需要将 Redis 外部化。您还将需要参阅 Spinnaker 生产化文档

Spinnaker 还需要一个数据存储(S3Minio 或其他对象存储)。默认安装会使用 Minio。对于生产环境,您将需要通过在 values.yaml 中启用 S3 来使用 S3,而不是 Minio。

要验证您的 Spinnaker 安装:

kubectl -n spinnaker get pods:

与以下类似的输出可确认 Spinnaker 已成功安装:

NAME                                          READY   STATUS      RESTARTS   AGE
spin-clouddriver-945c95564-8wl52              1/1     Running     0          2h
spin-deck-6c4bf6c4f6-wqgmk                    1/1     Running     0          2h
spin-echo-646f6c4b76-p29tl                    1/1     Running     0          2h
spin-front50-7cc5575457-qcvtd                 1/1     Running     1          2h
spin-gate-84dc696d7c-zqctg                    1/1     Running     0          2h
spin-igor-885f8bf5c-xprkc                     1/1     Running     0          2h
spin-orca-7bfd8fd4d6-28dks                    1/1     Running     0          2h
spin-rosco-844b85888-sggkk                    1/1     Running     0          2h
spinnaker-install-using-hal-qlvfj             0/1     Completed   0          2h
spinnaker-Minio-df54fb68d-h4ld9               1/1     Running     0          2h
spinnaker-Redis-master-0                      1/1     Running     0          2h
spinnaker-spinnaker-halyard-0                 1/1     Running     0          2h

要列出服务,请运行以下命令:

kubectl -n spinnaker get services

输出:

NAME                          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
spin-clouddriver              ClusterIP   172.20.135.53    <none>        7002/TCP   2h
spin-deck                     ClusterIP   172.20.167.104   <none>        9000/TCP   2h
spin-echo                     ClusterIP   172.20.46.99     <none>        8089/TCP   2h
spin-front50                  ClusterIP   172.20.234.34    <none>        8080/TCP   2h
spin-gate                     ClusterIP   172.20.132.82    <none>        8084/TCP   2h
spin-igor                     ClusterIP   172.20.87.99     <none>        8088/TCP   2h
spin-orca                     ClusterIP   172.20.241.201   <none>        8083/TCP   2h
spin-rosco                    ClusterIP   172.20.136.62    <none>        8087/TCP   2h
spinnaker-Minio               ClusterIP   None             <none>        9000/TCP   2h
spinnaker-Redis-master        ClusterIP   172.20.80.211    <none>        6379/TCP   2h
spinnaker-spinnaker-halyard   ClusterIP   None             <none>        8064/TCP   2h

要启动 Spinnaker UI,请运行命令:

kubectl -n spinnaker port-forward svc/spin-deck 9000:9000

在浏览器中导航至 http://localhost:9000。这时您应会看到:

第 2.1 步:设置 LDAP/AD 身份验证。

获取您的 Active Directory 服务器的 URL。在我的 AWS 账户中,有一个 AD 服务器与我的 Kubernetes 集群在同一个 VPC 中运行。如果您还没有这样的服务器,请转至 AWS 托管 AD 并自行获取一个服务器。

如下所示创建一个名为 gate-local.yaml 的文件。此文件将用于放置 Spinnaker 的 Active Directory 配置。


ldap:
  enabled: true
  url: ldap://10.0.157.236:389/dc=ad,dc=prabhatsharma,dc=com
  userSearchBase: OU=users,OU=ad
  userSearchFilter: (sAMAccountName={0})
  managerDn: CN=prabhat,OU=users,OU=ad,dc=ad,dc=prabhatsharma,dc=com
  managerPassword: MySuper#StrongPassword

gate-local.yaml 复制到 Halyard:

kubectl cp gate-local.yaml spinnaker-spinnaker-halyard-0:/home/spinnaker/.hal/default/profiles/

应用 Halyard 配置:

kubectl exec spinnaker-spinnaker-halyard-0 -- bash hal deploy apply

第 3 步:暴露 Spinnaker — 设置入站控制器

这是一个可选步骤,仅在您需要在 Kubernetes 集群外部暴露 Spinnaker 时使用。您必须安装了 NGINX 入站控制器才能成功完成此步骤。

我在 Route53 中配置了一个公有的万用域,它指向我的 NGINX 入站 ELB。您需要使用自己的域,为此请将 yourcustomdomain.com 替换为您自己的域。

创建文件 spinnaker-ingress.yaml


apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: spinnaker
  annotations:
    kubernetes.io/ingress.class: nginx   
spec:
  tls:
  - hosts:
    - spinnaker.yourcustomdomain.com
    - spin-gate.yourcustomdomain.com
  rules:
  - host: spinnaker.yourcustomdomain.com
    http:
      paths:
      - path: /
        backend:
          serviceName: spin-deck
          servicePort: 9000
  - host: spin-gate.yourcustomdomain.com
    http:
      paths:
      - path: /
        backend:
          serviceName: spin-gate
          servicePort: 8084

部署入站控制器:

kubectl -n spinnaker apply -f spinnaker-ingress.yaml

这时,您已经暴露了甲板(Spinnaker UI 终端节点)和闸门(Spinnaker API 终端节点)。

您需要告诉 Spinnaker 使用我们刚刚创建的新 Spinnaker 终端节点。为此我们将使用 Halyard。要运行 Halyard,请登录到 Halyard Pod:

kubectl -n spinnaker exec -it spinnaker-spinnaker-halyard-0 bash

这将会进入容器中的壳程序。

spinnaker@spinnaker-spinnaker-halyard-0:/workdir$

运行以下命令以将 Spinnaker 配置为使用新的终端节点。如果需要任何其他的配置,您始终可以参考完整的 Halyard 命令列表。


hal config security api edit --override-base-url https://spin-gate.yourcustomdomain.com
hal config security ui edit --override-base-url https://spinnaker.yourcustomdomain.com
hal deploy apply

此后您将能够通过 https://spinnaker.yourcustomdomain.com 访问 Spinnaker。

第 4 步:将一个 GitHub 账户添加到 Spinnaker

我们将使用 Halyard 来添加 GitHub 账户

要访问 Halyard Pod:


kubectl -n spinnaker exec -it spinnaker-spinnaker-halyard-0 bash
hal config artifact github account add aws-samples
hal deploy apply

注意:请将 aws-samples 更改为您自己的 Github 账户名。

以上命令将允许 Spinnaker 访问 GitHub。

第 5 步:为 Jenkins 映像推送配置 Amazon ECR 存储库

您需要一个 Docker 存储库来存储您的微服务 Docker 映像。为此我们将创建一个 Amazon ECR 存储库。

导航至 AWS 控制台 > 计算 > ECR

单击创建存储库

键入存储库的名称 (sample-microservice),然后单击创建存储库

此存储库将存储 Jenkins 推送的我们的微服务的 Docker 映像。

第 6 步:为 Docker 映像编译和 ECR 推送配置 Jenkins

注意:您必须已经安装并配置好 Amazon ECR 插件才能执行此操作。您可以前往 Jenkins > Plugin Manager(插件管理器)> Installed(已安装)并搜索 Amazon ECR,从而验证该插件已安装。

我们将配置一个 Jenkins 作业,此作业将通过向 GitHub 推送代码的方式触发。此作业将会构建一个 Docker 映像并将该映像推送到 Amazon ECR。

现在登录到您的 Jenkins 安装,并且:

6.1 创建一个新的任意风格项目

6.2 配置源代码管理

更改分叉后的 GitHub 存储库路径,然后将 aws-samples 替换为您自己的用户名,例如将 https://github.com/aws-samples/sample-microservice-with-spinnaker 替换为 https://github.com/[您的 GitHub 句柄]/sample-microservice-with-spinnaker。

6.3 配置编译触发器

您可以使用 Webhook 或轮询。在本博文中我们使用 Webhook。GitHub 的 Jenkins Webhook 配置不属于本博文的范围。

6.4 配置编译阶段

我们将 Jenkins 编译号作为 Docker 映像标签使用:

Jenkins 变量 BUILD_NUMBER 将作为新创建映像的标签使用。

第 7 步:为 Spinnaker 配置 Amazon ECR

注意:要完成此项操作,您的 Kubernetes 节点必须分配了恰当的 IAM 角色以允许访问 ECR。您可以在文档中找到可以分配到您的 Kubernetes 工作线程节点 IAM 角色的示例 IAM 策略

此配置将允许您配置将容器推送到 ECR 时将会触发的 Spinnaker 管道。


ADDRESS=123456789123.dkr.ecr.us-west-2.amazonaws.com
REGION=us-west-2


hal config provider docker-registry account add my-ecr-registry \
--address $ADDRESS \
--username AWS \
--password-command "aws --region $REGION ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken' | base64 -d | sed 's/^AWS://'"

hal deploy apply

有关管理 Docker 注册表的更多信息,请参阅 Spinnaker 的 Docker 注册表文档

第 8 步:在 Spinnaker 中构建 CI/CD 管道

在开始构建此管道前,您需要了解一些 Spinnaker 概念:

应用 — 应用是指您将使用 Spinnaker 部署的服务、该服务的所有配置以及它运行所需的所有基础实施。您一般会为每个服务创建不同的应用,但这并非 Spinnaker 的强制要求。

管道 — 管道是指 Spinnaker 提供的一定顺序的阶段,从操作基础设施的功能(部署、调整、禁用),到支持功能(人工判断、等待、运行 Jenkins 作业)等等。所有这些阶段一起准确定义了管理您的部署的操作手册。

阶段 — Spinnaker 中的阶段是管道的基本构建块,它描述了该管道将执行的操作。您可以按任何顺序排列 Spinnaker 中的阶段,但一些阶段顺序要比其他顺序更常见。Spinnaker 提供了多个阶段,例如部署、调整、禁用、人工判断等等。

构件 — 在 Spinnaker 中,构件是指引用任何外部资源的对象。该资源可以是:

  • Docker 映像
  • 存储在 GitHub 中的文件
  • Amazon 系统映像 (AMI)
  • S3、GCS 等中的二进制大对象

Spinnaker 使用 Helm v2 来管理向 Kubernetes 推送的部署。您必须为您计划推送部署的每个环境指定一个基本 Helm 模板和一个覆盖文档。

下面我们执行设置管道的必要步骤:

  1. 创建应用
  2. 创建管道
  3. 设置配置
    1. 设置构件
      1. Helm 模板 — sample-microservice-0.1.0.tgz
      2. Helm 开发环境覆盖 — values/dev.yaml
      3. Helm 生产环境覆盖 — values/dev.yaml
      4. Docker 映像 — 123456789123.dkr.ecr.us-west-2.amazonaws.com/sample-microservice
    2. 设置管道触发器
  4. 创建阶段
    1. Bake 开发
    2. Bake 生产
    3. 部署到开发
    4. 人工判断
    5. 部署到生产

8.1 创建应用

我们的应用将是 Spinnaker 中的一个占位符,代替我们将为其构建管道的服务。

登录到 Spinnaker 后,从 Applications > Create Application 创建一个新的应用。

 

单击 Create;您将会看到应用基础设施页面:

8.2 创建管道

转至“Pipelines”,然后单击 Configure a new pipeline

 

8.3 设置管道配置

现在您将进入:

现在我们将配置 Expected Artifacts

Helm 模板构件

单击 Add Artifact

注意:在下面的步骤中,请将 aws-samples 替换为您的 GitHub 句柄。

将默认内容 URL 设置为 https://api.gitgub.com/repos/aws-samples/sample-microservice-with-spinnaker/contents/sample-microservice-0.1.0.tgz

 

触发器每次触碰 Webhook 时,会将构件传输至 Spinnaker。如果您的管道需要特定的构件来执行尚未通过触发器收到的管道,您可以指定要使用的默认构件。在此例中,我们将指定默认构件,因为我们的管道未被 GitHub 触发,因此不会在我们需要执行时传输该构件。

对其他构件进行类似配置:

开发环境覆盖构件

构件类型 — GitHub
文件路径 — values/dev.yaml
默认构件内容 URL – https://api.github.com/repos/aws-samples/sample-microservice-with-spinnaker/contents/values/dev.yaml

生产环境覆盖构件

构件类型 — GitHub
文件路径 — values/prod.yaml
默认构件内容 URL – https://api.github.com/repos/aws-samples/sample-microservice-with-spinnaker/contents/values/prod.yaml

Docker 映像构件

构件类型 — Docker
Docker 映像 — 123456789123.dkr.ecr.us-west-2.amazonaws.com/sample-microservice
默认构件 Docker 映像 — 123456789123.dkr.ecr.us-west-2.amazonaws.com/sample-microservice:latest

现在我们将配置 Automated Triggers

自动化触发器可以在每次发生特定事件时(例如,Docker 映像推送到注册表、代码推送到 GitHub 等)启动某个管道。我们需要在我们的 ECR 存储库中有新的 Docker 映像可用时启动管道。

配置方式是从 Automated Triggers 的下拉列表中选择注册表名称和映像:

然后单击右下角的 Save Changes 以保存更改。

8.4 添加 Bake 阶段

现在我们的管道配置已经完成,可以添加新的阶段

Bake dev — 此阶段将使用 dev.yaml 中的覆盖值,通过 Helm v2 来渲染部署模板。

跳转至管道顶部,单击 Add stage

提供名称和将会进行部署的 Kubernetes 命名空间。命名空间必须已经存在,否则管道执行时将会失败。

这还将创建一个叫做 Produces Artifacts 的部分,您可以下翻看到:

此生成的构件是一个 base64 编码的 Kubernetes 部署文件(含服务、入口等)。

安装与上述 Bake dev类似的操作,创建一个 Bake prod 阶段。

这时您的管道应会与以下类似:

8.5 添加部署到生产阶段

在完成“Bake dev”和“Bake prod”阶段后,我们的 Kubernetes 部署文件已经准备就绪,可以用于部署。现在创建一个 Deploy dev 阶段,这将会部署到开发环境。选中 Bake dev 阶段后,单击 Add stage。将“Bake prod”作为一个依赖项与 Bake dev 一起添加。

8.6 添加人工判断阶段

许多团队希望有人来人工审批,然后再将部署推送到生成环境。如果您的团队属于这种情况,您可以添加一个“Manual Judgement”阶段。

单击 Add stage,然后从下拉列表中选择 Manual Judgement

8.7 添加部署到生产阶段

这是我们的最后一个阶段,如果一切进展顺利,我们会将部署文件推送到生产环境。单击 Add stage 并选择预期构件 sample-microservice-prod, type: embedded/base64,从而创建此阶段。它应当拥有一个依赖项 Manual Judgement

9.测试

在您的 Kubernetes 集群中创建两个命名空间:

kubectl create namespace sample-microservice-dev
kubectl create namespace sample-microservice-prod

现在您可以通过修改 main.go 并推送提交至 GitHub,从而对整个管道进行测试。您将一次看到以下事件:

  1. Jenkins 编译被触发。
  2. 新的 Docker 映像被发布到 Amazon ECR。
  3. Spinnaker 管道被触发。

您可以在管道屏幕上看到进度。在人工判断阶段,它将与以下类似:

单击 Continue,管道将继续将部署推送到生产环境。

祝贺您! 您已经启动并运行了您的 Spinnaker 管道。如需了解更多信息,请参阅官方的 Spinnaker 指南

10.清除

完成测试后,您可以按照下列步骤执行清理:

10.1 删除 Helm 图表

helm delete spinnaker --purge

这将会删除与 Spinnaker Helm 部署关联的所有资源。

10.2 删除入站控制器

kubectl -n spinnaker delete ingress spinnaker

这将删除 Spinnaker 入站控制器。

小结

在本博文中,我们向大家演示了如何安装 Spinnaker 和创建持续交付管道。此外,我们还介绍了一些 Spinnaker 概念合同可以在构建管道时使用的不同类型的阶段。虽然此管道十分简单,Spinnaker 也支持多种其他功能,例如回滚和金雀花部署。它可以与 Jenkins 和 Travis CI 等 CI 工具集成。它还可以与 PrometheusSignalFx 等集成以进行金雀花分析。要了解有关 Spinnaker 功能的更多信息,请参阅精彩的 Spinnaker 文档

祝大家部署快乐!