返回文章列表
CI/CD | 源代码管理 | 2024-03-07

使用Pulumi管理GitLab资源

极狐GitLab

学习Pulumi的基础设施即代码工具如何帮助用户优化极狐GitLab的CI/CD工作流。

在不断发展的DevOps领域中,平台工程师越来越寻求高效灵活的工具来管理他们的极狐GitLab资源,特别是用于编排持续集成/持续交付(CI/CD)流水线。Pulumi提供了一种独特的基础设施即代码(IaC)方法,允许工程师使用熟悉的编程语言,如TypeScript、Python、Go等。这种方法可以优化极狐GitLab CI/CD工作流程自动化过程。Pulumi具有声明式语法,结合将基础设施视为软件的能力,有助于实现版本控制、协作和可复现性,与极狐GitLab的理念完美契合。

 

让我们一起探究使用Pulumi和极狐GitLab的这种强大功能。

 

什么是Pulumi?

 

Pulumi是一个IaC工具,可以管理超过150个支持的云或SaaS产品资源(包括AWS和极狐GitLab,在本文中将会演示)。你可以使用Pulumi用常见的通用编程语言如TypeScript、Python、Go来表达你的基础设施。

 

Pulumi是声明式的(就像其他一些熟悉的IaC工具一样),这意味着你只需要描述资源的期望最终状态,而Pulumi将会找出从当前状态到期望状态的创建、读取、更新和删除(CRUD)操作顺序。

 

在最初使用通用编程语言来表示你的基础设施的期望状态时,与像CloudFormation或Terraform等工具相比,Pulumi的方法可能看起来很奇怪,但Pulumi的方法具有诸多优势,包括以下方面:

 

  • 熟悉的工具。你不需要特殊的工具来使用Pulumi。代码补全在你喜欢的编辑器或IDE中可以按预期工作,无需任何额外插件。你可以使用熟悉的打包工具如npm、PyPI等分享Pulumi代码。
  • 熟悉的语法。与基于DSL的IaC工具不同,你无需学习特殊的数组元素索引方式,或者创建循环或条件语句的特殊方式 - 你只需使用你已经了解的语言的常规语法。

 

Pulumi产品有一个开源组件,其中包括Pulumi命令行和与Pulumi和云及SaaS供应商之间的集成的生态系统供应商。Pulumi还提供了一个免费的(个人使用)和付费(用于团队和组织)SaaS服务Pulumi Cloud,该服务提供状态文件和密钥管理等众多有用功能。它是一个被广泛支持的开源IaC工具。

 

初始化项目

 

完成本示例需要以下内容:

 

1、一个Pulumi Cloud账户。Pulumi Cloud永久免费供个人使用。 Pulumi Cloud将管理您的Pulumi状态文件,并处理所有密钥加密/解密。由于个人使用是免费的(无需信用卡),我们强烈建议在学习如何使用Pulumi时使用Pulumi Cloud作为您的后端。

2、一个极狐GitLab账户、群组以及将GITLAB_TOKEN设置为环境变量的极狐GitLab令牌。

3、一个AWS账户和具有部署身份和访问管理(IAM)资源权限的凭据。

 

本示例将使用Pulumi 仓库中的两个提供者:

 

1、极狐GitLab Provider 将被用来管理诸如项目、ProjectFiles(为了初始化项目仓库)、ProjectHooks(用于与Pulumi Cloud集成)和ProjectVariables(用于保存我们的CI/CD流水线配置)。

 

2、AWS经典提供者用于管理AWS资源,创建AWS与极狐GitLab之间的OpenID Connect(OIDC)连接。

 

你可以通过切换到新建的空目录并运行以下命令来初始化您的Pulumi项目,并接受对后续提示的所有默认值:

pulumi new typescript

这将为您的Pulumi程序启动一个空白Pulumi程序。现在您可以导入您需要的提供者SDK:

npm i @pulumi/aws @pulumi/gitlab

