在 Kubernetes 上使用 Spinnaker 构建部署流水线

2021-06-25 17:05:08 浏览数 (1)

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 安装 Docker 和 Amazon 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 图表。

代码语言:javascript复制
helm 创建示例微服务

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

1.1 添加命名空间

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

代码语言:javascript复制
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 替换部署的标签),即从:

代码语言:javascript复制
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: {{ .Values.image.repository }}
          imagePullPolicy: "{{ .Values.image.pullPolicy }}:{{ .Values.image.tag}}"

更改为:

代码语言:javascript复制
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: {{ .Values.image.repository }}
          imagePullPolicy: {{ .Values.image.pullPolicy }}

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

代码语言:javascript复制
helm package sample-microservice

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

第 2 步:使用 Helm 安装 Spinnaker

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

代码语言:javascript复制
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 还需要一个数据存储(S3、Minio 或其他对象存储)。默认安装会使用 Minio。对于生产环境,您将需要通过在 values.yaml 中启用 S3 来使用 S3,而不是 Minio。

要验证您的 Spinnaker 安装:

代码语言:javascript复制
kubectl -n spinnaker get pods

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

代码语言:javascript复制
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

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

代码语言:javascript复制
kubectl -n spinnaker get services

输出:

代码语言:javascript复制
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,请运行命令:

代码语言:javascript复制
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 配置。

代码语言:javascript复制
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:

代码语言:javascript复制
kubectl cp gate-local.yaml spinnaker-spinnaker-halyard-0:/home/spinnaker/.hal/default/profiles/

应用 Halyard 配置:

代码语言:javascript复制
kubectl exec spinnaker-spinnaker-halyard-0 -- bash hal deploy apply

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

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

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

创建文件 spinnaker-ingress.yaml

代码语言:javascript复制
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

部署入站控制器:

代码语言:javascript复制
kubectl -n spinnaker apply -f spinnaker-ingress.yaml

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

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

代码语言:javascript复制
kubectl -n spinnaker exec -it spinnaker-spinnaker-halyard-0 bash

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

代码语言:javascript复制
spinnaker@spinnaker-spinnaker-halyard-0:/workdir$

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

代码语言:javascript复制
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:

代码语言:javascript复制
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 管道。

代码语言:javascript复制
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. 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
    5. 设置构件
    6. 设置管道触发器
  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 集群中创建两个命名空间:

代码语言:javascript复制
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 图表

代码语言:javascript复制
helm delete spinnaker --purge

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

10.2 删除入站控制器

代码语言:javascript复制
kubectl -n spinnaker delete ingress spinnaker

这将删除 Spinnaker 入站控制器。

小结

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

原文链接:https://aws.amazon.com/cn/blogs/china/deployment-pipeline-spinnaker-kubernetes/

0 人点赞