连续集成 continuous integration （CI）是指代码变更会被自动构建和测试。以下是我为自己的 C++ 项目构建 CI 流水线的过程。本文介绍如何在 GitLab 上配置 CI 流水线。我在前面的文章中介绍了 基于 CMake 和 VSCodium 的构建系统 和 基于 GoogleTest 和 CTest 的单元测试。本文将在此基础上进一步配置 CI 流水线。我会先演示如何布设和运行 CI 流水线，然后再介绍如何配置它。CI 是指提交到代码仓库的代码变更会被自动构建和测试。在开源领域，GitLab 是一个流行的 CI 流水线平台。除了作为中心 Git 仓库外，GitLab 还提供 CI/CD 流水线、 问题跟踪 issue tracking 和 容器注册表 container registry 功能。相关术语在进入正题之前，我先介绍在本文和 GitLab 文档 中会遇到的常见术语。 持续交付 continuous delivery （CD）：自动化供应软件，以供随时交付 持续部署 continuous deployment （CD）：自动化软件发布 流水线 pipeline : CI/CD 的直接构件，它由阶段和作业构成 阶段 stage ：一组作业 作业 job ：某项需要执行的具体任务，比如编译、单元测试等 执行器 runner ：实际执行作业的服务布设 CI 流水线在下面的章节中，我将复用以前的 示例工程。点击 GitLab 仓库页面右上角的 复刻 Fork 按钮复刻代码仓库。设置执行器为了让你对整个流程有所了解，我们先从在本地安装执行器讲起。参照执行器服务 安装指南 安装好服务，然后注册执行器。1、选择 GitLab 项目页面左侧的 设置 Settings ，再选择 CI/CD。2、展开 执行器 Runners 区域，关闭 共享的执行器 Shared runners 选项（黄框处）。特别注意令牌和 URL（绿框处），下一步会用到它们。3、在终端中运行 gitlab-runner register，根据提示输入以下注册信息：GitLab 实例: https://gitlab.com/ （如上图）注册令牌：从执行器区域中获取 （如上图）描述：按需自由填写标签：可以不填执行环境：选 Shell如果有需要，你可以在 ~/.gitlab-runner/config.toml 中修改这些配置。4、用命令 gitlab-runner run 启动执行器。你可以在 GitLab 的项目设置界面执行器区域看到执行器的状态：运行流水线前面已经提过，流水线就是一组由执行器执行的作业。每个推送到 GitLab 的提交都会生成一个附加到该提交的流水线。如果多个提交被一起推送，那么只会为最后一个提交生成流水线。为了演示，我直接在 GitLab 在线编辑器中提交和推送修改。打开 README.md 文件，添加一行数据：现在提交修改。这里注意默认的行为是为提交新建一个分支，为了简便起见，我们择提交到主分支。提交后一会儿后，你就应该改能看到 GitLab 执行器执行的控制台中有输出消息：Checking for jobs... received job=1975932998 repo_url=<https://gitlab.com/hANSIc99/cpp\_testing\_sample.git> runner=Z7MyQsA6 Job succeeded duration_s=3.866619798 job=1975932998 project=32818130 runner=Z7MyQsA6 在 GitLab 项目概览界面左侧选择 CI/CD --> 管道 Pipelines ，查看最近执行的流水线：选中流水线可以在详情界面看到哪些作业失败了，并能查看各个作业的输出。当遇到非零返回值是就认为作业执行失败了。在下面的例子中我通过调用 exit 1 强制让作业执行失败：CI 配置阶段、流水线和作业的配置都在仓库根目录的 .gitlab-ci.yml 文件中。我建议使用 GitLab 内置的流水线编辑器，它会自动对配置进行检查。stages: - build - test build: stage: build script: - cmake -B build -S . - cmake --build build --target Producer artifacts: paths: - build/Producer RunGTest: stage: test script: - cmake -B build -S . - cmake --build build --target GeneratorTest - build/Generator/GeneratorTest RunCTest: stage: test script: - cmake -B build -S . - cd build - ctest --output-on-failure -j6 文件中定义了两个阶段：build 和 test，以及三个作业：build、RunGTest 和 RunCTest。其中作业 build 属于一个同名的阶段，另外两个作业属于阶段 test。script 小节下的命令就是一般的 Shell 命令。你可以认为是将它们逐行输入到 Shell 中。我要特别提及 产物artifact 这个特性。在示例中我定义了二进制的 Producer 为作业 build 的产物。产物会被上传到 GitLab 服务器，并且可以从服务器的这个页面上被下载：默认情况下，后续阶段的作业会自动下载先前阶段作业生成的所有产物。你可以在 docs.gitlab.com 上查看 gitlab-ci.yml 参考指南。总结上面只是一个最基本的例子，让你对持续集成的一般原则有一个了解。再演示中我禁用了共享执行器，然而这才是 GitLab 的优势所在。你可以在一个干净的容器化的环境中构架、测试和部署程序。除了使用 GitLab 提供的免费执行器，你也可以用自己的容器作为执行器。当然还有更高阶的用法：用 Kubernetes 来协调调度执行者容器，让流水线适应大规模使用的使用场景。如需进一步了解，可以查看 about.gitlab.com。如果你使用的是 Fedora，需要注意的一点是目前 GitLab 执行者还不支持用 Podman 作为容器引擎。（LCTT 译注：Podman 是 Fedora 自带的容器引擎。）根据 议题 issue #27119，对 Podman 支持已将列上日程。（LCTT 译注：Podman 4.2 及以上版本增加了对于 GitLab 执行器的支持。）把重复性的操作描述成作业，并将作业合并成流水线和阶段，可以让你跟踪它们的质量而不增加额外工作。。特别是在大型社区项目中，适当配置的 CI 可以告诉你提交的代码是否对项目有改善，为你接受或拒绝合并请求提供依据。（题图：MJ/fb711c48-251a-4726-a41c-247370e5df25）via: https://opensource.com/article/22/2/setup-ci-pipeline-gitlab作者：Stephan Avenwedde 选题：lujun9972 译者：toknow-gh 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
对齐部署镜像和描述符是很困难的，但是某些策略可以使整个过程更高效。在软件架构中，当两个组件之间有某些概念性或技术上的差异时会出现 阻抗失配 impedance mismatch 。这个术语其实是从电子工程中借用的，表示电路中输入和输出的电子阻抗必须要匹配。在软件开发中，存储在镜像仓库中的镜像与存储在源码控制管理系统（LCTT 译注：SCM，Source Code Management）中它的 部署描述符 deployment descriptor 之间存在阻抗失配。你如何确定存储在 SCM 中的部署描述符表示的是正确的镜像？两个仓库追踪数据的方式并不一致，因此将一个镜像（在镜像仓库中独立存储的不可修改的二进制）和它的部署描述符（Git 中以文本文件形式存储的一系列修改记录）相匹配并不那么直观。注意：本文假定读者已经熟悉以下概念： 源码控制管理 Source Control Management （SCM）系统和分支Docker 或符合 OCI 标准的镜像和容器 容器编排系统 Container Orchestration Platforms （COP），如 Kubernetes 持续集成/持续交付 Continuous Integration/Continuous Delivery （CI/CD） 软件开发生命周期 Software development lifecycle （SDLC）环境阻抗失配：SCM 与镜像仓库为了更好地理解阻抗失配在什么场景下会成为问题，请考虑任意项目中的软件开发生命周期环境（SDLC），如开发、测试或发布环境。测试环境不会有阻抗失配。现在使用 CI/CD 的最佳实践中开发分支的最新提交都会对应开发环境中的最新部署。因此，一个典型的、成功的 CI/CD 开发流程如下：向 SCM 的开发分支提交新的修改新提交触发一次镜像构建新生成的镜像被推送到镜像仓库，标记为开发中镜像被部署到容器编排系统（COP）中的开发环境，该镜像的部署描述符也更新为从 SCM 拉取的最新描述符。换句话说，开发环境中最新的镜像永远与最新的部署描述符匹配。回滚到前一个构建的版本也不是问题，因为 SCM 也会跟着回滚。最终，随着开发流程继续推进，需要进行更多正式的测试，因此某个镜像 —— 镜像对应着 SCM 中的某次提交 —— 被推到测试环境。如果是一次成功的构建，那么不会有大问题，因为从开发环境推过来的镜像应该会与开发分支的最新提交相对应。开发环境的最新部署被允许入库，触发入库过程最新部署的镜像被标记为测试中镜像在测试环境中被拉取和部署，（该镜像）对应从 SCM 拉取的最新部署描述符到目前为止,一切都没有问题，对吗？如果出现下面的场景，会有什么问题？场景 A：镜像被推到下游环境，如 用户验收测试 user acceptance testing （UAT），或者是生产环境。场景 B：测试环境中发现了一个破坏性的 bug，镜像需要回滚到某个确定正常的版本。在任一场景中，开发过程并没有停止，即开发分支上游有了一次或多次新的提交，而这意味着最新的部署描述符已经发生了变化，最新的镜像与之前部署在测试环境中的镜像不一致。对部署描述符的修改可能会也可能不会对之前版本的镜像起作用，但是它们一定是不可信任的。如果它们有了变化，那么它们就一定与目前为止你测试过的想要部署的镜像的部署描述符不一致。问题的关键是：如果部署的镜像不是镜像库中的最新版本，你怎么确定与部署的镜像相对应的是 SCM 中的哪个部署描述符？ 一言以蔽之，无法确定。两个库直接有阻抗失配。如果要详细阐述下，那么是有方法可以解决的，但是你需要做很多工作，这部分内容就是文章接下来的主题了。请注意，下面的方案并不是解决问题的唯一办法，但是已经投入到生产环境并已经对很多项目起了作用，而且已经被构建并部署到生产环境中运行了超过一年。二进制与部署描述符源码通常被构建成一个 Docker 镜像或符合 OCI 标准的镜像，该镜像通常被部署到一个容器编排平台（COP）上，如 Kubernetes。部署到 COP 需要部署描述符来定义镜像被如何部署以及作为容器运行，如 Kubernetes 部署 或 CronJobs。这是因为在镜像和它的部署描述符之间有本质差异，在这里可以看到阻抗失配。在这次讨论中，我们认为镜像是存储在镜像仓库中不可修改的二进制。对源码的任何修改都不会修改镜像，而是用另一个新的镜像去替换它。相比之下，部署描述符是文本文件，因而可以被认为是源码且可修改。如果遵循最佳实践，那么部署描述符是被存储在 SCM，所有修改都会提交，而这很容易回溯。解决阻抗失配建议的解决方案的第一部分，就是提供一个能匹配镜像仓库中的镜像与对保存部署描述符的 SCM 做的代码提交的方法。最直接的解决方案是用源提交的哈希值标记镜像。这个方法可以区分不同版本的镜像、容易分辨，并且提供足够的信息来查找正确的部署描述符，以便镜像更好地部署到 COP。再回顾下上面的场景：场景 A 镜像被推到下游环境： 当镜像被从测试环境推到 UAT 环境时，我们可以从镜像的标签中知道应该从 SCM 的哪一次源码提交拉取部署描述符。场景 B 当一个镜像需要在某一环节中回滚：无论我们选择回滚到那个镜像版本，我们都可以知道从 SCM 的哪一次源码提交拉取正确的部署描述符。在每一种情景中，无论在某个镜像被部署到测试环境后开发分支有多少次提交和构建，对于每一次升级的镜像，我们都可以找到它当初部署时对应的部署描述符。然而，这并不是阻抗失配的完整解决方案。再考虑两个场景：场景 C 在负载测试环境中，会尝试对不同的部署描述符进行多次部署，以此来验证某一次构建的表现。场景 D 一个镜像被推送到下游环境，在该环境中部署描述符有一个错误。在上面的所有场景中，我们都需要修改部署描述符，但是目前为止我们只有一个源码提交哈希。请记住，最佳实践要求我们所有对源码的修改都要先提交到 SCM。某次提交的哈希本身是无法修改的，因此我们需要一个比仅仅追踪原来的源码提交哈希更好地解决方案。解决方案是基于原来的源码提交哈希新建一个分支。我们把这个分支称为部署分支。每当一个镜像被推到下游测试或发布环境时，你应该基于前一个 SDLC 环境的部署分支的最新提交创建一个新的部署分支。这样同一个镜像可以重复多次部署到不同的 SDLC 环境，并在后面每个环境中可以感知前面发现的改动或对镜像做的修改。注意： 在某个环境中做的修改是如何影响下一个环境的，是用可以共享数据的工具（如 Helm Charts）还是手动剪切、粘贴到其他目录，都不在本文讨论的范围内。因此，当一个镜像被从一个 SDLC 环境中推到下一环境时：创建一个部署分支如果镜像是从开发环境中推过来的，那么部署分支就基于构建这个镜像的源码提交哈希创建否则，部署分支基于当前部署分支的最新提交创建镜像被部署到下一个 SDLC 环境，使用的部署描述符是该环境中新创建的部署分支的部署描述符图 1：部署分支树部署分支下游环境的第一个部署分支，只有一次提交下游环境的第二个部署分支，只有一次提交有了部署分支这个解决方案，再回顾下上面的场景 C 和场景 D：场景 C 修改已经部署到下游 SDLC 环境中的镜像的部署描述符场景 D 修复某个 SDLC 环境中部署描述符的错误两个场景中，工作流如下：把对部署描述符做的修改提交到 SLDC 环境和镜像对应的部署分支通过部署分支最新提交对应的部署描述符把镜像重新部署到 SLDC 环境这样，部署分支彻底解决了（存储着代表一次独一无二的构建的单一的、不可修改的镜像的）镜像仓库与（存储着对应一个或多个 SDLC 环境的可修改的部署描述符的）SCM 仓库之间的阻抗失配。实践中的思考这看起来像是行得通的解决方案，但同时它也为开发者和运维人员带来了新的实践中的问题，比如：A. 为了更好地管理部署分支，部署描述符作为资源应该保存在哪里，是否要与构建镜像的源码保存在同一个 SCM 仓库？到目前为止，我们都在避免谈论应该把部署描述符放在哪个仓库里。在还没有太多细节需要处理时，我们推荐把所有 SDLC 环境的部署描述符与镜像源码放在同一个 SCM 仓库。当部署分支创建后，镜像的源码可以作为方便找到部署的容器中运行的镜像的引用来使用。上面提到过，可以通过镜像的标签来关联镜像与原始的源码提交。在一个单独的仓库中查找某次提交的源码的引用，会给开发者带来更大的困难（即便借助工具），这就是没有必要把所有资源都分开存储的原因。B. 应该在部署分支上修改构建镜像的源码吗？简答：不应该。详细阐述：不应该，因为永远不要在部署分支上构建镜像，它们是在开发分支上构建的。修改部署分支上定义一个镜像的源码会破坏被部署的镜像的构建记录，而且这些修改并不会对镜像的功能生效。在对比两个部署分支的版本时这也会成为问题。这可能会导致两个版本的功能差异有错误的测试结果（这是使用部署分支的一个很小的额外好处）。C. 为什么使用镜像 标签 tag ？ 标记 label 不可以吗？通过 标签 tag 可以在仓库中很容易地查找镜像，可读性也很好。在一组镜像中读取和查找 标记 label 的值需要拉取所有镜像的 清单文件 manifest ，而这会增加复杂度、降低性能。而且，考虑到历史记录的追踪和不同版本的查找，对不同版本的镜像添加 标签 tag 也很有必要，因此使用源码提交哈希是保证唯一性，以及保存能即时生效的有用信息的最简单的解决方案。D. 创建部署分支的最佳实践是怎样的？DevOps 最重要的三个原则：自动化、自动化、自动化。依赖资源来持续地强迫遵循最佳实践，充其量只是碰运气，因此在实现镜像的升级、回滚等 CI/CD 流水线时，把自动化部署分支写到脚本里。E. 对部署分支的命名规范有建议吗？<部署分支标识>-<环境>-<源码提交哈希>部署分支标识： 所有部署分支范围内唯一的字符串；如 “deployment” 或 “deploy”环境： 部署分支适用的 SDLC 环境；如 “qa”（测试环境）、 “stg”（预生产环境）、 或 “prod”（生产环境）源码提交哈希： 源码提交哈希中包含原来构建被部署的镜像的源码，开发者可以通过它很容易地查找到创建镜像的原始提交，同时也能保证分支名唯一。例如， deployment-qa-asdf78s 表示推到 QA 环境的部署分支， deployment-stg-asdf78s 表示推到 STG 环境的部署分支。F. 你怎么识别环境中运行的哪个镜像版本？我们的建议是把最新的部署分支提交哈希和源码提交哈希添加到 标记 中。开发者和运维人员可以通过这两个独一无二的标识符查找到部署的所有东西及其来源。在诸如执行回滚或前滚操作时，使用那些不同版本的部署的选择器也能清理资源碎片。G. 什么时候应该把部署分支的修改合并回开发分支？这完全取决于开发团队。如果你修改的目的是为了做负载测试，只是想验证什么情况会让程序崩溃，那么这些修改不应该被合并回开发分支。另一方面，如果你发现和修复了一个错误，或者对下游环境的部署做了调整，那么就应该把部署分支的修改合并回开发分支。H. 有现成的部署分支示例让我们试水吗？el-CICD 已经在生产上使用这个策略持续一年半应用到超过一百个项目了，覆盖所有的 SDLC 环境，包括管理生产环境的部署。如果你可以访问 OKD、Red Hat OpenShift lab cluster 或 Red Hat CodeReady Containers，你可以下载el-CICD 的最新版本，参照 教程 来学习部署分支是何时以怎样的方式创建和使用的。结语通过实践上面的例子可以帮助你更好的理解开发过程中阻抗失配相关的问题。对齐镜像和部署描述符是成功管理部署的关键部分。via: https://opensource.com/article/21/8/impedance-mismatch-cicd作者：Evan "Hippy" Slatis 选题：lujun9972 译者：lxbwolf 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
GitHub Actions 是一项为快速建立持续集成和交付（CI/CD）工作流程而提供的服务。这些工作流程在被称为“ 运行器 runner ”的主机上运行。GitHub 提供的 托管运行器 的操作系统的选择是有限的（Windows Server、Ubuntu、MacOS）。另一个选择是使用 自托管 的运行器，这让仓库管理员对运行器有更多控制。自托管的运行程序是专门为某个存储库或组织服务的。下面的文章介绍了使用 Fedora CoreOS 配置自托管运行程序的步骤。入门Fedora CoreOS 是一个精简的操作系统，旨在便于大规模的部署和维护。该操作系统会自动更新，并默认提供运行容器所需的工具。由于这些原因，Fedora CoreOS 是运行 CI/CD 工作流程的一个极佳选择。配置和配备 Fedora CoreOS 机器的第一步是生成一个 Ignition 文件。Butane 允许你使用更友好的格式（YAML）生成 Ignition 文件。配置一个 Fedora CoreOS 运行器要在 Fedora CoreOS 上执行 GitHub Actions，托管主机需要用于注册和运行该运行器的二进制文件和脚本。从 Actions 运行器项目 下载二进制文件和脚本，并部署在 /usr/local/sbin/actions-runner 下。version: "1.3.0" variant: fcos storage: directories: - path: /usr/local/sbin/actions-runner mode: 0755 user: name: core group: name: core files: - path: /usr/local/sbin/actions-runner/actions-runner-linux.tar.gz overwrite: true contents: source: https://github.com/actions/runner/releases/download/v2.278.0/actions-runner-linux-x64-2.278.0.tar.gz mode: 0755 user: name: core group: name: core 注册和删除令牌为一个项目配置运行器需要一个“ 令牌 token ”。这可以防止在没有正确权限的情况下从项目中注册或删除自托管的运行器。GitHub 提供的令牌有一个小时的过期时间。如果运行器在这个时间之后重新启动，它将需要一个新的注册令牌。该令牌可能出问题，特别是在 Fedora CoreOS 自动更新时。更新过程希望托管主机在收到新数据后至少每隔几周重启一次。幸运的是，可以使用 GitHub REST API 来获取这些令牌，并在托管主机每次重启时自动配置运行器。下面的 manage-runner.sh 脚本使用 API 来获取令牌，删除任何已经配置好的运行器，并用新的令牌注册运行器。#!/bin/bash # Handles the Github Action runner configuration. # Remove and Registration token expires after 1 hour, if we want our runner # to work after a reboot (auto update) we need to refresh the tokens. # First remove the runner with a fresh remove token REMOVE_TOKEN=$(curl -u ${GITHUB_USER}:${GITHUB_TOKEN} -X POST -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/actions/runners/remove-token | jq -r '.token') /usr/local/sbin/actions-runner/config.sh remove --token ${REMOVE_TOKEN} # Then register the runner with a fresh registration token REGISTRATION_TOKEN=$(curl -u ${GITHUB_USER}:${GITHUB_TOKEN} -X POST -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/actions/runners/registration-token | jq -r '.token') /usr/local/sbin/actions-runner/config.sh --url https://github.com/cverna/fcos-actions-runner --token ${REGISTRATION_TOKEN} --labels fcos --unattended 上面的脚本使用了一些环境变量，包含 GitHub 用户名和用于验证 REST API 请求的 个人访问令牌 Personal Access Token 。个人访问令牌需要存储库权限，以便成功检索运行器的注册和移除令牌。该令牌是安全敏感信息，所以最好将其存储在一个具有更严格权限的不同文件中。在这个例子中，这个文件是 actions-runner。GITHUB_USER=<user> GITHUB_REPO=<repo> GITHUB_TOKEN=<personal_access_token> 以下是创建这两个文件 manage-runner.sh 和 actions-runner 的 Butane 片段。- path: /usr/local/sbin/actions-runner/manage-runner.sh contents: local: manage-runner.sh mode: 0755 user: name: core group: name: core - path: /etc/actions-runner contents: local: actions-runner mode: 0700 user: name: core group: name: core 在 Fedora CoreOS 上运行 Actions最后，创建用于配置和启动运行器的 systemd 服务。在 Butane 配置文件中定义这些服务。systemd: units: - name: github-runner-configure.service enabled: true contents: | [Unit] Description=Configure the github action runner for a repository After=network-online.target boot-complete.target Requires=boot-complete.target [Service] EnvironmentFile=/etc/actions-runner Type=oneshot RemainAfterExit=yes User=core WorkingDirectory=/usr/local/sbin/actions-runner ExecStartPre=tar xvf actions-runner-linux.tar.gz --no-same-owner ExecStart=/usr/local/sbin/actions-runner/manage-runner.sh [Install] WantedBy=multi-user.target - name: github-runner.service enabled: true contents: | [Unit] Description=Run the github action runner After=github-runner-configure.service [Service] WorkingDirectory=/usr/local/sbin/actions-runner User=core ExecStart=/usr/local/sbin/actions-runner/run.sh [Install] WantedBy=multi-user.target 这将创建两个服务：github-runner-configure.service（在主机启动完成后运行一次）和 github-runner.service（运行 Actions 运行器二进制文件并等待新的 CI/CD 作业）。现在 Butane 配置已经完成，从中生成一个 Ignition 文件并配备一个 Fedora CoreOS Actions 运行器。$ podman run -i --rm -v $PWD:/code:z --workdir /code quay.io/coreos/butane:release --pretty --strict --files-dir /code config.yaml -o config.ignition 一旦 Ignition 文件生成，它就可以用来在 支持 Fedora CoreOS 的平台上配备一个运行器。配置一个 Action 来使用一个自托管的运行器下面的测试 Action 工作流程将测试 FCOS 的自托管的运行器。在你的 git 存储库中创建以下文件 .github/workflows/main.yml。# This is a basic workflow to help you get started with Actions name: CI # Controls when the action will run. on: # Triggers the workflow on push or pull request events but only for the main branch push: branches: [ main ] pull_request: branches: [ main ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: fcos # Steps represent a sequence of tasks that will be executed as part of the job steps: # Runs a single command using the runners shell - name: Run a one-line script run: podman run --rm fedora-minimal:34 echo Hello World ! 请注意，runs-on 的配置被设置为使用标签为 fcos 的运行器。本文介绍的代码可以在 这里 中找到。via: https://fedoramagazine.org/run-github-actions-on-fedora-coreos/作者：Clément Verna 选题：lujun9972 译者：wxy 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
新恶意程序正利用 WSL 隐蔽攻击 Windows安全专家发现了针对 WSL 创建的恶意 Linux 安装文件。首批针对 WSL 环境的攻击样本在今年 5 月初被发现，并每过一段时间就出现一次。这表明黑客正在尝试用新的方法来破坏 Windows 设备，并利用 WSL 以逃避检测。这些恶意文件主要依靠 Python 3 来执行其任务，并打包成用于 Linux 的 ELF 可执行文件。这真是无孔不入，恶意软件就以这种形式将 Linux 当成了目标。Travis CI 漏洞暴露数千开源项目的密钥Travis CI 是一个流行的持续集成工具，它提供了与 GitHub 和 Bitbucket 等的无缝整合，能直接克隆用户在 GitHub 中的代码库，然后在虚拟环境中进行构建和测试。它被 90 万个开源项目使用。安全研究人员发现了它的一个严重安全漏洞，会导致 Travis CI 曝光使用它测试的仓库的安全环境变量，如签名密钥、访问证书和 API 令牌。这可能会导致攻击者可借此进入组织的网络。安全研究人员建议所有使用 Travis CI 的项目更换相关的密钥和令牌。而在此事件中，Travis CI 对安全问题的漫不经心激怒了开发者社区，他们甚至要求 GitHub 禁用 Travis CI。作为一家普遍应用的 CI 服务商，这样对信息安全和开发者的漠视，必将带来更大的问题。GitHub Action 不香么？Alphabet 采用激光技术实现 5 公里传输 700TB 数据Google 母公司 Alphabet 关闭了探索将氦气球投放至平流层以实现无线互联网覆盖的项目，但该项目中的用于连接高空气球的自由空间光通信链路（FSOC）等技术保留了下来。目前这项技术正被用于为非洲人民提供高速宽带链接。这种链路有点像是没有电缆的光纤。X 实验室表示，该链路在短短 20 天之内传输了近 700 TB 数据。这种技术在某些场景下很有意义啊，其实包括它的气球项目，在救灾等恶劣环境都很有用。
你如何定义持续集成/持续部署管道取决于你组织的要求。 持续集成 continuous integration / 持续部署 continuous deployment （CI/CD）管道是每个 DevOps 计划的基础。 CI/CD 管道打破了传统的开发孤岛，使开发和运营团队能够在整个软件开发生命周期中进行协作。更好的是，转向 DevOps 和 CI/CD 管道可以帮助你的组织以更高的速度更安全地 交付软件。拆解 CI/CD 管道CI/CD 管道有很多定义，所以我总是建议组织定义自己的 CI/CD 管道版本和其他 DevOps 概念，而不是使用其他人的。开源 CI/CD 工具为你提供构建满足组织要求的 CI/CD 管道的自由和选择。形成 CI/CD 管道的阶段是将不同的任务子集分组为 管道阶段。典型的管道阶段包括：构建：开发人员编译应用程序代码。测试：质量保证（QA）团队使用自动化测试工具和策略测试应用程序代码。发布：开发团队将应用程序代码交付到代码库。部署：DevOps 团队将应用程序代码分阶段投入生产。安全性和合规性：QA 团队根据项目要求验证构建。这是组织部署容器扫描工具的阶段，这些工具根据 常见漏洞和暴露 Common Vulnerabilities and Exposures （CVE）检查容器镜像的质量。这些是 CI/CD 管道的标准阶段，但一些组织调整 CI/CD 管道模型以满足他们的要求。例如，为医疗保健市场构建应用程序的组织，具有严格的合规性标准，可以在整个工具链中分发测试、验证和合规性门槛。其他示例可能是依赖于具有开源软件（OSS）的复杂软件供应链的组织。商业组件可能会设立一个门槛，开发团队成员可以在其中为 OSS 包生成 软件物料清单 software bill of materials （SBOM），或者外部商业软件供应商必须将 SBOM 作为其合同可交付成果的一部分进行交付。CI/CD 管道的障碍实施 CI/CD 管道会改变团队的流程和文化。尽管许多开发人员愿意接受某些任务和测试的自动化，但人员可能成为采用 CI/CD 的障碍。从瀑布式流程转向 CI/CD 可能会动摇某些组织中基本的和隐含的权力结构。由于 CI/CD 管道提高了软件交付速度，旧手动流程的“守门人”可能会受到这种变化的威胁。整合机会随着你在文化、流程和工具中达到更高的 DevOps 成熟度水平，包含 CI/CD 工具链的工具的开源根源为一些激动人心的集成创造了机会。分析公司 Forrester 在 2020 年预测， 即时学习 just-in-time learning 将加入 CI/CD 管道。如果你考虑一下，会发现这是有道理的。在当前远程工作的时代，甚至对于新员工的远程入职，这更有意义。例如，组织可以将文档 wiki 与内部流程文档集成到其管道中。更雄心勃勃的组织可以将学习管理系统（LMS）（例如 Moodle）集成到其 CI/CD 管道中。它可以使用 LMS 发布有关新 DevOps 工具链功能的简短视频，开发人员在加入时或在整个管道中更新工具时需要学习这些功能。一些组织正在将群聊和其他协作工具直接集成到他们的 CI/CD 管道中。聊天平台提供警报并支持团队之间的协作和沟通。将 Mattermost、Rocket.Chat 或其他 企业聊天 平台集成到你的 CI/CD 管道中需要预先规划和分析，以确保管道用户不会被警报淹没。另一个需要探索的集成机会是将分析和高级报告构建到你的 CI/CD 管道中。这有助于你利用通过管道传输的数据。总结CI/CD 管道是 DevOps 的基础。开源使其能够适应并灵活地满足你在 DevOps 之旅中实施的运营变更所产生的新需求。我希望看到对统一 DevOps 平台趋势的开源响应，在这种趋势中，组织寻求端到端的 CI/CD 解决方案。这种解决方案的要素就在那里。毕竟，GitLab 和 GitHub 将他们的平台追溯到开源根源。最后，不要忘记每一个成功的 CI/CD 工具链背后的教育和外展。记录你的工具链和相关流程将改善开发人员入职和持续的 DevOps 团队培训。你和你的组织如何定义你的 CI/CD 工具链？请在评论中分享你的反馈。via: https://opensource.com/article/21/6/what-cicd-pipeline作者：Will Kelly 选题：lujun9972 译者：baddate 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
CI/CD 平台迁移实践：从 Travis-CI 转移到 Github Action
LCTT 的 CI 已经在 Travis CI 上运转了多年，一致保持着良好的使用体验。自 2019 年 Github 推出了自家的 CI 工具 Github Action 后，我们就在考虑将 CI 从 Travis-CI 迁移到 Github，以降低维护和沟通的成本，并借助于 GitHub Action Marketplace 实现更强的功能。最近，因为 TravisCI 屡屡部署出错，而我们的账户因为使用的较多，已经超出了免费使用的限制，以此为契机，将 CI 从 Travis CI 迁移到 GitHub Action。项目介绍Translate Project 是 LCTT 翻译组的主要协作项目，几百位译者通过 GitHub 进行围绕开源、Linux、软件工程等领域的文章翻译，从 2013 年来，累计了大量的提交，致使项目下有非常多的文件。Translate Project 借助于 CI 帮助译者对基本的文章格式和拉取请求进行检查；并定时执行命令，以进行所有的申请检查，对于超时未完成翻译的工作进行回收；对于文章的状态进行标记，生成相应的徽章。迁移思路Travis CI 和 Github Action 在使用方面，其实总体差异不会太大，都是基于 YAML 文件格式来编写配置文件。不过，和 Travis CI 不同的是，Github Action 支持多个不同的配置文件，因此，你可以根据不同的场景，设定不同的配置文件，降低单个配置的文件的复杂度。此外，由于我们的脚本中依赖了一些 Travis CI 的环境变量，也需要将其替换为 Github Action 中的相应环境变量，从而确保脚本可以运转。改造实践1. 分析之前的 CI 流程我们在 TravisCI 上的 CI 配置文件如图：总体可以分为三块：命令区：说明了安装阶段和执行阶段的操作有哪些条件区：指定了这个配置文件在哪些条件下会生效部署区：写明了构建产物如何进行部署在命令区中，有预置的安装过程和后续的执行过程。在安装过程中，安装了一些依赖，并将当前的 pages 资源克隆到本地，以继承上一次构建生成的资料。在条件区则指明了仅作用于 master 分支。在部署区便是将前面命令区的执行结果进行部署。在实际的执行过程中，还会根据环境变量不同，决定是否要执行特定的命令，这部分在后续的改造过程中，就可以调整部署，拆分到不同的文件中。2. 直接套用配置文件在完成了基本的分析后，就可以建立新的 Action 配置文件了。由于基本的语法很类似，对于其中的不少内容可以进行直接套用。比如，我们的配置文件在直接套用后，结果如下直接套用的文件已经可以直接运行，不过，这里有很多不满足需要的地方，所以需要做一些修改。3. 恢复 Travis CI 的环境变量由于我们使用的 Badge 等生成脚本并非我所编写，所以在这一次的迁移中，并不打算对齐进行调整，以避免出现故障。而脚本中依赖了一些变量，需要将其重新设置出来。Github Action 提供了一些方法，可以让你手动设置环境变量。你可以在你的构建的步骤中，加入如下代码，从而在构建环境中设定 TRAVIS_BRANCH 和 TRAVIS_EVENT_TYPE 环境变量，确保你可以使用这个环境变量。 - name: Set ENV variables run: | echo "::set-env name=TRAVIS\_BRANCH::${TRAVIS\_BRANCH:-$(echo $GITHUB\_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')}" echo "::set-env name=TRAVIS\_EVENT\_TYPE::$(if [ "schedule" == "${{ github.event\_name }}" ]; then echo "cron"; else echo "${{ github.event\_name }}"; fi)" 此外，由于 set-env 这个方法相对比较危险，你还需要在环境变量中，开启危险函数的执行。jobs: build: runs-on: ubuntu-latest env: ACTIONS\_ALLOW\_UNSECURE\_COMMANDS: true 4. 拆分配置文件Github Action 和 TravisCI 不同的一点是你可以将你的 CI 文件拆分成多个文件，从而降低每一个单独的配置文件的复杂度。根据前面对于流程的分析，可以将我们的 CI 流程拆分成三个部分：生成 badge 文件，应当跟随每一次提交进行生成 status 文件，执行时间较长，可以定期执行根据拉取请求内容进行整理，做核验则将我们的配置文件拆分成三个不同的文件：也得益于拆分开，则在 checker 中就可以免于安装一些必要的依赖，从而精简 CI 流程，提升 CI 的执行时间。5. 测试 CI 的运行情况在完成了配置文件的编写和拆分后，就可以进行本地的执行测试。Github Action 写完了，难免要执行一下，确保整个流程是正常的。这个时候你可以安装工具（https://github.com/nektos/act），来在本地执行 Action ，从而确认你的代码执行是正确的。如果你是 macOS ，只需要执行 brew install act 就可以安装 act 工具，来完成 act 的安装。安装完成 act ，就可以通过执行 act 命令来在本地执行 Action ，比如，执行 act pull_request 来触发 GitHub 的拉取请求事件通过本地测试后，再将你的配置文件推送到 GitHub 上，进行生产环境的测试即可。6. 移除 Travis-CI通过上述的一些步骤，我们完成了从 Travis CI 到 GitHub Action 的迁移，此时，就可以移除项目根目录中的 .travis.yml 文件，彻底关闭 Travis CI。7. 替换环境变量在完成了基本的迁移后，需要对代码中的一些历史问题进行修复。在第三步中，我们对于 Travis-CI 的环境变量进行替换，但长期维护的项目应当尽量将这些未标注上下文的信息替换为有文档标注的，因此，我们需要将其替换。替换环境变量主要依赖 Github 官方的环境变量说明，你可以参考官方文档。简化后，配置文件从之前的 27 行，减少至 17 行，变得更加的精简、易懂。name: LCTT Article Checker on: pull_request: branches: [master] jobs: build: runs-on: ubuntu-latest env: PULL_REQUEST_ID: ${{ github.event.number }} steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: "checkout master branch & return to pull request branch" run: CURRENT=$(echo ${{github.ref}} | sed "s|refs/|refs/remotes/|") && git checkout master && git checkout $CURRENT - name: run check run: sh ./scripts/check.sh; 8. 修改 GitHub 的分支保护条件为了确保修改符合标准，我们限制了新的拉取请求必须通过 CI 检查，才能合并进入 master 分支，因此，也需要修改相应的分支保护规则，确保设定相应的保护。一些注意事项1. 环境变量不同如果你依赖了环境变量，则需要进行相应的修改。或者可以像我一样，先通过 set-env 来让本地拥有临时的环境变量，后续再逐步进行迁移。2. Action 运行依赖要注意安全Action 执行过程中会有两个部分。Action 本身流程依赖于 master 分支，但执行过程中调用的脚本是根据源决定的，因此，从安全角度来看，你应当尽可能将所有的流程放在 Action 中，而不是放在你的源码目录中。3. 如何触发 CI 的拉取请求检查？在进行拉取请求测试的时候，需要不断触发不同的提交 ，你可以通过执行 git commit --allow-empty -m "Trigger notification" && git push 来触发一个空白的提交， 推送到 Github 后，就可以再次触发拉取请求的构建，提升构建的效率。总结通过对 TravisCI 的流程整理、代码修改等流程，我们将之前的 Travis-CI 迁移至速度更快、性能更好的 GitHub Action ，一方面可以优化我们的工作流，另一方面，也让我们的代码更加简洁明了。对于还在使用 Travis CI 的项目来说，也可以考虑迁移到 GitHub Action 中，来优化自己的工作流。参考阅读https://mauricius.dev/run-and-debug-github-actions-locally/https://jeffrafter.com/working-with-github-actions/https://developer.okta.com/blog/2020/05/18/travis-ci-to-github-actions
统一的持续集成与持续交付的流水线的构想是一种梦想吗？当我加入 WorkSafeBC 负责云端运维和工程流程优化的云端运维团队时，我和大家分享了我的梦想，那就是一个工具化的流水线，每一个产品都可以持续集成和持续交付。根据 Lukas Klose 的说法， 流程 flow （在软件工程的语境内）是“软件系统以稳定和可预测的速度创造价值的状态”。我认为这是最大的挑战和机遇之一，特别是在复杂的新兴解决方案领域。我力求通过一种持续、高效和优质的解决方案，提供一种持续交付模式，并且能够构建正确的事物让我们的用户感到满意。想办法把我们的系统分解成更小的碎片，这些碎片本身是有价值的，使团队能够渐进式地交付价值。这需要业务和工程部门改变思维方式。持续集成和持续交付的（CI/CD）流水线CI/CD 流水线是一种 DevOps 实践，用于更频繁、一致、可靠的地交付代码变更。它可以帮助敏捷开发团队提高部署频率，减少变更准备时间、变更失败率和关键绩效指标（KPI）的平均恢复时间，从而提高质量并且实现更快的交付。唯一的先决条件就是坚实的开发流程、对质量的心态和对需求从构想到废弃的责任心，以及一个全面的流水线（如下图所示）。它简化了工程流程和产品，以稳定基础架构环境；优化工作流程；并创建一致的、可重复的、自动化的任务。正如 Dave Snowden 的 Cynefin Sensemaking 模型所说的那样，这样就允许我们将复杂不可解决的任务变成了复杂可解决的任务，降低了维护成本，提高了质量和可靠性。精简流程的一部分是将 浪费实践类型 wasteful practice types Muri（过载）、Mura（变异）和 Muda（浪费）的浪费降低最低。Muri（过载）：避免过度工程化，避免与商业价值不相关的功能以及过多的文档。Mura（变异）：改善审批和验证流程（比如，安全签批）；推动 左移提前 shift-left 策略以推行单元测试、安全漏洞扫描与代码质量检查；并改进风险评定。Muda（浪费）：避免技术债、错误或前期的详细文档等浪费。看起来 80％ 的重点都集中在提供一种可以集成和协作的工程产品上，这些系统可以采用一个创意和计划、开发、测试和监控你的解决方案。然而，一个成功的转型和工程系统是由 5％ 的产品、15％ 的过程和 80％ 的开发人员组成的。我们可以使用的产品有很多。比如，Azure DevOps 为持续集成（CI）、持续交付（CD）和可扩展性提供了丰富支持，并与 Stryker、SonarQube、WhiteSource、Jenkins 和 Octopus 等开源集成和商用成品（COTS）软件即服务（SaaS）进行集成。对于工程师来说，关注产品总是一种诱惑，但请记住，它们只是我们旅程的 5%。最大的挑战是打破数十年的规则、规定和已经步入舒适区的流程：“我们一直都是这样做的；为什么需要改变呢？”开发和运维人员之间的摩擦导致了各种支离破碎的、重复的、不间断的集成和交付流水线。开发人员希望能访问所有东西，以便持续迭代，让用户使用起来和持续地快速发布。运维人员希望将所有东西锁起来，保护业务、用户和品质。这些矛盾在不经意间导致了很难做到一种自动化的流程，进而导致发布周期晚于预期。让我们使用最近的一次白板讨论中的片段来探索流水线。想要支持流水线的变化是一项困难并且花费巨大的工作；版本和可追溯性的不一致使得这个问题变得更加复杂，因此不断精简开发流程和流水线是一项挑战。我主张一些原则使得每个产品都能使用通用流水线：使一切可自动化的东西都自动化一次构建保持持续集成和持续交付保持持续精简和改进保持一个构建的定义保持一个发布流水线的定义尽早、频繁地扫描漏洞，并且尽快失败尽早、频繁地进行测试，并且尽快失败保持已发布版本的可追踪和监控但是，如果我要打破这些，最重要的原则就是保持简单。如果你不能说明流水线化的原因（是什么、为什么）和过程（如何），你或许是不了解自己的软件过程的。我们大多数人想要的不是最好的、超现代的和具有革命意义的流水线 —— 我们仅仅是需要一个功能强大的、有价值的和能促进工程的流水线。首先需要解决的是那 80% —— 文化、人员和他们的心态。请你的 CI/CD 骑士们穿上闪亮的盔甲，在他们的盾牌上贴上 TLA（ 两个/三个字母的缩写 two/three-lettered acronym ）符号，加入到实践和经验工程的力量中来。统一流水线让我们逐步完成我们的白板会议实践。每个应用使用一套构建定义来定义一个 CI/CD 流水线，用来触发拉取请求的预合并验证与持续集成的构建。生成一个带有调试信息的发布的构建，并且将其上传到 符号服务器。这使开发人员可以在本地和远程生产环境进行调试，而在不用考虑需要加载哪个构建和符号，符号服务器为我们施展了这样的魔法。在构建过程中进行尽可能多的验证（左移提前），这允许开发新特性的团队可以尽快失败，不断的提高整体的产品质量，并在拉取请求中为代码审核人员提供宝贵证据。你喜欢有大量提交的拉取请求吗？还是一个带有少数提交和提供了漏洞检查、测试覆盖率、代码质量检查和 Stryker 突变残余等支持的拉取请求？就我个人而言，我投后者的票。不要使用构建转换来生成多个特定环境的构建。通过一个构建实现发布时转换、标记化和 XML/JSON 的值替换。换句话说，右移滞后具体环境的配置。安全存储发布配置数据，并且根据数据的信任度和敏感度，让开发和运维都能使用。使用开源的密钥管理工具、Azure 密钥保险库、AWS 密钥管理服务或者其他产品，记住你的工具箱中有很多方便的工具。使用用户组而不是用户，将审批人管理从跨多个流水线的多个阶段移动到简单的组成员。创建一条流水线并且对赋予特定的交付阶段的权限，而不是重复流水线让团队进入他们感兴趣的地方。最后，但并非最不重要的是，拥抱拉取请求，以帮助提高对代码仓库的洞察力和透明度，增进整体质量、协作，并将预验证构建发布到选定的环境，比如，开发环境。这是整个白板更正式的视图。所以，你对 CI/CD 流水线有什么想法和经验？我的通过一条流水线来管理它们的这个梦想是空想吗？via: https://opensource.com/article/19/7/cicd-pipeline-rule-them-all作者：Willy-Peter Schaub 选题：lujun9972 译者：chunibyo-wly 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
CKI 团队是如何防止 bug 被合并到 Linux 内核中。Linux 内核的每个发布版本包含了来自 1,700 个开发者产生的 14,000 个变更集，很显然，这使得 Linux 内核快速迭代的同时也产生了巨大的复杂性问题。内核上 Bug 有小麻烦也有大问题，有时是系统崩溃，有时是数据丢失。随着越来越多的项目对于持续集成（CI）的呼声，内核持续集成（CKI）小组秉承着一个任务目标：防止 Bug 被合并到内核当中。Linux 测试问题许多 Linux 发行版只在需要的时候对 Linux 内核进行测试。而这种测试往往只在版本发布时或者用户发现错误时进行。有时候，出现玄学问题时，维护人员需要在包含了数万个补丁的变更中匆忙地寻找哪个补丁导致这个新的玄学 Bug。诊断 Bug 需要专业的硬件设备、一系列的触发器以及内核相关的专业知识。CI 和 Linux许多现代软件代码库都采用某种自动化 CI 测试机制，能够在提交进入代码存储库之前对其进行测试。这种自动化测试使得维护人员可以通过查看 CI 测试报告来发现软件质量问题以及大多数的错误。一些简单的项目，比如某个 Python 库，附带的大量工具使得整个检查过程更简单。在任何测试之前都需要配置和编译 Linux。而这么做将耗费大量的时间和计算资源。此外，Linux 内核必需在虚拟机或者裸机上启动才能进行测试。而访问某些硬件架构需要额外的开销或者非常慢的仿真。因此，人们必须确定一组能够触发错误或者验证修复的测试集。CKI 团队如何运作？Red Hat 公司的 CKI 团队当前正追踪来自数个内部内核分支和上游的稳定内核分支树等内核分支的更改。我们关注每个代码库的两类关键事件：当维护人员合并 PR 或者补丁时，代码库变化后的最终结果。当开发人员通过拼凑或者稳定补丁队列发起变更合并时。当这些事件发生时，自动化工具开始执行，GitLab CI 管道开始进行测试。一旦管道开始执行 linting) 脚本、合并每一个补丁，并为多种硬件架构编译内核，真正的测试便开始了。我们会在六分钟内完成四种硬件架构的内核编译工作，并且通常会在两个小时或更短的时间内将反馈提交到稳定邮件列表中。（自 2019 年 1 月起）每月执行超过 100,000 次内核测试，并完成了超过 11,000 个 GitLab 管道。每个内核都会在本地硬件架构上启动，其中包含：aarch64：64 位 ARM，例如 Cavium（当前是 Marvell）ThunderX。ppc64/ppc64le：大端和小端的 IBM POWER 系统。s390x：IBM Zseries 大型机x86\_64：Intel 和 AMD 工作站、笔记本和服务器。这些内核上运行了包括 Linux 测试项目（LTP）在内的多个测试，其中包括使用常用测试工具的大量测试。我们 CKI 团队开源了超过 44 个测试并将继续开源更多测试。参与其中上游的内核测试工作日渐增多。包括 Google、Intel、Linaro 和 Sony 在内的许多公司为各种内核提供了测试输出。每一项工作都专注于为上游内核以及每个公司的客户群带来价值。如果你或者你的公司想要参与这一工作，请参加在 9 月份在葡萄牙里斯本举办的 Linux Plumbers Conference 2019。在会议结束后的两天加入我们的 Kernel CI hackfest 活动，并推动快速内核测试的发展。更多详细信息，请见我在 Texas Linux Fest 2019 上的演讲。via: https://opensource.com/article/19/6/continuous-kernel-integration-linux作者：Major Hayden 选题：lujun9972 译者：LazyWolfLin 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
ick 是一个持续集成（CI）系统。访问 http://ick.liw.fi/ 获取更多信息。更加详细的内容如下：首个公开版本发行这个世界可能并不需要又一个持续集成系统（CI），但是我需要。我对我尝试过或者看过的持续集成系统感到不满意。更重要的是，有几样我感兴趣的东西比我所听说过的持续集成系统要强大得多。因此我开始编写我自己的 CI 系统。我的新个人业余项目叫做 ick。它是一个 CI 系统，这意味着它可以运行自动化的步骤来构建、测试软件。它的主页是 http://ick.liw.fi/，下载页面有指向源代码、.deb 包和用来安装的 Ansible 脚本的链接。我现已发布了首个公开版本，绰号 ALPHA-1，版本号 0.23。（LCTT 译注：截止至本译文发布，已经更新到 ALPHA-6）它现在是 alpha 品质，这意味着它并没拥有期望的全部特性，如果任何一个它已有的特性工作的话，那真是运气好。诚邀贡献ick 目前是我的个人项目。我希望能让它不仅限于此，同时我也诚邀更多贡献。访问治理页面查看章程，入门页面查看如何开始贡献的的小建议，联系页面查看如何联络。架构ick 拥有一个由几个通过 HTTPS 协议通信使用 RESTful API 和 JSON 处理结构化数据的部分组成的架构。访问架构页面了解细节。宣告持续集成（CI）是用于软件开发的强大工具。它不应枯燥、易溃或恼人。它构建起来应简单快速，除非正在测试、构建的代码中有问题，不然它应在后台安静地工作。一个持续集成系统应该简单、易用、清楚、干净、可扩展、快速、综合、透明、可靠，并推动你的生产力。构建它不应花大力气、不应需要专门为 CI 而造的硬件、不应需要频繁留意以使其保持工作、开发者永远不必思考为什么某样东西不工作。一个持续集成系统应该足够灵活以适应你的构建、测试需求。只要 CPU 架构和操作系统版本没问题，它应该支持各种操作者。同时像所有软件一样，CI 应该彻彻底底的免费，你的 CI 应由你做主。（目前的 ick 仅稍具雏形，但是它会尝试着有朝一日变得完美 —— 在最理想的情况下。）未来的梦想长远来看，我希望 ick 拥有像下面所描述的特性。落实全部特性可能需要一些时间。各种事件都可以触发构建。时间是一个明显的事件，因为项目的源代码仓库改变了。更强大的是任何依赖的改变，不管依赖是来自于 ick 构建的另一个项目，或者是包（比如说来自 Debian）：ick 应当跟踪所有安装进一个项目构建环境中的包，如果任何一个包的版本改变，都应再次触发项目构建和测试。ick 应该支持构建于（或针对）任何合理的目标平台，包括任何 Linux 发行版，任何自由的操作系统，以及任何一息尚存的不自由的操作系统。ick 应该自己管理构建环境，并且能够执行与构建主机或网络隔离的构建。这部分工作：可以要求 ick 构建容器并在容器中运行构建。容器使用 systemd-nspawn 实现。 然而，这可以改进。（如果您认为 Docker 是唯一的出路，请为此提供支持。）ick 应当不需要安装任何专门的代理，就能支持各种它能够通过 ssh 或者串口或者其它这种中性的交流管道控制的 操作者 worker 。ick 不应默认它可以有比如说一个完整的 Java Runtime，如此一来，操作者就可以是一个微控制器了。ick 应当能轻松掌控一大批项目。我觉得不管一个新的 Debian 源包何时上传，ick 都应该要能够跟得上在 Debian 中构建所有东西的进度。（明显这可行与否取决于是否有足够的资源确实用在构建上，但是 ick 自己不应有瓶颈。）如果有需要的话 ick 应当有选择性地补给操作者。如果所有特定种类的操作者处于忙碌中，且 ick 被设置成允许使用更多资源的话，它就应该这么做。这看起来用虚拟机、容器、云提供商等做可能会简单一些。ick 应当灵活提醒感兴趣的团体，特别是关于其失败的方面。它应允许感兴趣的团体通过 IRC、Matrix、Mastodon、Twitter、email、SMS 甚至电话和语音合成来接受通知。例如“您好，感兴趣的团体。现在是四点钟您想被通知 hello 包什么时候为 RISC-V 构建好。”请提供反馈如果你尝试过 ick 或者甚至你仅仅是读到这，请在上面分享你的想法。在联系页面查看如何发送反馈。相比私下反馈我更偏爱公开反馈。但如果你偏爱私下反馈，那也行。via: https://blog.liw.fi/posts/2018/01/22/ick_a_continuous_integration_system/作者：Lars Wirzenius 译者：tomjlw 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
本文是一篇简单指南：介绍一些顶级的开源的持续集成、持续交付和持续部署（CI/CD）工具。虽然持续集成、持续交付和持续部署（CI/CD）在开发者社区里已经存在很多年，一些机构在其运维部门也有实施经验，但大多数公司并没有做这样的尝试。对于很多机构来说，让运维团队能够像他们的开发同行一样熟练操作 CI/CD 工具，已经变得十分必要了。无论是基础设施、第三方应用还是内部开发的应用，都可以开展 CI/CD 实践。尽管你会发现有很多不同的工具，但它们都有着相似的设计模型。而且可能最重要的一点是：通过带领你的公司进行这些实践，会让你在公司内部变得举足轻重，成为他人学习的榜样。一些机构在自己的基础设施上已有多年的 CI/CD 实践经验，常用的工具包括 Ansible、Chef 或者 Puppet。另一些工具，比如 Test Kitchen，允许在最终要部署应用的基础设施上运行测试。事实上，如果使用更高级的配置方法，你甚至可以将应用部署到有真实负载的仿真“生产环境”上，来运行应用级别的测试。然而，单单是能够测试基础设施就是一项了不起的成就了。配置管理工具 Terraform 可以通过 Test Kitchen 来快速创建更短暂和冥等的的基础设施配置，这比它的前辈要强不少。再加上 Linux 容器和 Kubernetes，在数小时内，你就可以创建一套类似于生产环境的配置参数和系统资源，来测试整个基础设施和其上部署的应用，这在以前可能需要花费几个月的时间。而且，删除和再次创建整个测试环境也非常容易。当然，作为初学者，你也可以把网络配置和 DDL（ 数据定义语言 data definition language ）文件加入版本控制，然后开始尝试一些简单的 CI/CD 流程。虽然只能帮你检查一下语义语法或某些最佳实践，但实际上大多数开发的管道都是这样起步的。只要你把脚手架搭起来，建造就容易得多了。而一旦起步，你就会发现各种管道的使用场景。举个例子，我经常会在公司内部写新闻简报，我使用 MJML 制作邮件模板，然后把它加入版本控制。我一般会维护一个 web 版本，但是一些同事喜欢 PDF 版，于是我创建了一个管道。每当我写好一篇新闻稿，就在 Gitlab 上提交一个合并请求。这样做会自动创建一个 index.html 文件，生成这篇新闻稿的 HTML 和 PDF 版链接。HTML 和 PDF 文件也会在该管道里同时生成。除非有人来检查确认，这些文件不会被直接发布出去。使用 GitLab Pages 发布这个网站后，我就可以下载一份 HTML 版，用来发送新闻简报。未来，我会修改这个流程，当合并请求成功或者在某个审核步骤后，自动发出对应的新闻稿。这些处理逻辑并不复杂，但的确为我节省了不少时间。实际上这些工具最核心的用途就是替你节省时间。关键是要在抽象层创建出工具，这样稍加修改就可以处理不同的问题。值得留意的是，我创建的这套流程几乎不需要任何代码，除了一些轻量级的 HTML 模板，一些把 HTML 文件转换成 PDF 的 nodejs 代码，还有一些生成索引页面的 nodejs 代码。这其中一些东西可能看起来有点复杂，但其中大部分都源自我使用的不同工具的教学文档。而且很多开发人员也会乐意跟你合作，因为他们在完工时会发现这些东西也挺有用。上面我提供的那些代码链接是给 DevOps KC（LCTT 译注：一个地方性 DevOps 组织） 发送新闻简报用的，其中大部分用来创建网站的代码来自我在内部新闻简报项目上所作的工作。下面列出的大多数工具都可以提供这种类型的交互，但是有些工具提供的模型略有不同。这一领域新兴的模型是用声明式的方法例如 YAML 来描述一个管道，其中的每个阶段都是短暂而幂等的。许多系统还会创建有向无环图（DAG），来确保管道上不同的阶段排序的正确性。这些阶段一般运行在 Linux 容器里，和普通的容器并没有区别。有一些工具，比如 Spinnaker，只关注部署组件，而且提供一些其他工具没有的操作特性。Jenkins 则通常把管道配置存成 XML 格式，大部分交互都可以在图形界面里完成，但最新的方案是使用领域专用语言（DSL）（如 Groovy）。并且，Jenkins 的任务（job）通常运行在各个节点里，这些节点上会装一个专门的 Java 代理，还有一堆混杂的插件和预装组件。Jenkins 在自己的工具里引入了管道的概念，但使用起来却并不轻松，甚至包含一些禁区。最近，Jenkins 的创始人决定带领社区向新的方向前进，希望能为这个项目注入新的活力，把 CI/CD 真正推广开（LCTT 译注：详见后面的 Jenkins 章节)。我认为其中最有意思的想法是构建一个云原生 Jenkins，能把 Kubernetes 集群转变成 Jenkins CI/CD 平台。当你更多地了解这些工具并把实践带入你的公司和运维部门，你很快就会有追随者，因为你有办法提升自己和别人的工作效率。我们都有多年积累下来的技术债要解决，如果你能给同事们提供足够的时间来处理这些积压的工作，他们该会有多感激呢？不止如此，你的客户也会开始看到应用变得越来越稳定，管理层会把你看作得力干将，你也会在下次谈薪资待遇或参加面试时更有底气。让我们开始深入了解这些工具吧，我们将对每个工具做简短的介绍，并分享一些有用的链接。GitLab CI项目主页源代码许可证：MITGitLab 可以说是 CI/CD 领域里新登场的玩家，但它却在权威调研机构 Forrester 的 CI 集成工具的调查报告中位列第一。在一个高水平、竞争充分的领域里，这是个了不起的成就。是什么让 GitLab CI 这么成功呢？它使用 YAML 文件来描述整个管道。另有一个功能叫做 Auto DevOps，可以为较简单的项目用多种内置的测试单元自动生成管道。这套系统使用 Herokuish buildpacks 来判断语言的种类以及如何构建应用。有些语言也可以管理数据库，它真正改变了构建新应用程序和从开发的开始将它们部署到生产环境的过程。它原生集成于 Kubernetes，可以根据不同的方案将你的应用自动部署到 Kubernetes 集群，比如灰度发布、蓝绿部署等。除了它的持续集成功能，GitLab 还提供了许多补充特性，比如：将 Prometheus 和你的应用一同部署，以提供操作监控功能；通过 GitLab 提供的 Issues、Epics 和 Milestones 功能来实现项目评估和管理；管道中集成了安全检测功能，多个项目的检测结果会聚合显示；你可以通过 GitLab 提供的网页版 IDE 在线编辑代码，还可以快速查看管道的预览或执行状态。GoCD项目主页源代码许可证：Apache 2.0GoCD 是由老牌软件公司 Thoughtworks 出品，这已经足够证明它的能力和效率。对我而言，GoCD 最具亮点的特性是它的价值流视图（VSM）。实际上，一个管道的输出可以变成下一个管道的输入，从而把管道串联起来。这样做有助于提高不同开发团队在整个开发流程中的独立性。比如在引入 CI/CD 系统时，有些成立较久的机构希望保持他们各个团队相互隔离，这时候 VSM 就很有用了：让每个人都使用相同的工具就很容易在 VSM 中发现工作流程上的瓶颈，然后可以按图索骥调整团队或者想办法提高工作效率。为公司的每个产品配置 VSM 是非常有价值的；GoCD 可以使用 JSON 或 YAML 格式存储配置，还能以可视化的方式展示数据等待时间，这让一个机构能有效减少学习它的成本。刚开始使用 GoCD 创建你自己的流程时，建议使用人工审核的方式。让每个团队也采用人工审核，这样你就可以开始收集数据并且找到可能的瓶颈点。Travis CI项目主页源代码许可证：MIT我使用的第一个软件既服务（SaaS）类型的 CI 系统就是 Travis CI，体验很不错。管道配置以源码形式用 YAML 保存，它与 GitHub 等工具无缝整合。我印象中管道从来没有失效过，因为 Travis CI 的在线率很高。除了 SaaS 版之外，你也可以使用自行部署的版本。我还没有自行部署过，它的组件非常多，要全部安装的话，工作量就有点吓人了。我猜更简单的办法是把它部署到 Kubernetes 上，Travis CI 提供了 Helm charts，这些 charts 目前不包含所有要部署的组件，但我相信以后会越来越丰富的。如果你不想处理这些细枝末节的问题，还有一个企业版可以试试。假如你在开发一个开源项目，你就能免费使用 SaaS 版的 Travis CI，享受顶尖团队提供的优质服务！这样能省去很多麻烦，你可以在一个相对通用的平台上（如 GitHub）研发开源项目，而不用找服务器来运行任何东西。Jenkins项目主页源代码许可证：MITJenkins 在 CI/CD 界绝对是元老级的存在，也是事实上的标准。我强烈建议你读一读这篇文章：“Jenkins: Shifting Gears”，作者 Kohsuke 是 Jenkins 的创始人兼 CloudBees 公司 CTO。这篇文章契合了我在过去十年里对 Jenkins 及其社区的感受。他在文中阐述了一些这几年呼声很高的需求，我很乐意看到 CloudBees 引领这场变革。长期以来，Jenkins 对于非开发人员来说有点难以接受，并且一直是其管理员的重担。还好，这些问题正是他们想要着手解决的。Jenkins 配置既代码（JCasC）应该可以帮助管理员解决困扰了他们多年的配置复杂性问题。与其他 CI/CD 系统类似，只需要修改一个简单的 YAML 文件就可以完成 Jenkins 主节点的配置工作。Jenkins Evergreen 的出现让配置工作变得更加轻松，它提供了很多预设的使用场景，你只管套用就可以了。这些发行版会比官方的标准版本 Jenkins 更容易维护和升级。Jenkins 2 引入了两种原生的管道功能，我在 LISA（LCTT 译注：一个系统架构和运维大会） 2017 年的研讨会上已经讨论过了。这两种功能都没有 YAML 简便，但在处理复杂任务时它们很好用。Jenkins X 是 Jenkins 的一个全新变种，用来实现云端原生 Jenkins（至少在用户看来是这样）。它会使用 JCasC 及 Evergreen，并且和 Kubernetes 整合的更加紧密。对于 Jenkins 来说这是个令人激动的时刻，我很乐意看到它在这一领域的创新，并且继续发挥领袖作用。Concourse CI项目主页源代码许可证：Apache 2.0我第一次知道 Concourse 是通过 Pivotal Labs 的伙计们介绍的，当时它处于早期 beta 版本，而且那时候也很少有类似的工具。这套系统是基于微服务构建的，每个任务运行在一个容器里。它独有的一个优良特性是能够在你本地系统上运行任务，体现你本地的改动。这意味着你完全可以在本地开发（假设你已经连接到了 Concourse 的服务器），像在真实的管道构建流程一样从你本地构建项目。而且，你可以在修改过代码后从本地直接重新运行构建，来检验你的改动结果。Concourse 还有一个简单的扩展系统，它依赖于“资源”这一基础概念。基本上，你想给管道添加的每个新功能都可以用一个 Docker 镜像实现，并作为一个新的资源类型包含在你的配置中。这样可以保证每个功能都被封装在一个不可变的独立工件中，方便对其单独修改和升级，改变其中一个时不会影响其他构建。Spinnaker项目主页源代码许可证：Apache 2.0Spinnaker 出自 Netflix，它更关注持续部署而非持续集成。它可以与其他工具整合，比如 Travis 和 Jenkins，来启动测试和部署流程。它也能与 Prometheus、Datadog 这样的监控工具集成，参考它们提供的指标来决定如何部署。例如，在 金丝雀发布 canary deployment 里，我们可以根据收集到的相关监控指标来做出判断：最近的这次发布是否导致了服务降级，应该立刻回滚；还是说看起来一切 OK，应该继续执行部署。谈到持续部署，一些另类但却至关重要的问题往往被忽略掉了，说出来可能有点让人困惑：Spinnaker 可以帮助持续部署不那么“持续”。在整个应用部署流程期间，如果发生了重大问题，它可以让流程停止执行，以阻止可能发生的部署错误。但它也可以在最关键的时刻让人工审核强制通过，发布新版本上线，使整体收益最大化。实际上，CI/CD 的主要目的就是在商业模式需要调整时，能够让待更新的代码立即得到部署。Screwdriver项目主页源代码许可证：BSDScrewdriver 是个简单而又强大的软件。它采用微服务架构，依赖像 Nomad、Kubernetes 和 Docker 这样的工具作为执行引擎。官方有一篇很不错的部署教学文档，介绍了如何将它部署到 AWS 和 Kubernetes 上，但如果正在开发中的 Helm chart 也完成的话，就更完美了。Screwdriver 也使用 YAML 来描述它的管道，并且有很多合理的默认值，这样可以有效减少各个管道重复的配置项。用配置文件可以组织起高级的工作流，来描述各个任务间复杂的依赖关系。例如，一项任务可以在另一个任务开始前或结束后运行；各个任务可以并行也可以串行执行；更赞的是你可以预先定义一项任务，只在特定的拉取请求时被触发，而且与之有依赖关系的任务并不会被执行，这能让你的管道具有一定的隔离性：什么时候被构造的工件应该被部署到生产环境，什么时候应该被审核。以上只是我对这些 CI/CD 工具的简单介绍，它们还有许多很酷的特性等待你深入探索。而且它们都是开源软件，可以自由使用，去部署一下看看吧，究竟哪个才是最适合你的那个。via: https://opensource.com/article/18/12/cicd-tools-sysadmins作者：Dan Barker 选题：lujun9972 译者：jdh8383 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出