- Linux 中的管道允许您通过连接 stdout 和 stdin 将进程链接在一起,内核提供支持,并且有 tee、xargs 和 cpio 等工具可以处理复杂的流程。
- Linux 中高效的 CI/CD 流水线依赖于良好的阶段设计、缓存的大量使用、不可变工件和并行测试。
- 优化 Linux 服务器(CPU、内存、I/O、Docker)以及 Jenkins、GitHub Actions 或 GitLab Runner 执行器是缩短时间的关键。
- 将安全性、可观测性和成本控制集成到流程中,可确保在生产环境中实现可靠、可追溯和可持续的部署。
优化 Linux 中的管道 这不仅仅是关于用符号链接命令的问题。 |这一切背后隐藏着一个完整的世界 性能优化工作流程设计、持续集成/持续交付 (CI/CD)、安全性和操作系统调优,对于构建一个运行缓慢、不稳定的流水线,以及一个高效、可靠且维护成本低廉的流水线,都至关重要。如果您使用 Linux 服务器,无论是在终端中自动化任务还是运行持续集成流水线,了解这些细节都能为您节省大量时间和精力。
本文将结合两种互补的视角:一方面, Linux 命令行中管道的经典用法 (管道、重定向、类似命令 tee, xargs o cpio); 另一方面, Linux 服务器上的 CI/CD 流水线优化这包括缓存、测试并行化、Docker调优、供应链安全和高级工作流指标。所有内容均以西班牙语(来自西班牙)讲解,并配有清晰的示例和非常实用的方法。
什么是管道?管道在 Linux 中扮演什么角色?

“管道”一词源于管道的概念:数据从一点流向另一点。在计算机领域,尤其是在 Linux 系统中,管道是一种机制,它允许一个进程的标准输出成为另一个进程的标准输入。换句话说,一个命令的输出会自动传递给下一个命令,而无需经过中间文件。
在类 Unix 系统中,管道主要分为两种类型。一种是匿名管道或未命名管道,它们只能在密切相关的进程之间使用(例如,父进程和子进程)。另一种是命名管道,也称为 FIFO(先进先出),它允许不直接相关的进程之间进行通信,这些进程甚至可以位于连接到同一网络的不同机器上。
匿名管道通常提供单向通信:一个进程写入,另一个进程读取。相比之下,命名管道允许双向通信,前提是设计得当,例如,通过从两端以读/写模式打开FIFO。它们广泛用于协调需要相互传递数据而不阻塞的守护进程、脚本或服务。
在实现层面,对管道的支持体现在…… Linux内核不是在 shell 中。命令解释器(bash、zsh 等)只是通过系统调用创建管道,例如 pipe() y fork()重定向文件描述符,然后启动每个程序。进程如何阻塞、缓冲区如何管理以及数据如何在生产者和消费者之间传播的真正奥秘,都由系统内核处理。
理解标准输入、标准输出和数据流

要有效地使用管道,理解stdin、stdout 和 stderr的概念至关重要。这些并非抽象概念:Linux 中的每个进程都以三个打开的文件描述符开始,它们指向内核管理的特定资源。
标准输入(描述符 0)和标准输出(描述符 1)可以被视为连接到某个对象的字节流:它可以是终端、文件、网络套接字或管道。它们并非简单的缓冲区;它们是对内核对象(文件类型结构)的引用,而这些内核对象又与 inode、套接字或内部管道结构相关联。
每个过程都有自己的描述符,因此 管道中的每个命令 它独立地处理标准输入和标准输出。例如,在类似这样的行上 ls | grep txt | wc -l中, ls 在管道中写入, grep 它从一根管道读取数据,然后写入另一根管道,并且 wc 从最后一个开始读取。对用户来说,它显示为一个字符串,但实际上它们是多个字符串。 多个串联内核缓冲区每个进程都会根据可用空间或数据情况进行阻塞和恢复。
当第一个进程产生数据的速度超过第二个进程消耗数据的速度时,管道缓冲区就会被填满。此时,后续的写入操作会返回,阻塞发送进程,直到消耗进程…… 阅读足够的信息 这样可以释放空间。这可以防止内存失控;除非使用非阻塞 I/O 或特殊信号,否则数据不会无限累积。例如,在以下情况下: dd if=/dev/sda | gzip -9,是 gzip 压缩速度较慢 dd 他被迫等待。
这种背压机制使得管道即使在阶段之间存在性能不平衡的情况下也能保持相当稳定,这一点也体现在CI/CD 管道的设计中,其中速度较慢的阶段成为需要测量和优化的瓶颈。
Linux 终端中管道的实际应用