您的index.ts文件是您的Pulumi程序的入口点(就像您在任何其他Node.js程序中所期望的那样),它将是要添加资源的文件。在index.ts的顶部添加以下导入:

import * as gitlab from "@pulumi/gitlab";
import * as aws from "@pulumi/aws";

 

现在,您准备添加一些资源!

 

添加第一个资源

 

首先,让我们定义一个变量,用于保存我们OIDC JWT令牌中的受众声明。将以下代码添加到index.ts:

const audience = "gitlab.com";

上述代码假设您正在使用极狐GitLab SaaS(https://jihulab.com)。如果您使用的是私有化部署的极狐GitLab ,则该值应该是极狐GitLab 安装的域名,例如jihulab.example.com。

 

然后,您将使用一个Pulumi函数通过名称获取现有的极狐GitLab 群组,并在您的GitLab群组中创建一个新的公开极狐GitLab项目:

 

const group = gitlab.getGroup({
  fullPath: "my-gitlab-group", // Replace the value with the name of your GL group
});

const project = new gitlab.Project("pulumi-gitlab-demo", {
  visibilityLevel: "public",
  defaultBranch: "main",
  namespaceId: group.then(g => parseInt(g.id)),
  archiveOnDestroy: false // Be sure to set this to `true` for any non-demo repos you manage with Pulumi!
});

 

创建OIDC资源

 

为了允许极狐GitLab CI/CD请求并获得临时AWS凭证,您需要在AWS中创建一个包含极狐GitLab证书指纹的OIDC提供者,然后创建一个允许极狐GitLab承担的AWS角色。

 

您将限定假定角色策略,以便此角色只能由您之前声明的极狐GitLab项目承担。极狐GitLab CI/CD所假定的角色将具有完整的管理员访问权限,以便Pulumi可以在AWS中创建和管理任何资源。(请注意,可以授予比FullAdministrator更低的访问权限以供Pulumi使用,但FullAdministrator通常是实际需要的,例如在需要创建IAM资源(如角色)时。角色创建需要FullAdministrator。这一考虑也适用于Terraform等IaC工具。)

 

将以下代码添加到index.ts:

 

const GITLAB_OIDC_PROVIDER_THUMBPRINT = "b3dd7606d2b5a8b4a13771dbecc9ee1cecafa38a";

const gitlabOidcProvider = new aws.iam.OpenIdConnectProvider("gitlab-oidc-provider", {
  clientIdLists: [`https://${audience}`],
  url: `https://${audience}`,
  thumbprintLists: [GITLAB_OIDC_PROVIDER_THUMBPRINT],
}, {
  deleteBeforeReplace: true, // URLs are unique identifiers and cannot be auto-named, so we have to delete before replace.
});

const gitlabAdminRole = new aws.iam.Role("gitlabAdminRole", {
  assumeRolePolicy: {
    Version: "2012-10-17",
    Statement: [
      {
        Effect: "Allow",
        Principal: {
          Federated: gitlabOidcProvider.arn,
        },
        Action: "sts:AssumeRoleWithWebIdentity",
        Condition: {
          StringLike: {
            // Note: Square brackets around the key are what allow us to use a// templated string. See:// https://stackoverflow.com/questions/59791960/how-to-use-template-literal-as-key-inside-object-literal
            [`${audience}:sub`]: pulumi.interpolate`project_path:${project.pathWithNamespace}:ref_type:branch:ref:*`
          },
        },
      },
    ],
  },
});

new aws.iam.RolePolicyAttachment("gitlabAdminRolePolicy", {
  policyArn: "arn:aws:iam::aws:policy/AdministratorAccess",
  role: gitlabAdminRole.name,
});

 

关于指纹有几点需要注意:

 

1、如果是私有化部署的极狐GitLab,则需要从您的私有化部署GitLab 中获取指纹。

2、如果您使用GitLab SaaS,可能在您阅读这篇文章时,极狐GitLab的OIDC证书已经被更改。

 

无论哪种情况,您可以通过按照AWS文档中包含的“获取OpenID Connect身份提供者的指纹”指南来获取正确/最新的指纹值。

 

您还需要将角色的ARN作为项目变量添加,以便CI/CD流程可以发出请求来承担角色:

 

new gitlab.ProjectVariable("role-arn", {
  project: project.id,
  key: "ROLE_ARN",
  value: gitlabAdminRole.arn,
});

 

项目钩子(可选)

 

Pulumi通过与极狐GitLab的Webhook集成提供了一个功能,该功能将直接将pulumi预览的输出作为评论发布到合并请求中。为使Webhook正常工作,您必须建立一个Pulumi 组织,并将极狐GitLab设置为其SSO来源。如果您没有Pulumi组织,且希望尝试该集成功能,您可以注册一个免费试用组织。此试用持续14天,将为您提供访问所有Pulumi付费功能的权限,并且不需要信用卡信息。有关集成的详细信息,请查看Pulumi CI/CD & 极狐GitLab集成。

 

要设置Webhook,将以下内容添加到您的index.ts文件:

new gitlab.ProjectHook("project-hook", {
  project: project.id,
  url: "https://api.pulumi.com/workflow/gitlab",
  mergeRequestsEvents: true,
  enableSslVerification: true,
  token: process.env["PULUMI_ACCESS_TOKEN"]!,
  pushEvents: false,
});

请注意,上述资源假定您的Pulumi访问令牌被存储为环境变量。您可能希望将令牌存储在您的堆栈配置文件中。为此,请运行以下命令:

pulumi config set --secret pulumiAccessToken ${PULUMI_ACCESS_TOKEN}

这将在您的Pulumi堆栈配置文件(Pulumi.dev.yaml)中存储加密后的值。由于该值已加密,您可以安全地将堆栈配置文件提交到git中。您可以在您的Pulumi程序中如此访问其值:

const config = new pulumi.Config();
const pulumiAccessToken = config.requireSecret("pulumiAccessToken");

 

创建存储库并添加存储库文件

 

您需要创建一个git存储库(一个极狐GitLab项目)并向其中添加一些控制CI/CD流程的文件。首先,创建一些将包含在极狐GitLab仓库中的文件:

mkdir -p repository-files/scripts
touch repository-files/.gitlab-ci.yml repository-files/scripts/{aws-auth.sh,pulumi-preview.sh,pulumi-up.sh}
chmod +x repository-files/scripts/{aws-auth.sh,pulumi-preview.sh,pulumi-up.sh}

接下来,您需要一个极狐GitLab CI/CD YAML文件来描述流水线:应该在哪个容器镜像中运行以及流水线的步骤是什么。将以下代码放入repository-files/.gitlab-ci.yml文件中:

default:
  image:
    name: "pulumi/pulumi:3.91.1"
    entrypoint: [""]

stages:
  - infrastructure-update

pulumi-up:
  stage: infrastructure-update
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  before_script:
    - chmod +x ./scripts/*.sh
    - ./scripts/aws-auth.sh
  script:
    - ./scripts/pulumi-up.sh
  only:
    - main # i.e., the name of the default branch

pulumi-preview:
  stage: infrastructure-update
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  before_script:
    - chmod +x ./scripts/*.sh
    - ./scripts/aws-auth.sh
  script:
    - ./scripts/pulumi-preview.sh
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'

CI/CD流程非常简单,但展示了一个准备投入生产的流水线所需的基本功能(或这些步骤可能是您组织需要的全部内容):

 

1、当打开或更新合并请求时,运行 pulumi  preview命令。这将帮助审核人员获取重要的上下文。由于IaC必然是有状态的(状态文件使得Pulumi成为声明式工具),审核人员在审查更改时必须同时具备代码更改和基础设施更改,以完全了解对代码库更改的影响。此流程构成持续集成。

 

2、当代码合并到默认分支(默认称为main)时运行 pulumi up命令。此流程构成持续交付。

 

请注意,此示例使用了"pulumi/pulumi"的“kitchen sink”镜像,其中包含Pulumi支持的所有语言的运行时,以及一些辅助工具如AWS CLI(您将需要它来使用OIDC认证)。虽然“pulumi/pulumi”镜像很方便,但也相当大(在编写时为1.41 GB),这使得初始化相对较慢。如果您要使用Pulumi创建生产流水线,可以考虑创建自己的定制(更精简)镜像,其中正好安装了您需要的工具,也许可以从Pulumi的特定语言镜像开始,例如pulumi/pulumi-nodejs。

 

接下来,您需要编写将通过OIDC授权极狐GitLab与AWS进行身份验证的脚本。将以下代码放入repository-files/scripts/aws-auth.sh文件中:

#!/bin/bash

mkdir -p ~/.aws
echo "${GITLAB_OIDC_TOKEN}" > /tmp/web_identity_token
echo -e "[profile oidc]\nrole_arn=${ROLE_ARN}\nweb_identity_token_file=/tmp/web_identity_token" > ~/.aws/config

echo "length of GITLAB_OIDC_TOKEN=${#GITLAB_OIDC_TOKEN}"
echo "ROLE_ARN=${ROLE_ARN}"

export AWS_PROFILE="oidc"
aws sts get-caller-identity

用于持续集成的脚本需要在打开合并请求时执行 pulumi preview命令。将以下代码放入repository-files/scripts/pulumi-preview.sh文件中:

#!/bin/bash
set -e -x

export PATH=$PATH:$HOME/.pulumi/bin

yarn install
pulumi login
pulumi org set-default $PULUMI_ORG
pulumi stack select dev
export AWS_PROFILE="oidc"
pulumi preview

 

用于持续交付的脚本需要在将合并请求合并到默认分支时执行 pulumi up命令。将以下代码放入repository-files/scripts/pulumi-up.sh文件中:

 

#!/bin/bash
set -e -x

# Add the pulumi CLI to the PATH
export PATH=$PATH:$HOME/.pulumi/bin

yarn install
pulumi login
pulumi org set-default $PULUMI_ORG
pulumi stack select dev
export AWS_PROFILE="oidc"
pulumi up -y

 

最后,您需要将这些文件添加到您的极狐 GitLab项目中。将以下代码块添加到您的index.ts文件中:

[
  "scripts/aws-auth.sh",
  "scripts/pulumi-preview.sh",
  "scripts/pulumi-up.sh",
  ".gitlab-ci.yml",
].forEach(file => {
  const content = fs.readFileSync(`repository-files/${file}`, "utf-8");

  new gitlab.RepositoryFile(file, {
    project: project.id,
    filePath: file,
    branch: "main",
    content: content,
    commitMessage: `Add ${file},`,
    encoding: "text",
  });
});

 

请注意,我们可以利用通用编程语言功能:我们可以创建一个数组,并使用forEach()来迭代其成员,并且我们可以从Node.js运行时使用fs.readFileSync()方法来读取文件的内容。这是强大的东西!

 

项目变量和堆栈输出

 

您还需要一些资源来完成代码。您的CI/CD流程需要一个Pulumi访问令牌,以便对抗Pulumi云后端进行身份验证,该后端保存您的Pulumi状态文件并处理秘密的加密和解密。您还需要提供您的Pulumi组织的名称。(如果您作为个人使用Pulumi云,这将是您的Pulumi用户名。)将以下内容添加到index.ts文件中:

new gitlab.ProjectVariable("pulumi-access-token", {
  project: project.id,
  key: "PULUMI_ACCESS_TOKEN",
  value: process.env["PULUMI_ACCESS_TOKEN"]!,
  masked: true,
});

new gitlab.ProjectVariable("pulumi-org", {
  project: project.id,
  key: "PULUMI_ORG",
  value: pulumi.getOrganization(),
});

最后,您需要添加一个堆栈输出,以便我们可以运行 git clone命令来测试我们的流水线。堆栈输出允许您从命令行或其他Pulumi程序中访问Pulumi程序中的值。将以下内容添加到index.ts文件中:

export const gitCloneCommand = pulumi.interpolate`git clone ${project.sshUrlToRepo}`;

 

部署基础设施和测试流水线


要部署资源,请运行以下命令:

pulumi up

Pulumi将输出它打算创建的资源列表。选择是来继续。

 

命令完成后,您可以运行以下命令获取用于您的极狐GitLab仓库的git clone命令:

pulumi stack output gitCloneCommand

在一个新的空目录中,从您的Pulumi堆栈输出运行 git clone命令,例如:

git clone git@gitlab.com:jkodroff/pulumi-gitlab-demo-9de2a3b.git

进入该目录并创建一个新的分支:

git checkout -b my-first-branch

现在您准备在我们的仓库中创建一些示 例基础设施。您可以使用aws-typescript快速生成一个包含AWS资源的简单Pulumi程序:

pulumi new aws-typescript -y --force

该模板包含一个非常简单的Pulumi程序,您可以用来验证流水线:

$ cat index.ts
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.Bucket("my-bucket");

// Export the name of the bucket
export const bucketName = bucket.id;

 

提交您的更改并推送您的分支:

git add -A
git commit -m "My first commit."
git push

 

在GitLab界面中,为您的分支创建一个合并请求:

 

您的合并请求流水线应该开始运行:

 

一旦流水线完成,您应该在流水线日志中看到pulumi preview命令的输出:

 

 

如果您安装了可选的Webhook,您应该看到 pulumi preview的结果作为评论发布到合并请求中:

 

 

一旦流水线完成运行,您的合并请求已准备好合并:

 

在合并请求后,将触发主分支流水线。请注意,在此屏幕底部,您将看到主分支CI/CD的初始运行失败。这是正常现象,是由于将.gitlab-ci/yml初始上传到主分支时没有出现Pulumi程序所导致的。

 

 

如果您点击进入主分支流水线执行,您将看到您的存储桶已被创建。

 

要删除存储桶,请在仓库的本地克隆中运行以下命令:

pulumi destroy

 

或者,您可以创建一个删除Pulumi程序中存储桶并重新运行流水线的合并请求。因为Pulumi是声明式的,从程序中删除存储桶将导致其从AWS中删除。

 

最后,在具有OIDC和GitLab资源的Pulumi程序中再次运行pulumi destroy命令,以完成清理工作。

 

接下来的步骤


使用基础设施即代码(IaC)来定义流水线和其他极狐GitLab资源可以极大地提高您的平台团队可靠、快速地管理资源的能力,从而保持应用团队的持续交付。借助Pulumi,您还可以使用流行的编程语言表达这些资源,获得强大的表达能力!

 

如果您喜欢这里所读的内容,以下是一些可以增强您的CI/CD流水线的方法:

 

1、添加Pulumi Policy Packs到您的流水线:Pulumi Policy Packs允许您验证资源是否符合组织的安全和合规政策。Pulumi的开源Compliance Ready Policies是您旅程的良好起点。Compliance Ready Policies包含主要云提供商的合规框架规则,如PCI-DSS和ISO27001,而且易于集成到您的流水线中。


2、了解Pulumi ESC(Environments, Secrets, and Configuration):Pulumi ESC使您能够轻松共享静态机密,如GitLab令牌,甚至可以生成动态机密,如AWS OIDC凭据。在大规模使用Pulumi时,ESC变得尤为有用,因为它可以减少在多个Pulumi程序中使用的配置和机密的重复性。您甚至无需使用Pulumi IaC也可以从Pulumi ESC中受益 - Pulumi ESC的命令行可以与任何CLI工具(如AWS CLI)一起使用。

极狐GitLab 一体化DevOps平台 专为中国用户研发,免费试用60天专业版高级功能
售前咨询
联系电话
在线支持
预约演示