Concourse CI 管道生成器实用程序。
项目描述
大厅套件 - 用于极端流水线
Concourse Kit 是一种高度自以为是的方法,用于在单个单一存储库中开发、生成、测试、验证和设置多个特定领域的 Concourse 管道。
它主要针对平台或基础架构团队,他们针对特定平台(如 Cloud Foundry、Kubernetes)进行维护、构建和自动化,或管理多个、大型和复杂的平台或工作流。
这些自动化工作负载通常共享大量通用数据、任务,并部署针对特定环境的同一管道的多个实例。
意见
- 生成 - 未声明:用于自动化整个平台的管道通常以数千行 YAML 结尾,并且可能会令人难以置信地重复。模板化 YAML 可能会变得非常棘手。Concourse Kit 指定管道是字面上的代码,并生成到所需的管道 YAML 中。
- 专注于 Python:管道以 Python 3.9 代码编写,鼓励所有任务使用 Python,原因如下:
- Python 比 Bash 脚本更具可读性。
- Python 比 Bash 脚本更易于测试。
- Python 足够强大,可以生成任何所需的管道配置。
- 与 Go 等语言相比,Python 更容易被更广泛的受众所接受。
- Mono Repo:在同一个域上运行的自动化应该包含在同一个 repo 中。这使得共享资源、任务、环境数据和常用脚本易于回收。
约定
Concourse Kit 指定要遵循的以下约定。
- 生成到管道配置中的代码应该在
pipelines - 测试管道配置的代码应该在
pipeline_tests - 特定于大厅环境的环境数据应在
concourse-environments - 特定于自动化目标的环境数据应在
target-environments - 使用
cc_kit.py脚本设置管道。
要求
要使用 Concourse Kit 启动和运行,您将需要以下内容。
- Python 3.9:您将需要安装 Python 3.9+,因为此 cck 使用联合运算符作为字典。
- fly CLI:您将需要安装 fly CLI,因为 concourse 套件会调用它来验证并为您设置管道。
- 开放的心态:是的,这是一种非常规的开发和管理管道的方法,但它可能已经足够疯狂了。
安装
pip install concoursekit
Concoursekit 是使用 pip 安装的。这将安装模块并使cckCLI 实用程序可用。
安装后,您可以运行以下命令来初始化 concoursekit 管理的新工作目录。
cck --init
这将.cck.yml在为 cck 提供一些基本配置默认值的目录中放置一个文件。
# The default concourse target to use
concourse_target: concourse
# These options are allowed.
# fly_default_options:
# - non-interactive | interactive
# - hide-pipeline | expose-pipeline
# - unpause-pipeline | pause-pipeline
# When Setting a Pipeline Fly will use these options
fly_default_options:
- interactive
- hide-pipeline
- unpause-pipeline
# The directory to import <pipeline_name>.py files from.
pipelines_dir: pipelines
# The directory to look for <pipeline_name>_test.py files from.
pipelines_test_dir: pipeline_tests
# The directory to use for target-environments
target_environments_dir: target_environments
命令行界面
该cck实用程序是进入大厅套件的入口点。它具有三个主要命令。
cck --gen-pipeline
从 pipeline.py 文件生成 pipeline.yml 文件。
cck --set-pipeline
调用 fly 以设置一个或多个管道。
cck --test-pipeline
为一个或多个管道运行 PyTest。用于测试管道配置结果。
上面的每个命令都可以采用以下参数。
cck --set-pipeline --name <pipeline_name> --env <env>
为特定环境设置特定管道。
cck --set-pipeline --name <pipeline_name> --all
为其范围内的所有目标环境设置一个特定的管道。
cck --set-pipeline --all
为每个管道范围内的所有目标环境设置所有管道。
cck --gen-pipeline --name <pipeline_name> --env <env>
pipeline.yml为特定环境的特定管道生成单个文件。
cck --test-pipeline --name <pipeline_name>
为特定管道运行 PyTest 测试。
cck --test-pipeline --all
为所有管道运行所有 PyTest 测试。
设置命令也可以带一个--plan标志。
cck --set-pipeline --name <pipeline_name> --all --plan
cck --set-pipeline --name --all --plan
显示管道名称、它们的源.py文件、它们将针对的环境并验证它们的配置。
环境
Concourse Kit 围绕目标环境的概念组织管道自动化。目标环境包含特定于一个或多个目标环境的所有变量和文件内容。从自动化的角度来看,自动化作业总是针对特定环境中的基础设施、API 或资源,因此得名target-environments.
为了使cckCLI 能够运行并生成或设置管道,您必须在该目录下声明至少一个环境target-environments目录。如何组织目标的示例可能如下所示:
target-environments
├───common
├───dev
│ ├───eu-dev
│ └───us-dev
├───prod
├───sandbox
└───stage
该concourse-environments目录应包含与部署大厅本身及其环境相关的数据和文件内容。这有助于将自动化数据与目标数据隔离开来。
生成管道配置
所有管道 YAML 配置都是生成的,而不是声明的或模板化的。要配置新管道,pipelines/<pipeline_name>.py必须创建一个新管道。
你好世界
这是大厅网站上记录的 Hello World 示例。
---
jobs:
- name: job
public: true
plan:
- task: simple-task
config:
platform: linux
image_resource:
type: registry-image
source: { repository: busybox }
run:
path: echo
args: ["Hello world!"]
要使用 cck 配置此管道,pipelines/hello_world.py需要创建一个新文件并包含以下内容。它必须pipeline_config有一个定义为返回的顶级函数dict。
def pipeline_config():
return {
"jobs": [
{
"name": "hello-world-job",
"plan": [
{
"task": "hello-world-task",
"config": {
"platform": "linux",
"image_resource": {
"type": "registry-image",
"source": {
"repository": "busybox"
}
},
"run": {
"path": "echo",
"args": ["hello world!"]
}
}
}
]
}
] # end jobs
}
要生成管道,请运行以下命令。即使在此示例中没有使用环境,generate 命令仍然需要它。
> cck --generate-pipeline --name hello_world --env dev
Generating Pipeline to hello_world.yml
这将生成与上图相同的 yaml。
使用环境
通常,如果您正在自动化基础架构或复杂平台,您将拥有一个针对一个或多个环境的管道。例如,如果您部署和管理 Kubernetes 集群,您可能希望为 dev、stage 和 prod 安装完全相同的集群,唯一的区别是变量、端点、证书等的环境特定值。
如果我们将我们pipeline.py视为一个函数,并将target-environment数据视为输入参数,我们可以为每个环境生成一个特定于环境的管道。
给定以下目标环境。
target-environments
├───dev
│ └───vars.yml
├───prod
| └───vars.yml
└───stage
└───vars.yml
并且在每个 vars.yml 文件中都有一个特定于环境的端点。
# target-environments/dev/vars.yml
api-endpoint: dev.api.some.target.foocorp.int
# target-environments/stage/vars.yml
api-endpoint: stage.api.some.target.foocorp.int
# target-environments/prod/vars.yml
api-endpoint: prod.api.some.target.foocorp.int
在pipelines/example.py文件中,我们的配置如下所示。请注意,Concourse Kit 使用 YAMLmaker 来帮助生成 YAML。您可以在此处阅读有关如何使用 YAMLmaker 的更多信息。
的值target-environment始终位于 os 环境变量下:ENVIRONMENT. 使用该ENVIRONMENT变量时,我们可以获取特定于我们为其生成配置的环境的变量。
from yamlmaker import Sources
from yamlmaker import env
def pipeline_config():
sources = Sources({
"vars": "target-environments/" + env("ENVIRONMENT") + "/vars.yml"
})
return {
"jobs": [
{
"name": "hello-world-job",
"plan": [
{
"task": "hello-world-task",
"config": {
"platform": "linux",
"image_resource": {
"type": "registry-image",
"source": {
"repository": "busybox"
}
},
"params": {
"API_ENDPOINT": sources.grab("vars", "api-endpoint")
},
"run": {
"path": "echo",
"args": ["hello world!"]
}
}
}
]
}
] # end jobs
}
生成管道.yml
> cck --generate-pipeline --name hello_world --env dev
Generating Pipeline to hello_world.yml
我们生成的配置现在看起来像这样,您可以看到使用了 dev 特定变量。
jobs:
- name: hello-world-job
plan:
- task: hello-world-task
config:
platform: linux
image_resource:
type: registry-image
source:
repository: busybox
params:
API_ENDPOINT: dev.api.some.target.foocorp.int
run:
path: echo
args:
- hello world!
该--generate命令一次只能为一个环境生成一个配置。--all生成管道配置时不能指定标志。
设置单个管道
您可以通过两种方式设置管道,第一种是普通fly方法并将生成的 yaml 文件作为管道配置传递。第二种方法是让您cck调用fly来为一个或多个环境设置管道。
设置飞行目标
要cck设置管道,首先设置一个fly目标,concourse如下所示:
fly -t concourse login -c http://localhost:8080 -u example -p example
如果您愿意,您可以针对不同的团队,在此示例中,它将仅使用该main团队。
设置管道
设置管道时,将生成并立即设置。pipeline.py管道的名称与下划线替换为破折号的文件相同。此外,target-environment是名称的前缀。
> cck --set-pipeline --name hello_world --env dev
Generating Pipeline to dev-hello-world.yml
Setting pipeline: dev-hello-world
jobs:
job hello-world-job has been added:
+ name: hello-world-job
+ plan:
+ - config:
+ image_resource:
+ source:
+ repository: busybox
+ type: registry-image
+ params:
+ API_ENDPOINT: dev.api.some.target.foocorp.int
+ platform: linux
+ run:
+ args:
+ - hello world!
+ path: echo
+ task: hello-world-task
apply configuration? [yN]:
为多个环境设置管道。
使用命令时指定--all标志--set-pipeline将尝试为所有环境设置管道,但在.cck.ymlunder中定义的除外ignore_environments: []。默认情况下,common已为您添加环境。
为此,每个人都target-environment必须具有所有相同的 var yaml 文件、内容文件等,否则管道将适用于某些环境,而不适用于其他环境。
> cck --set-pipeline --name hello_world --all
Generating Pipeline to dev-hello-world.yml
Setting pipeline: dev-hello-world
jobs:
job hello-world-job has been added:
+ name: hello-world-job
+ plan:
+ - config:
...
+ - hello world!
+ path: echo
+ task: hello-world-task
apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: http://localhost:8080/teams/main/pipelines/dev-hello-world
the pipeline is currently paused. to unpause, either:
- run the unpause-pipeline command:
fly -t concourse unpause-pipeline -p dev-hello-world
- click play next to the pipeline in the web ui
Generating Pipeline to prod-hello-world.yml
Setting pipeline: prod-hello-world
jobs:
job hello-world-job has been added:
+ name: hello-world-job
+ plan:
...
+ - hello world!
+ path: echo
+ task: hello-world-task
apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: http://localhost:8080/teams/main/pipelines/prod-hello-world
the pipeline is currently paused. to unpause, either:
- run the unpause-pipeline command:
fly -t concourse unpause-pipeline -p prod-hello-world
- click play next to the pipeline in the web ui
Generating Pipeline to stage-hello-world.yml
Setting pipeline: stage-hello-world
jobs:
job hello-world-job has been added:
+ name: hello-world-job
+ plan:
...
+ - hello world!
+ path: echo
+ task: hello-world-task
apply configuration? [yN]: y
pipeline created!
为所有环境设置,一个或多个环境除外
有时您可能希望设置所有环境,但其中一个或多个环境除外。为此,您可以通过在目标环境名称后面加上 bang 来否定特定环境!。
> cck --set-pipeline --name hello_world --all --env !sandbox
这将为除沙盒环境之外的所有环境设置。
将管道范围限定为特定环境。
很少有需要针对每个环境的管道,但是,管道需要针对多个特定环境的情况相当普遍。
要声明管道的目标,您可以像这样在文件target-environments中声明顶级变量 , 。pipeline_environmentspipelines/pipeline.py
from yamlmaker import Sources
from yamlmaker import env
pipeline_environments = [
"dev",
"stage"
]
def pipeline_config():
sources = Sources({
"vars": "target-environments/" + env("ENVIRONMENT") + "/vars.yml"
})
return {
"jobs": [
{
"name": "hello-world-job",
"plan": [
{
"task": "hello-world-task",
"config": {
"platform": "linux",
"image_resource": {
"type": "registry-image",
"source": {
"repository": "busybox"
}
},
"params": {
"API_ENDPOINT": sources.grab("vars", "api-endpoint")
},
"run": {
"path": "echo",
"args": ["hello world!"]
}
}
}
]
}
] # end jobs
}
当您再次cck使用该--all标志运行时,它只会为pipeline_environments列表中声明的环境设置管道。
> cck --set-pipeline --name hello_world --all
Generating Pipeline to dev-hello-world.yml
Setting pipeline: dev-hello-world
no changes to apply
Generating Pipeline to stage-hello-world.yml
Setting pipeline: stage-hello-world
no changes to apply
管道后缀
有时在管道名称的末尾添加标签或附加后缀以在使用许多管道时为其提供一些上下文会很方便。例如,您可能有一些处理平台操作的管道或一些处理安装或更新特定任务的管道。
您可以通过声明以下顶级变量来提供要应用于管道名称的后缀:pipeline_suffix.
pipeline_suffix = "operations"
def pipeline_config():
return {
"jobs": [
{
"name": "hello-world-job",
"plan": [
{
"task": "hello-world-task",
"config": {
"platform": "linux",
"image_resource": {
"type": "registry-image",
"source": {
"repository": "busybox"
}
},
"run": {
"path": "echo",
"args": ["hello world!"]
}
}
}
]
}
] # end jobs
}
> cck --set-pipeline --name hello_world --env dev
Generating Pipeline to dev-hello-world-operations.yml
Setting pipeline: dev-hello-world-operations
jobs:
...
+ task: hello-world-task
apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: http://localhost:8080/teams/main/pipelines/dev-hello-world-operations
the pipeline is currently paused. to unpause, either:
- run the unpause-pipeline command:
fly -t concourse unpause-pipeline -p dev-hello-world-operations
- click play next to the pipeline in the web ui
飞行选项
使用设置管道fly时,通常使用non-interactive选项运行它,或者立即隐藏、公开、暂停或取消暂停管道。为了使这更容易和解释,您可以指定一个名为的顶级变量fly_options = []
例如,管道将被配置为这样,当它被设置时,它不会与你确认,它会取消暂停,并自动隐藏它。
fly_options = [
"non-interactive",
"unpause-pipeline",
"hide-pipeline"
]
def pipeline_config():
...
> cck --set-pipeline --name foo_mgmt --end dev
Setting pipeline: dev-foo-mgmt
Generating Pipeline to dev-foo-mgmt.yml
no changes to apply
hid 'dev-foo-mgmt'
unpaused 'dev-foo-mgmt'
指定大厅目标
默认情况下,运行命令时cck将使用文件中指定的目标。如果要将管道设置为不同的目标,可以使用顶级变量。.cck.ymlflyconcourse_target = str
concourse_target = "my-cool-team"
def pipeline_config():
...
设置所有管道
如果您需要为所有环境重新设置所有管道(也许您必须重新部署大厅或恢复它们。)可以使用一个命令来执行此操作。
采取以下管道和环境。
├───concourse-environments
├───pipelines
│ ├───bar_mgmt.py
│ └───foo_mgmt.py
├───pipeline_tests
├───resources
├───target-environments
│ ├───common
│ ├───dev
│ ├───prod
│ └───stage
└───tasks
andbar_mgmt范围为devand stage,foo_mgmt范围为dev, stage, 和prod.
运行以下命令将为它们所限定的环境设置所有管道。 cck如果您错误地运行命令,会给您一个 10 秒的窗口来中止命令。
> cck --set-pipeline --all
Setting all pipelines in 10 seconds... ctl+c to cancel.
Generating Pipeline to dev-bar-mgmt-operations.yml
Setting pipeline: dev-bar-mgmt-operations
...
Generating Pipeline to stage-bar-mgmt-operations.yml
Setting pipeline: stage-bar-mgmt-operations
...
Generating Pipeline to dev-foo-mgmt-install.yml
Setting pipeline: dev-foo-mgmt-install
...
Generating Pipeline to stage-foo-mgmt-install.yml
Setting pipeline: stage-foo-mgmt-install
...
Generating Pipeline to prod-foo-mgmt-install.yml
Setting pipeline: prod-foo-mgmt-install
...
> fly -t concourse pipelines
name paused public last updated
dev-foo-mgmt-install yes no 2021-07-04 20:41:13 -0500 CDT
stage-foo-mgmt-install yes no 2021-07-04 20:41:14 -0500 CDT
prod-foo-mgmt-install yes no 2021-07-04 20:41:16 -0500 CDT
dev-bar-mgmt-operations yes no 2021-07-04 20:41:10 -0500 CDT
stage-bar-mgmt-operations yes no 2021-07-04 20:41:12 -0500 CDT
规划管道
在设置管道之前,最好在实际设置之前预览如何cck命名、设置和切换所有各种fly选项。此外,您可能希望确保您的配置从 Concourse 的角度来看是有效的,即使它从 Python 的角度来看也是有效的。
规划单一管道和目标环境
运行以下命令将显示单个管道和环境的计划。
> cck --set-pipeline --name foo_mgmt --env dev --plan
规划单个管道和所有目标环境
> cck --set-pipeline --name foo_mgmt --all --plan
规划所有管道和所有目标环境
以下是无效配置的示例,还显示了各种颜色!
> cck --set-pipeline --all --plan
计划期间的 Python 异常
有时,如果您正在开发配置并对其进行验证,您可能会遇到cck无法处理的 Python 异常。在这种情况下,cck将为您提供pipeline.py您正在处理的配置的回溯,就像这样,并为您提供ENVIRONMENT它试图为其生成的配置。
测试管道
因为所有管道cck管理都是生成的,所以有一个可以确保管道正确生成的伴随测试可能是一个好主意。
假设您有一个非常复杂的管道,其中包含特定于环境的作业或其他条件。您可以编写配套测试以确保在生成管道配置时它具有正确数量的作业等。您可以根据需要编写复杂或简单的测试,这取决于您。
测试单个管道
让我们为pipelines/foo_mgmt.py. 为此,我们在pipelines_tests/foo_mgmt_test.py.
#pipelines/foo_mgmt.py
from yamlmaker import env
from yamlmaker import Include
pipeline_suffix = "install"
pipeline_environments = [
"dev",
"stage",
"prod"
]
def pipeline_config():
return {
"jobs": [
{
"name": "foo-job-" + env("ENVIRONMENT"),
"plan": [
{
"task": "foo-task",
"config": {
"platform": "linux",
"image_resource": {
"type": "registry-image",
"source": {
"repository": "busybox"
}
},
"run": {
"path": "echo",
"args": ["for all envs"]
}
}
}
]
}
] + Include.when(env("ENVIRONMENT") == "dev", [
{
"name": "bar-job-" + env("ENVIRONMENT"),
"plan": [
{
"task": "bar-task",
"config": {
"platform": "linux",
"image_resource": {
"type": "registry-image",
"source": {
"repository": "busybox"
}
},
"run": {
"path": "echo",
"args": ["only in dev!"]
}
}
}
]
}
]) # end jobs
}
以下测试将验证在给定特定环境时是否定义了正确数量的作业。这是一个简单的示例,但您要测试或验证的内容取决于您生成的管道的复杂性。
#pipeline_tests/foo_mgmt_test.py
import os
from pipelines.foo_mgmt import pipeline_config
def test_dev_has_two_jobs():
os.environ["ENVIRONMENT"] = "dev"
config = pipeline_config()
assert len(config["jobs"]) == 2
def test_prod_has_one_job():
os.environ["ENVIRONMENT"] = "prod"
config = pipeline_config()
assert len(config["jobs"]) == 1
运行测试。
> cck --test-pipeline --name foo_mgmt
Testing Pipeline: foo_mgmt
================================================================================================= test session starts =================================================================================================
platform win32 -- Python 3.9.1, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: C:\Users\Anthony\workspace\concourse-kit
collected 2 items
pipeline_tests\foo_mgmt_test.py ..
======================================================================================================= PASSES ========================================================================================================
=============================================================================================== short test summary info ===============================================================================================
PASSED pipeline_tests/foo_mgmt_test.py::test_dev_has_two_jobs
PASSED pipeline_tests/foo_mgmt_test.py::test_prod_has_one_job
================================================================================================== 2 passed in 0.02s ==================================================================================================
测试所有管道
如果要验证所有管道都通过了测试,只需运行以下命令
> cck --test-pipeline --all
Testing All Pipelines
================================================================================================= test session starts =================================================================================================
platform win32 -- Python 3.9.1, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: C:\Users\Anthony\workspace\concourse-kit
collected 3 items
pipeline_tests\bar_mgmt_test.py .
pipeline_tests\foo_mgmt_test.py ..
======================================================================================================= PASSES ========================================================================================================
=============================================================================================== short test summary info ===============================================================================================
PASSED pipeline_tests/bar_mgmt_test.py::test_dev_has_two_jobs
PASSED pipeline_tests/foo_mgmt_test.py::test_dev_has_two_jobs
PASSED pipeline_tests/foo_mgmt_test.py::test_prod_has_one_job
================================================================================================== 3 passed in 0.03s ==================================================================================================