在日常使用中,管道用于将命令串联在一行中,并逐步转换数据。无需运行命令、查看输出、复制输出并粘贴到另一个命令中,您就可以用纯文本构建小型、高度灵活的“数据工厂”。
在 Unix 环境中,一个典型的例子是组合使用命令 fortune它会显示随机名言, cowsay它会打印出一头“会说话”的奶牛。使用管道时, Fortune的离去成了Cowsay想要传达的信息。只需一条命令即可完成所有操作。这是一个有趣的例子,但它完美地诠释了将简单工具组合起来完成更复杂任务的理念。
另一种经典方法是发送结果 ls a wc 用于统计行数、单词数和字符数。类似这样的 ls | wc 它可以让您快速查看上架商品的数量。它的妙处在于,您无需使用单个程序来完成所有操作,而是…… 你利用小型、精心设计的实用程序来创造解决方案。.
串联起来也很常见 cat, sort y more (或其他分页器)用于对文本文件进行排序,然后逐页浏览。通过管道,内容可以在命令之间传递,而无需保存到显式的临时文件中,这大大简化了脚本编写和管理任务。
在实际应用中,例如需要将学生名单和成绩分别存储在不同的文件中时,您可以使用 paste 合并列 cut 您可以选择感兴趣的字段,并使用管道符链在一行 shell 脚本中过滤、排序或转换所有内容。这种模式 将大问题分解成简单的命令,并结合管道进行操作。 这是Unix理念的精髓。
充分利用管道的高级命令:tee、xargs 和 cpio
在 Linux 中真正开始实现自动化时,管道会因为一些关键工具而变得更加强大。其中包括: tee, xargs y cpio这与标准数据流配合得非常好。
命令 tee 它就像水管里的“T”字接头:它从标准输入读取数据,写入标准输出,并将相同的输出复制到一个或多个文件中。当您想要……时,它是理想之选。 在屏幕上查看输出结果,同时保存。 稍后再进行审核或在其他阶段进行处理。此选项 -a 它会将数据添加到文件末尾,而不是覆盖原有数据。
例如,你可以使用以下方式对列表进行排序 sort将结果发送至 tee 将其存储在日志中,同时将其传递给 more 这样一来,就可以在单个流程中完成排序、保存到磁盘和方便查看,而无需重复排序过程。
命令 xargs 这是管道中另一个至关重要的组件。它的功能是接收来自标准输入(stdin)的数据(通常是一个元素列表),并将其转换为另一个命令的参数。当程序因为一次接收过多参数而崩溃,或者当你想要……时,它尤其有用。 将工作分成若干批次 有选择 -n这样就限制了每次执行传递的参数数量。
例如, ls | xargs -n 4 你将文件列表分成四组,每组执行目标命令(默认情况下)。 echo(或您指定的那个)多次重复。这样,您可以通过组合使用来构建类似“预览我要删除的内容”这样的管道。 ls, xargs y echo rm 在正式启动擦除操作之前。
处理复杂输入时要谨慎: 包含空格或特殊字符的路径 可以打破默认行为 xargs在这些情况下,它通常与……结合使用。 find 和选项 -print0,它使用空字符分隔元素,以及 xargs -0 这样两端就可以使用相同的可靠分隔符。
最后, cpio 这是一个鲜为人知的命令。 tar但它在通过管道处理文件流方面极其灵活。与 tar 不同,它从一开始就被设计成可以与管道协同工作。 重定向和管道:通过标准输入接收文件列表(通常由……生成)。 find)并生成或使用不带自身压缩的“包”类型文件,然后您可以使用它对其进行压缩 gzip 或类似。
主要模式 cpio 允许创建文件(-o),复制目录树(-p)或提取内容(-i(通常称为“复制输入”)。选项包括: -u 覆盖, -m 保留时间戳或 -d 重新创建目录结构是可能的。 详细控制复制的内容和方式尤其适用于复杂的脚本, tar 不够。
在 Linux 服务器上设计和优化 CI/CD 流水线
除了传统的命令行之外,流水线概念已成为持续集成和持续交付 (CI/CD)领域的基础。在 Linux 服务器上,CI/CD 流水线是一系列自动化步骤:获取代码、安装依赖项、编译、运行测试、打包工件和部署。
Linux 特别适合这项任务,因为它以速度快、稳定性好以及自动化工具生态系统而著称。Jenkins、GitHub Actions 和 GitLab CI 等平台都依赖 Linux 执行器(物理机、虚拟机或容器)来稳定运行流水线。
优化这些流水线不仅意味着让它们“运转起来”,更意味着尽可能减少它们的运行阻力。这意味着缩短检出时间、最大限度地减少重复的依赖项安装、优化 Docker 镜像以避免不必要的重建、重用已生成的工件,以及保持环境的安全性和可观测性。
一个基本的良好实践是将流水线构建成定义明确的阶段:构建、测试和部署。理想情况下,只需编译一次,生成一个工件(二进制文件、软件包、Docker 镜像),该工件可以并行测试不同的变体(例如,不同的语言版本),然后将同一个工件部署到预发布环境和生产环境,而无需重新编译。
使用存储在存储库(S3、Nexus、Artifactory、容器注册表或嵌入在 GitLab/GitHub 中的软件包)中的不可变工件,可以简化审计,实现快速版本回滚,并降低“在我的机器上运行正常,但在生产环境中却不行”的可能性。
前提条件:分发、CI 用户和服务器加固
在纠结于毫秒级的优化之前,重要的是要先在将作为 CI/CD 执行器的Linux 服务器上建立一个稳定的基础。这首先要从选择发行版和最低安全配置开始。
最明智的做法通常是统一使用团队熟悉的长期支持(LTS)或稳定版发行版:例如 Ubuntu LTS、Debian Stable,或者像 AlmaLinux 或 Rocky Linux 这样的企业级发行版。所有运行程序使用同一版本可以避免因作业间库或内核版本不同而导致的意外行为。
另一项建议是配置一个 CI专用用户在没有 root 权限的情况下,sudo 的使用非常有限,仅限于必要的命令(例如, systemctl o docker (如果确实有必要的话)。该用户必须使用 SSH 密钥进行身份验证,才能访问服务器以及与 Git 仓库或其他远程机器进行交互。
在系统层面,建议对服务器进行维护。 更新并进行了最小程度的加固这包括应用安全更新、配置限制性防火墙(例如,使用 UFW:拒绝所有入站流量,只允许必要的流量入站,并允许出站流量出站)以及启用诸如以下工具: fail2ban 为了阻止对 SSH 的暴力破解攻击,并通过以下方式调整一些网络和内核参数 sysctl 提高可靠性和性能。
例如,提高以下限制是很常见的做法: inotify的 为了防止监控大量文件的构建系统耗尽资源,需要调整参数。 vm.swappiness 使内核在使用交换空间时更加保守,这在 CI 作业一次性消耗大量内存时尤为重要。
缓存、Docker 和并行化:CI/CD 中的性能杠杆
如果你仔细查看平均流水线中时间实际消耗在哪里,你会发现很大一部分时间都浪费在了安装依赖项和重建 Docker 镜像上。解决这个问题通常比优化测试代码几毫秒更有效。
第一个关键点是依赖缓存。几乎所有依赖管理工具(pip、npm、Maven、Gradle、Go 模块等)都使用本地缓存目录。在持久化的 Linux 服务器上,您可以让作业之间共享这些目录,或者将它们挂载到持久卷上。这样,每次执行就无需重新下载整个互联网。
对于 Docker,请启用 构建工具包 并构建良好 Dockerfile 这标志着一个转折点。将依赖项安装放在复制 requirements 文件之后、其余代码之前,可以确保只要这些依赖项的版本保持不变,各个层就可以被重用。此外,还可以在构建过程中设置 pip、npm 等工具的特定缓存。
第二个主要杠杆是 并行测试执行许多框架本身就支持并发: pytest 同 -n autoJava 工具,例如 Surefire 和 Jest,以及 JavaScript 中的 Jest。 --maxWorkers等等。将测试套件按模块、文件夹甚至预计时间划分,并在多个工作人员之间进行分配,可以在不改变任何业务流程的情况下,将测试阶段的持续时间缩短 2 到 5 倍。
最后,还有工件和部署的问题。与其为测试环境、预生产环境和生产环境重新编译同一个镜像,更高效的做法是构建一次,将结果保存到代码仓库,并根据部署环境进行标记。这样可以降低 CPU 使用率,避免数据不一致,并显著加快长时间流水线的运行速度。
在 Linux 上优化 Jenkins、GitHub Actions 和 GitLab Runner
每个持续集成系统都有其自身的特点,但它们在 Linux 系统上运行时都能受益于相同的基本理念。关键通常在于使用临时且干净的执行器,维护一个大小合适的持久缓存,并控制并发性。
在 Jenkins 中,一种常见的做法是使用轻量级的临时代理(例如 Docker 容器或 Kubernetes 中的 Pod 或其他容器编排解决方案)来运行作业,同时尽可能简化主节点。这些代理可以配置为 Linux 服务器上的 systemd 服务,向控制器注册并在机器启动时自动启动。
对于使用自托管运行器的 GitHub Actions,建议将其部署在 配备高速固态硬盘的Linux虚拟机要创建一个专用于操作(语言依赖项、构建缓存等)的大型缓存目录,请限制并发作业的数量,以避免 CPU 和磁盘过载。利用官方缓存操作,例如使用以下路径: ~/.cache/pip, ~/.npm o ~/.m2 这在时间上会产生巨大的影响。
在 GitLab Runner 中,选择shell 执行器还是 Docker取决于您对性能和隔离性的平衡需求。shell 执行器速度更快,因为它直接在主机上运行,而 Docker 执行器则提供干净且可复现的环境。您还可以配置共享缓存(本地或 S3),并调整最大并发作业数,以便在不造成硬件过载的情况下充分利用硬件资源。
在所有这些情况下,使用共享卷进行依赖项缓存,同时防止构建之间工作区变得杂乱无章,都至关重要。临时机器或容器会随着每个流水线或流水线组的创建和销毁而大大减少由先前构建残留文件导致的“昨天还能用,今天就不行了”的问题。
Linux 服务器性能:CPU、内存、I/O 和 Docker
无论你的脚本优化得多么出色,如果运行流水线的 Linux 服务器配置不当,你都会遇到无休止的队列和缓慢的作业执行速度。对于一台中端服务器来说,一个典型的合理配置是4-8 个虚拟 CPU 和 8-16 GB 内存,配备 SSD 存储(理想情况下是 NVMe),以及一些交换空间(2-4 GB),以便在不频繁终止进程的情况下应对峰值负载。
文件系统也很重要。使用 ext4 或 XFS,并可选择 noatime 在编译或写入日志的卷中,减少不必要的 I/O。此外,挂载 tmpfs 对于临时文件或短生命周期的文件(例如, /mnt/ci-tmp)加快密集型操作,并防止磁盘在作业之间被残留文件填满。
对于 Docker 而言,守护进程的维护至关重要。安全且定期地移除未使用的镜像和卷,同时维护常用的基础镜像,有助于…… 控制磁盘空间和启动时间. 命令如下 docker system prune 通过适当的时间过滤器,它们可以在不使最近使用的资源过载的情况下进行清理。
如果您的持续集成 (CI) 流程容器密集,您还可以使用镜像寄存器来避免始终从互联网下载数据,使用 BuildKit 实现并发和层缓存,甚至可以为要求最高的执行器配置 CPU 亲和性(CPU 集)或专用节点,从而防止相邻工作负载之间的干扰。此外,了解CPU 微架构有助于您更好地为密集型 CI 工作负载分配资源。
管道安全(DevSecOps)和 Linux 部署
速度快但安全性差的流水线就像一颗定时炸弹。将安全性集成到流水线本身以及Docker 容器安全性中,如今已成为任何 DevSecOps 策略的标准做法,而 Linux 也为此提供了许多工具。
首先,必须极其谨慎地对待密钥和凭证。它们绝不应存在于代码或版本化的配置文件中。相反,它们应该存储在密钥管理器(例如 GitLab 的掩码变量、GitHub 的加密密钥、HashiCorp Vault 等)中,并且仅在需要它们的作业执行期间注入,并尽可能使用短期令牌。
另一个重要环节是生成软件物料清单 (SBOM)和对工件进行签名。Syft 或 CycloneDX 等工具可以列出构成镜像或二进制文件的所有组件,而 Cosign 或其他可验证的签名解决方案则确保只有经过流程验证的工件才能被部署。
在网络和访问方面,建议将持续集成(CI) 网络和生产网络进行隔离,部署严格的防火墙,审核执行日志,并定期轮换凭据。在使用 SSH 时,最好使用带有过期日期的证书或密钥,而不是静态密码。
在 Linux 系统上部署时,蓝绿部署、滚动部署和金丝雀部署等策略可以显著降低部署错误的影响。将应用程序作为 systemd 服务运行,在其前端部署 Nginx 或 HAProxy,并通过健康检查控制版本间的流量,可以实现更新期间几乎零停机时间。
例如,当使用 systemd 重新加载 Nginx 并重启服务时,会使用软停止信号(例如: SIGTERM通过合理的等待时间,可以在进程停止之前耗尽活动连接,从而在后台切换版本时保持用户体验不受影响。
Linux 流水线中的可观测性、指标和成本
一旦流水线启动并运行,下一步就是对其进行衡量,并了解时间和资源的去向。仅仅知道工作流是成功还是失败是不够的;您还需要监控每个阶段的持续时间、排队时间、成功率、部署频率、缓存命中率等等。
使用以下方式导出系统指标是很常见的做法: node_exporter使用 ELK 或 Loki 等解决方案集中管理日志,并在 Grafana 仪表板中可视化所有内容。这样,例如,您可以检测到测试阶段的持续时间是否在上周增加了 30%,或者作业是否花费了太多时间等待可用的执行器; 网络流量监控 开源工具可以增强这种可见性。
也可以对流水线本身进行检测,例如在 GitHub Actions 或 GitLab CI 中,以…… 通过编程方式衡量成功执行的次数、每次运行的持续时间以及总体状态。一个调用提供商 API 的脚本,计算运行总次数、成功运行次数、失败运行次数、成功率和平均持续时间,并将所有信息保存到 JSON 文件中(例如 pipeline-metrics.json)允许您将这些指标集成到报告或仪表板中。
有了这些信息,您就可以决定运行器的大小和数量:有时,与其使用少数几个大型运行器,不如使用多个小型运行器来减少等待时间。自动扩展功能(例如云自动扩展或 Kubernetes 节点动态池)有助于吸收白天的高峰活动,并最大限度地减少夜间资源利用率不足的情况。
这些做法不仅可以改善团队体验,还可以通过控制 CPU、内存,尤其是存储消耗来调整基础设施成本。如果不定期按计划清理图像和缓存,存储消耗往往会飙升。
掌握 Linux 中经典的命令行管道和现代 CI/CD 流水线,就能获得强大的组合:您可以自动化从简单的文本过滤任务到复杂、易于维护、安全且快速的构建、测试和部署流水线的一切操作。了解进程间的信息流、依赖项的缓存方式、服务器的调优方式以及指标和安全机制的集成方式,可以让您构建能够随着团队和项目规模扩展的工作流程,而不会成为持续的瓶颈。
