GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。
更多关于极狐GitLab :https://gitlab.cn 或者 DevOps 的最佳实践,可以关注文末的极狐GitLab 公众号。
学习极狐GitLab 的相关资料:
- 极狐GitLab 官网:https://gitlab.cn
- 极狐GitLab 官网文档:https://docs.gitlab.cn
- 极狐GitLab 论坛:https://forum.gitlab.cn/
- 极狐GitLab 安装配置:https://gitlab.cn/install
- 极狐GitLab 资源中心:https://resources.gitlab.cn
学习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)一起使用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。