了解 DevSecOps 的库存
在 DevSecOps 中,库存充当构成软件系统的所有构建块的关键集中列表。 它成为在 IBM Cloud上安全地开发,部署和维护应用程序所需的所有信息的单一信息点。 以下是此库存中通常包含的内容:
-
IBM Cloud 资源: 这包括传递虚拟服务器,无服务器功能,Cloudant 数据库以及您在 IBM Cloud 环境中供应的任何其他服务。
-
基础结构即代码 (IaC) 详细信息: 这包括 Terraform 配置,存储在 IBM® Cloud Foundry Artifactory中的环境变量以及指示如何配置和保护 IBM Cloud 资源的其他设置。
-
应用程序依赖关系: 这些是第三方服务,API 和微服务,您的云应用程序依赖这些服务来正常运行。
-
IBM® Key Protect for IBM Cloud® 密钥: 这是指系统操作必需的敏感信息,例如密码,API 密钥和加密密钥。 这些需要在 IBM Key Protect中进行细致控制和安全存储。
清单的结构和内容
库存模型将跟踪工件的以下项:
- 工件的名称
- 它将部署到的环境或区域。
- 工件的构建位置 (管道运行,落实沙)
- 已构建工件的签名
在工件构建和部署期间跟踪证据。 这也有助于变更管理和合规性审计。
分支
库存在 Git 存储库 (存储库) 中实现。 Git 在跟踪和审计更改方面自给自足。
分支用作环境。 主分支 (master
) 由持续集成管道编写和更新。 其他环境通过使用促销从主分支进行更新。 有关促销的更多信息,请参阅 促销 部分。
库存内容
库存包含参与部署的每个工件的库存条目。 一个库存条目指向单个工件。 库存条目是可以在文件夹中构造并使用条目名称进行命名的 JSON 文件。
库存文件夹是条目名称的一部分。
示例
从以下条目名称列表中选择一个名称作为服务名称:
- 授权/服务
- auth/db
- 用户/服务
- main_service
- helm-charts/main_service
使用以下结构在清单中实现内容:
/
├── auth
│ ├── service
│ └── db
├── ui
│ └── service
├── helm-charts
│ └── main_service
└ main_service
库存条目格式
虽然 Entry
类型使用 typescript 语法表示库存条目的模式,但您可以将其转换为使用 JSON 模式。
interface Entry {
repository_url: string;
artifact: string;
build_number: number;
commit_sha: string;
name: string;
pipeline_run_id: string;
version: string;
app_artifacts: {
signature: string;
provenance: string;
[key: string]: any;
}
type: string;
sha256: string;
provenance: string;
signature: string;
}
示例
资产的图像类型的库存条目
{
"repository_url": "https://github.com/test-org/compliance-app-20201211", # source code repository url of the image artifact
"artifact": "us.icr.io/namespace/ hello-compliance-app:20201217081811-master-b85e3d472e9cc35b429c39e8c3f9eb282738c20a@sha256:da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0", # image artifact name, should be in a format like <static_name>:<version>@sha256:<sha256>
"build_number": 21, # pipeline build number
"commit_sha": "b85e3d472e9cc35b429c39e8c3f9eb282738c20a", # should be a proper git commit sha
"name": "hello-compliance-app", # name of the inventory entry file name
"pipeline_run_id": "f21321bf-9054-4bf3-80a8-4fb34743b7d9", # pipeline run id where artifact was built
"version": "v1", # version of the artifact
"app_artifacts": {}, # any additional information can be stored here
"type": "image",
"sha256": "da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0",
"provenance": "us.icr.io/namespace/hello-compliance-app:20201217081811-master-b85e3d472e9cc35b429c39e8c3f9eb282738c20a@sha256:da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0", # The fully qualified URL where artifact is stored, in case of image artifact, it is same as the artifact field
"signature": "owFNUX1IE3EY3vwAEy0VyoSJdkVWtu0+d3eTjNIIi0jETCSU3353cz+83V23myi2BlFgYiUFqSmZLciUzCJkRYJp9IEWFWXB0hAyrBQxEjIIuhFSf70vL8/7vM/zPi3JsaYEc+TnbqG8qrnTPDZ8w2WqiqwtacCghnQEgYQ5GzAkiLKO9PpoLyiwRtSsmugWNVGGIubE/D4bgpoNKXag60gCdo8oSYoVKl5VQsDAWIGqOkmcxAmSYHGO4AjC6gU+3eBxcYxICTRLijyEFOOiSR5SvMhBys2LLpIjWYqDJA6wwHYMeUG1+J8GL5CRW/TpVgFVG8VQ4vMAknE4BUA5OIoQGIKhKZwFkIeAdnECj+OCmxQADh2QoFmG5lkWUiTN8gJ0kDxPuxiWJAU8ekyvV6PegK54EcyGiqwDJItatg9Vy0D3a2IUpKg6UuS/T4KaaIC1fzuMDbfhmMGEvIY64FUxJ+Ew3PMU5SADgdNmKs5kTjBlrtsQ99iyY49nns8o6jsXWgkjPiYahClxVcrK5Flngumz2j7YdmD0ecutytsvxxNPHflKlRV2RyqD69NjC6Smji9XuukFyZ+lvM18gUr7F4NXge9YyZPik411tc1n9bKO/hDz7oGaX/ur94OnNHiwOG6n5ZsrsCsvtyvmkH4zOWlrRWuL7fzgj9zlcCTAhtu2LbeGLNfv3Ju0Jc9PZPk7Pm3Ov2CW+2xj8ReX6ooGamZ610yqRM/+8Qo2XnOeyZzbVKgs+f2+9unpJOve4Tmla+PdqftDWkHPm9Vq3nsyZ2DUkmP/nTb7qNw5l2SfWtiSemJx9nLaYOpx6amlOT18aeIwJQhHg1XOjJF9r18NXQvPuL9rH5tSQqbGhyN/AA==" # The signature of the artifact
}
非映像类型资产的库存条目,例如部署和 Helm 图表
{
"repository_url": "https://github.com/test-org/compliance-app-20201211", # source code repository url of the artifact
"artifact": "deployment.yaml", # artifact name, should not be changed in every build
"build_number": 21, # pipeline build number
"commit_sha": "b85e3d472e9cc35b429c39e8c3f9eb282738c20a", # should be a proper git commit sha
"name": "hello-compliance-app-deployment", # name of the inventory entry file name
"pipeline_run_id": "f21321bf-9054-4bf3-80a8-4fb34743b7d9", # pipeline run id where artifact was built
"version": "v1", # version of the artifact
"app_artifacts": {}, # any additional information can be stored here
"type": "type", # type of the artifact
"sha256": "da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0", # sha256 of the artifact
"provenance": "https://raw.github.ibm.com/org/my-app/commit-1/deployment.yaml", # The fully qualified URL where artifact is stored
"signature": "owFNUX1IE3EY3vwAEy0VyoSJdkVWtu0+d3eTjNIIi0jETCSU3353cz+83V23myi2BlFgYiUFqSmZLciUzCJkRYJp9IEWFWXB0hAyrBQxEjIIuhFSf70vL8/7vM/zPi3JsaYEc+TnbqG8qrnTPDZ8w2WqiqwtacCghnQEgYQ5GzAkiLKO9PpoLyiwRtSsmugWNVGGIubE/D4bgpoNKXag60gCdo8oSYoVKl5VQsDAWIGqOkmcxAmSYHGO4AjC6gU+3eBxcYxICTRLijyEFOOiSR5SvMhBys2LLpIjWYqDJA6wwHYMeUG1+J8GL5CRW/TpVgFVG8VQ4vMAknE4BUA5OIoQGIKhKZwFkIeAdnECj+OCmxQADh2QoFmG5lkWUiTN8gJ0kDxPuxiWJAU8ekyvV6PegK54EcyGiqwDJItatg9Vy0D3a2IUpKg6UuS/T4KaaIC1fzuMDbfhmMGEvIY64FUxJ+Ew3PMU5SADgdNmKs5kTjBlrtsQ99iyY49nns8o6jsXWgkjPiYahClxVcrK5Flngumz2j7YdmD0ecutytsvxxNPHflKlRV2RyqD69NjC6Smji9XuukFyZ+lvM18gUr7F4NXge9YyZPik411tc1n9bKO/hDz7oGaX/ur94OnNHiwOG6n5ZsrsCsvtyvmkH4zOWlrRWuL7fzgj9zlcCTAhtu2LbeGLNfv3Ju0Jc9PZPk7Pm3Ov2CW+2xj8ReX6ooGamZ610yqRM/+8Qo2XnOeyZzbVKgs+f2+9unpJOve4Tmla+PdqftDWkHPm9Vq3nsyZ2DUkmP/nTb7qNw5l2SfWtiSemJx9nLaYOpx6amlOT18aeIwJQhHg1XOjJF9r18NXQvPuL9rH5tSQqbGhyN/AA==" # The signature of the artifact
}
使用 cocoa inventory add 命令可写入库存。
库存工作流程
库存包含除 master
分支以外的多个分支。 这些分支可以表示部署阶段,环境或区域,或两者的混合。 这些分支的结构取决于设置和使用情况。
CI 写入库存
master
分支通过连续集成构建进行填充。 目标中的最后一个落实 (在本例中名为 staging
) 包含一个标记,该标记显示它是最后完成的部署。
如果将库存的缺省分支切换到其他分支,那么必须将先前缺省分支中的落实重定基底到新的缺省分支,以使 Git 落实历史记录具有线性关系。
您可以通过定制发布脚本来跳过写入库存。 有关更多信息,请参阅 发布到库存。
促销
当您提升到目标分支时,将创建拉取请求。 拉取请求内容将填充“变更请求”字段。 复审拉取请求后,可以将其合并。
增量和部署
合并提升拉取请求后,可以启动部署管道。 部署增量是上次完成的部署的内容与当前部署的内容之间的差异。 部署增量列出了正在部署的库存项。
库存结论
部署完成后,可以提前移动 latest
标记。
在 dev 方式触发器期间,将不会对标记进行高级操作。 开发方式触发器仅用于测试 CD 管道。
升级到更多环境
您可以从任何分支升级并部署到另一个分支。
库存情况
当前已部署状态包含要部署到环境的内容。 目标分支中的每个提升的落实都包含相关管道运行标识和变更请求标识作为标记。 某些落实可以具有多个标记,例如,当您重试失败的部署或再次部署时。 “库存”保存用于重放部署的每一条信息。
设置具有多个区域的单个目标
针对单个目标环境引入了多个 latest
标记,以便针对不同类型的用例,多个连续部署管道可以在同一目标上工作。 例如,可以将同一目标环境 (例如 us-south
或 eu-de
) 用于生产目标环境和库存分支中的多个区域。
您不需要使用 region
属性 (例如 us-south-prod
和 eu-de-prod
) 为每个区域设置不同的分支,并以冗余方式运行提升。 请改为为同一库存分支指定这些附加目标,然后将其用作 Git 标记。
在此设置中,生产分支在同一分支上具有多个 latest
标记,例如 us-south_prod_latest
和 eu-de_prod_latest
。 负责每个区域的每个持续部署管道都可以使用这些标记进行部署。
例如,您计划在任何地方部署的一组更改可能会首先发布到单个区域,然后通过使用连续部署管道将这些区域作为目标逐步部署到其他区域。
库存操作
清单包含一些使用 CLI 或使用纯 Git 和 GitHub CLI 运行的基本操作。
CLI 命令
-
在登台中创建从主分支到目标分支的提升拉取请求。
cocoa inventory promote \ --source="master" \ --target="staging" \ --priority="moderate" \ --assigned-to="assignee@ibm.com" \ --description="Change description" \ --purpose="Change purpose" \ --impact="Change impact" \ --backout-plan="Details on backout and rollback")
-
通过将
target_latest
标记移动到与pipeline-run-id
标记相同的落实来完成部署。cocoa inventory label move \ --to-label="${PIPELINE_RUN_ID}" \ "target_latest"
Git 和 GitHub CLI
-
在登台中创建从主分支到目标分支的提升拉取请求。
promote() { if [ -z $1 ] || [ -z $2 ]; then echo "Missing source and target" exit 1 fi local source="$1" local target="$2" if ! git show-ref "refs/remotes/origin/$target"; then # Create a new target branch, from the beginning of master git checkout master git checkout -b "$target" $(git rev-list --max-parents=0 HEAD) git_push fi git checkout "$source" git pull --rebase # Create a promotion branch for the PR # this can be discarded after the Promotion PR merge git checkout -b "promote-$source-to-$target" git push --set-upstream origin "promote-$source-to-$target" # Create PR from promotion branch to target branch gh pr create \ --base "$target" \ --head "promote-$source-to-$target" \ --title "Promote $source to $target" \ --body "" \ --repo "https://github.com/org/inventory-repository" # promotion branch can be deleted once the PR was merged } $ promote master staging
-
通过将
target-latest
标记移动到与pipeline-run-id
标记相同的落实来完成部署。conclude () { local target="$1" local tag="$2" latest="$1-latest" # remove the latest tag git push origin ":refs/tags/$latest" # find the commit hash of the target tag sha=$(git rev-list -n 1 $tag) # add the latest tag to the same commit of the target tag git tag -fa "$latest" -m "" $sha git push --tags --force } $ conclude staging pipeline-run-fe33b05c
-
使用 Git 和 GitHub CLI 将登台还原为较早状态。
revert () { local branch="$1" local commit="$2" # create a revert branch from the target branch git checkout "$branch" git pull --rebase git checkout -b "$branch-revert" # revert commits since the target commit, then commit and push git revert -n $(git rev-list --no-merges HEAD...$commit) git commit -m "revert $branch to $commit" git push --set-upstream origin "$branch-revert" # create PR from revert branch to the target branch gh pr create \ --base "$branch" \ --head "$branch-revert" \ --title "Revert $branch to $commit" \ --body "" \ --repo "$REPO" # revert branch can be deleted once the PR was merged } $ revert staging ba3b8e5ed3320e6b4981077e1a1627f08de4f511
使用 Git 存储库的常见用例
有关使用 Git 存储库的更多信息,请参阅以下示例场景:
如何排除库存中的文件和目录
一-缺省情况下,管道会排除库存中的隐藏文件和 .md
文件。 在库存存储库中创建名为 .inventoryignore
的文件以排除任何文件或目录。 管道将在存储库的根目录中搜索 .inventoryignore
文件。 但是,如果您希望库存排除文件使用其他名称,那么可以通过将 inventory-ignore-file
键设置为管道中的环境属性来指定该名称。 请确保此文件位于库存存储库的根目录中。
例如,如果您的文件名为 .custominventoryignore
,请添加值为 custominventoryignore
的环境变量 inventory-ignore-file
。
以下是 .custominventoryignore
文件的示例内容:
.md
sample_file
sample_directory/
```
In the file before this:
- `.md`: Excludes all files with the `.md` extension. Do not add `*` at the start, like `*.md`, as regex is not supported.
- `sample_file`: Excludes the specific file throughout the entire repository.
- `sample_directory/`: Excludes the entire directory. Avoid adding `*` at the end, use `sample_directory/*`, as regex is not supported.
<!-- v2.2 : caits-prod-app-clouddocs_cloud-docs-devsecops_20240606T060629-11_en_zh-Hans -->