复活 GitStats:让 Git 历史分析焕发新活力

最近的晚上的时间(一般要等到孩子睡了)我正在做一件事:复活已经沉寂多年的 GitStats 项目。

此前,我曾写过两篇关于 GitStats 的文章,如果感兴趣,可以查阅了解。

什么是 GitStats

GitStats 是一个用 Python 写的工具,用来分析 Git 仓库的历史记录,并生成 HTML 报告。

然而,它只支持 Python 2,且作者已经停止维护(最后一次提交还停留在 9 年前)。

在当前开发环境中,兼容性和使用便捷性都受到很大限制,但不可否认,它的价值依旧存在。

因此,我决定对这个项目进行现代化改造。

我已经完成的工作

  1. **迁移到 Python 3.9+**:重构代码以支持 Python 3 版本。✅
  2. 创建现代化流水线:增加 CI/CD 等工具,便于持续开发和发布。✅
  3. 发布到 PyPI:用户现在可以通过 pip install gitstats 来安装。✅
  4. 提供 Docker 镜像:用户无需自行处理依赖,运行 gitstats 更加便捷。✅
  5. 提供在线预览:创建一个展示页面,让用户直观了解 GitStats 的功能。✅

特别感谢

在这里我要特别感谢 Sumin Byeon(@suminb)。从他的介绍来看,他应该是一位生活在韩国的程序员。

原本 GitStats 在 PyPI 上的 Owner 是他,因此我无法直接使用这个名字。我尝试过其他名字,例如 git-stats 和 gitstory,但都因与其他项目的名字相近而被 PyPI 拒绝。

看到他的项目已经有五年没有维护了,我抱着试一试的心态给他发了一封邮件,问他是否愿意将 GitStats 的名字转让给我,因为我正在重振这个项目。

没想到,他很快回复了,并最终同意将 GitStats 的名字交给我。他唯一的条件是,如果将来我停止维护 GitStats,而其他人需要这个名字时,我也能像他一样将名字交给对方。

THANK YOU

我答应了他,也承诺将长期维护 GitStats。(希望我能够做到)

未来计划

  1. 解决有价值的 Issue:梳理原仓库中未解决的问题,挑选具有价值的进行修复。
  2. 审查现有 Pull Requests:评估原仓库的 PR,视情况合并到当前项目中。
  3. 更新文档:完善文档,使其更清晰易懂。
  4. 添加新功能:增加功能,使项目更强大、更有用。
  5. 优化 UI:提升界面美观性,改善用户体验。

如何参与

如果你对 GitStats 的改进有兴趣,欢迎参与这个项目!你可以:

  1. 建议功能:提出想法或功能请求,帮助项目更贴近用户需求。
  2. 贡献代码: 修复 Bug 或添加功能,为项目直接出力。
  3. 分享推广:将 GitStats 推荐给可能感兴趣的朋友或社区。

最后,让我们携手合作,让 GitStats 再次焕发活力!

写于 2024 年 11 月 28 日凌晨 2:50


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

pip vs pipx 的区别

pip vs pipx 的区别

在 Python 的生态中,pippipx 都是用于管理包的软件工具,但它们有不同的设计目标和使用场景。有些同学可能会疑惑,两者到底有什么区别?该如何选择?


1. pip: 通用的 Python 包管理工具

pip 是 Python 官方推荐的包管理工具,用于安装和管理 Python 包(libraries)。

主要特点

  • 适用于任何 Python 包:可以安装库和命令行工具。

  • 安装在全局或虚拟环境:包默认安装到全局 Python 环境,或者虚拟环境(如 venvvirtualenv)中。

  • 命令简单

    pip install package-name

适用场景

  • 安装开发所需的依赖(如 requestsflask)。
  • 创建项目特定的环境(通常结合虚拟环境使用)。

局限性

  • 如果直接安装到全局环境,容易导致版本冲突。
  • 对于命令行工具(CLI)工具的安装和管理较繁琐,因为它们共享相同的环境。

2. pipx: 专注于隔离安装命令行工具

pipx 是一个专门为 Python 命令行工具(CLI)设计的工具,提供隔离的安装环境。

主要特点

  • 为每个工具创建独立环境:每个 CLI 工具都在自己的虚拟环境中运行,避免冲突。
  • 自动管理依赖:安装工具时,它会自动处理依赖的版本管理。
  • 简化使用体验:CLI 工具直接可用,无需额外配置路径。
  • 命令简单
    pipx install package-name

适用场景

  • 安装和管理 Python CLI 工具(如 blackhttpiecommit-check)。
  • 避免工具之间的依赖冲突。
  • 对开发工具或脚本运行环境要求高的用户。

局限性

  • 仅适用于 CLI 工具,不适合安装普通的 Python 库。
  • 需要先安装 pipx 工具:
    python -m pip install pipx

对比总结

特性 pip pipx
用途 安装和管理所有 Python 包 安装和管理 CLI 工具
安装范围 全局环境或虚拟环境 每个工具独立的虚拟环境
依赖隔离 需要手动管理(结合虚拟环境更好) 自动隔离,工具互不影响
适用场景 开发项目的依赖管理 CLI 工具的独立安装和使用
示例 pip install flask pipx install black

如何选择?

  • 如果你正在构建一个 Python 项目,需要安装项目依赖,使用 pip
  • 如果你需要安装 Python CLI 工具,如 pytestpre-commit,建议用 pipx,以确保独立性和稳定性。

简单来说:pip 是通用工具,pipx 是针对 CLI 工具的专用解决方案


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

用于 DevOps 的 Nix 和 NixOS

当 CI 或更糟的是生产发生灾难性故障时,“在我的计算机上工作”一直是毫无帮助的答案。除其他外,Nix 是一种通过提供可重复、声明性和可靠的系统来解决此问题的方法。这使得它成为通常称为 DevOps 的两个方面的绝佳工具:操作系统的开发和流程。这篇文章将通过一个实际示例展示这两个方面,但首先,让我们从鸟瞰的角度看看这些承诺到底意味着什么。

可重复

Nix 的灵感来自一种函数式编程语言,它将软件包和配置本身的构建过程建模为“纯”函数。相同的输入应该始终产生相同的输出。虽然这听起来相当抽象,但在实践中,这意味着如果它在你的笔记本电脑上运行,它将在生产服务器、CI 或你的同事的机器上运行完全相同。Nix 严格禁止你使用未声明的依赖项,所有内容都由加密哈希固定,并且软件包的评估和构建彼此独立。

声明式

虽然简单的脚本或其他更复杂的工具(如 Ansible)会告诉你的机器“该做什么”才能达到某种状态,但在编写 Nix 代码时,你将“定义某物是什么”。对于任何做过函数式编程的人来说,这不是一个新概念。但是,虽然差异很小,但影响却很大。声明式配置是上面讨论的可重复性和部署过程的幂等性的重要组成部分。Nix 不仅允许共享配置和构建说明,还允许共享项目本身的开发和构建环境。只需几行代码,你就可以添加一个开发环境,其中包含团队中每个开发人员在项目上工作所需的所有工具、编程语言和固定版本。

可靠的

安装软件包时绝不会破坏其他软件包。同一软件的不同版本之间的升级也是如此。Nix 不仅提供原子升级,还确保一个软件包永远不会破坏其他软件包。你甚至可以(并且通常会)在同一系统上愉快地共存同一软件包的多个版本或配置。甚至更好的是,你可以根据需要回滚或在所谓的代之间切换。在升级过程中,永远不会出现不一致的状态,想象一下在旧版本旁边安装和配置新版本的软件包,并在一切准备就绪后切换到新版本。

好的,它是如何工作的?

首先,为了避免混淆,先介绍一些术语。Nix 指两件事:

  • 声明式包管理器
  • 用于定义包和配置的编程语言

另一方面,NixOS 是一个围绕 Nix 包管理器构建的 Linux 发行版,它使用其功能来定义整个系统配置。

Nix 打破了众所周知的 Linux 文件系统层次结构。如果你曾经使用过它,你会偶然发现下面有一个相当大的目录/nix/store,里面有很多神秘的路径。这就是所谓的 Nix 存储,Nix 将所有软件包存储在其自己独特的子目录中,例如:

/nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1/

将所有内容放入一个大目录中可能听起来违反直觉,但这实际上是实现 Nix 大部分魔力的概念。每个存储路径都具有相同的结构:

/nix/store/<hash>-<name>-<version>

其中哈希是根据包的所有依赖项计算得出的唯一标识符(准确地说:包的构建依赖关系图的加密哈希)。

但为什么?

这种非常简单的结构允许很多理想的特性。首先,相同的路径将具有完全相同的内容。这是我们确保可重复性的第一步。它还确保文件不会在你不知情的情况下被篡改,因为哈希会以数学方式验证内容。

现在,你可以同时拥有同一软件包的多个版本。它们将具有不同的哈希值,因此位于存储中的不同路径中。不再存在软件包之间的依赖版本冲突(即“DLL-hell”),每个软件包都可以引用和使用自己所需的版本。

一个重要的结果是,升级或卸载应用程序等操作不会破坏其他应用程序,因为这些操作永远不会“破坏性地”更新或删除其他软件包使用的文件。这使我们能够实现所谓的原子升级和回滚。

/usr/lib 像在传统 Linux 系统上一样摆脱全局位置可确保不存在未在包中指定的隐藏依赖项。如果它在一个系统上构建,它将在另一个系统上构建,无论安装了什么其他软件。

实际上,软件包是根据 Nix(语言)表达式构建的。从这里开始,Nix 计算出派生。这最好被描述为“构建操作”,即构建特定软件包所需的所有依赖项、工具、环境变量、源和步骤的完整规范。派生与编程语言无关,并且具有确定性。

通过哈希严格标识系统的每个包和部分还可以实现强大的缓存。当指示构建

/nix/store/b6gvzjyb2pg0...-firefox-33.1

从源头开始,Nix 会首先检查它是否已存在于商店或任何已配置的缓存中,如果已存在,则从那里提取。实际上,从源头构建只是常用软件包的后备方法

Flakes

Flakes 是 Nix 的一个新功能,最好被描述为“将 Nix 表达式打包成可组合实体的机制”。实际上,flake 是一个文件系统树(通常从 Git 存储库或 tarball 中获取),其中包含根目录中名为 flake.nix 的文件。

它们是一种标准化接口,用于拆分和分发 Nix 代码,并使重用和组合变得容易。我们将在以下部分中使用此格式,并flake.nix逐步构建你的文件,并在过程中进一步解释。

一个实际的例子

说完这些,让我们看看 Nix 在实践中是如何使用的。以下示例将演示使用 Nix 在任何可能的地方构建(DevOps 中的“Dev”)和部署(DevOps 中的“Ops”)示例 Go 应用程序的 DevOps 流程。

开发(Dev)

对于“开发”部分,我们首先介绍一下我们的示例应用程序。一个用 Go 编写的非常简单的 Web 服务器。假设我们使用 Go 模块,即运行 go mod init 并为我们的应用程序 go mod tidy 创建一个 go.modgo.sum 文件。package main

import (
"fmt"
"net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Hello World!\n")
}

func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8080", nil)
}

最简单的形式是,flake 是定义属性的outputs和 (可选)inputs和 的属性集description。输入是 flake 中使用的源或依赖项,在大多数情况下是 git 存储库或要从中获取的纯 URL。输出通常是要在其他 flakes 中使用的包、部署说明、配置或 Nix 代码(函数)。虽然输出属性集可以采用你想要的任何形式,但常见输出有标准化名称。

为了“nixify”我们的项目,让我们首先在flake.nix 存储库的根目录中添加一个名为的文件,其中包含一个非常基本的薄片:


{
description = "A very basic flake";

inputs = {
nixpkgs.url = "github:nixos/nixpkgs";
};

outputs = { self, nixpkgs }: { };
}

{
description = "A very basic flake";

inputs = {
nixpkgs.url = "github:nixos/nixpkgs";
};

outputs = { self, nixpkgs }: { };
}

我们的 flake 定义github.com/nixos/nixpkgs为输入,目前没有输出。虽然它目前还不是很有用,但它是有用的。我们可以用它nix flake metadata 来显示一些关于它的信息。

❯ nix flake metadata
Resolved URL: git+file:///home/pinpox/code/example_app
Locked URL: git+file:///home/pinpox/code/example_app
Description: A very basic flake
Path: /nix/store/c4vxaphd27qjl253m5lmqrb3isg9rc5h-source
Last modified: 2022-05-30 12:09:33
Inputs:
└───nixpkgs: github:nixos/nixpkgs/0907dc851fa2e56db75ae260a8ecc9880dc7b49

如果尚不存在,这还将 flake.lock 为我们创建一个文件,将我们所有的输入固定到特定版本,并通过输入的哈希值进行验证。

添加包

完成基本样板后,我们可以添加第一个输出:应用程序的包。

packages.x86_64-linux = {
default = pkgs.buildGoModule {
pname = "example_app";
version = "1.0.0";
src = ./.;
vendorSha256 = "sha256-aCFVUq58hpK7O9DoYJ/7Sr4ICSUzz/JHNrse40um1n4=";
};
};

上面指定了如何在具有系统架构的 Linux 系统上构建我们的应用程序x64_64。我们可以使用通用mkDerivation函数来定义我们的包(派生),但 Nix 包含大多数常见编程语言和框架的辅助函数。这里buildGoModule用于定义我们的 Golang 项目的包,指定源为当前目录./.、名称、版本以及我们文件中指定的依赖项的哈希值go.mod,因为所有版本都必须用哈希值固定。

我们现在可以使用来构建我们的应用程序。这将构建我们的应用程序并在 nix 存储中nix build创建指向它的符号链接。result

ls -l
lrwxrwxrwx 61 pinpox 7 Jun 16:17 result -> /nix/store/0yasl97rl4drf9rgmbaqbcbii0rsizsi-example_app-1.0.0
.rwxr-xr-x 6,2M pinpox 7 Jun 16:06 example_app
.rw-r--r-- 534 pinpox 7 Jun 15:44 flake.lock
.rw-r--r-- 571 pinpox 7 Jun 16:08 flake.nix
.rw-r--r-- 80 pinpox 7 Jun 15:20 go.mod
.rw-r--r-- 189 pinpox 7 Jun 15:20 go.sum
.rw-r--r-- 415 pinpox 7 Jun 15:22 main.go

好吧,但我们本可以省去麻烦,直接go build买同样的东西,对吧?嗯,不完全是。

Nix 和 flakes 承诺为我们提供密封评估,这意味着构建应用程序所需的一切都固定在特定版本并使用校验和进行验证。这包括应用程序本身的代码,也包括使用的编译器、任何其他依赖项、工具和软件包以及系统架构本身。这不仅确保我们的应用程序不会因外部因素而中断,而且还可以在任何机器上构建。无论是同事的笔记本、CI 还是生产,都不再有“(仅)在我的计算机上工作”的情况。由于 Nix 与语言无关且不特定于 Go,因此我们还拥有一个用于以任何语言构建软件的通用接口。构建和运行(nix run)nixified go 应用程序的过程保持不变。

需要明确指出的是,在使用 Nix 构建或运行应用程序之前,系统上不需要安装任何先决条件,例如 go 编译器或任何其他工具(Nix 本身除外)。Nix 将创建 flake 指定的完整环境。第一次运行时将获取输入,然后从那里开始使用哈希进行检查,以确保确定性构建,同时尽可能多地缓存。

添加 shell(临时环境)

虽然包定义已经允许我们构建和运行我们的应用程序,但它并不真正适合开发。通过在输出中添加 Nix shell,我们可以创建一个开发环境,其中包含所有开发人员都可以使用的特定版本的所有工具。我们不必让每个开发人员浪费时间为新项目设置技术堆栈,而是可以传递一个 shell,其中包含在其指定版本中可用的所有工具。

由于我们项目的要求都已打包在 nixpkgs 中,因此我们可以在输出中添加一个简单的 shell,其中包含以下几行:

devShell.x86_64-linux = pkgs.mkShell {
buildInputs = with pkgs; [
go
gopls
gotools
go-tools
];

shellHook = ''
GOPATH=$HOME/go
'';
};

现在,nix flake show 将向我们展示两个输出:我们之前指定的包和新添加的shell。

❯ nix flake show
git+file:///home/pinpox/code/example_app
├───devShell
│ └───x86_64-linux: development environment 'nix-shell'
└───packages
└───x86_64-linux
└───default: package 'example_app-1.0.0'

我们可以通过运行进入 shell nix develop,然后会进入一个
包含我们需要的所有工具的 shell。

❯ nix develop
[pinpox@ahorn:~/code/example_app]$ go version
go version go1.17.10 linux/amd64

在此示例中,我们仅使用了 中预先打包的工具和依赖项nixpkgs。当然,也可以指定 之外的工具nixpkgs或覆盖特定版本的软件包。这可以通过添加你自己的软件包定义或使用overrides和覆盖) 来动态修改现有软件包来实现。在我们的 shell 中指定的工具buildInputs当然也固定到某个版本,因为我们的nixpkgs输入在 flake.lock 文件中固定到特定的 git 提交。

行动 (Ops)

到目前为止,我们只使用了 Nix,即包管理器,正如开头所述,它是一个单独的工具。对于操作部分,让我们以 Linux 发行版 NixOS 为例,它采用了 Nix 原则并将其应用于完整的系统配置。核心思想很简单,只是我们已经看到的 Nix 的自然延伸:就像我们的包存储在商店中的隔离路径中一样,我们也将其应用于配置。例如,SSH 服务器的配置可以用 Nix 语言定义,并在评估后/nix/store/5rnfzla9kcx4mj5zdc7nlnv8na1najvg-firefox-3.5.4/存储在路径中。/nix/store/s2sjbl85xnrc18rl4fhn56irkxqxyk4p-sshd_config

这使得整个操作系统利用了我们在软件包中看到的优势:它是独立的,可以回滚,并且不会在没有通知的情况下发生变化,因为所有内容都再次通过哈希进行验证。

该nixos-rebuild工具用于执行这些操作。要切换到新配置:

nixos-rebuild switch

每次构建配置后,你都会获得所谓的代数。这是你可以切换或回滚到的点。同样,如果出现问题或无法按预期工作

nixos-rebuild switch --rollback

将带你回到上一代。在启动时,你可以选择任何已保存的一代。

为了澄清这一点,NixOS 完全围绕 Nix 包管理器构建。它用于以纯函数式语言构建内核、应用程序、系统包和配置文件。这可以实现原子系统升级和回滚整个系统等功能。此外,该系统完全可复制,这使得重新安装或复制变得容易。另一个例子:

$ nixos-rebuild build-vm
$ ./result/bin/run-*-vm

将在虚拟机内构建你的系统配置并启动它。虚拟机将具有与你的主机系统本身相同的配置,允许你根据需要进行测试、实验和“预览”,而不会冒破坏主机的风险。

配置

系统配置通常在名为 configuration.nix

一个非常简单的例子如下

{
boot.loader.grub.device = "/dev/sda";
fileSystems."/".device = "/dev/sda1";
services.sshd.enable = true;
}

这个最小配置足以构建一个运行 SSH 守护进程的机器。使用 flake 时,我们还将flake.nix在输出下将配置添加到我们的 flake中nixosConfiguration 。

{
outputs = { self, nixpkgs }: {
# replace 'my-hostname' with your hostname here.
nixosConfigurations.my-hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
};
}

然后将薄片传递给nixos-rebuild命令

nixos-rebuild switch --flake '/path/to/flake#my-hostname'

模块

你可以在系统配置中设置的所有选项都来自模块,这些模块是包含 NixOS 表达式的文件。该configuration.nix文件也是一个模块。大多数其他模块位于nixpkgs 存储库中。模块是随后由 NixOS 组合以生成完整系统配置的文件。

完整解释模块系统超出了本文的范围,因此我们重点介绍上述应用程序的一个实际示例。我们将向你的flake.nix文件添加一个模块,以便任何人都可以导入它,从而生成应用程序的运行实例。

该模块只有一个名为“enable”的选项,设置为 true 时会将下面的部分添加config=到系统配置中。这是保存在 中的完整模块module.nix:

{ lib, pkgs, config, ... }:
with lib;
let
cfg = config.services.hello;
in
{
options.services.hello = {
enable = mkEnableOption "hello service";
};

config = mkIf cfg.enable {
systemd.services.hello = {
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.hello}/bin/hello -g'Hello, ${escapeShellArg cfg.greeter}!'";
};
};
}

要导入它,只需nixosConfigurations按照添加文件的方式将其添加到输出中 configuration.nix:

modules = [ ./configuration.nix ./module.nix ];

该模块创建一个运行我们应用程序的 systemd 单元。通常,你还会在此处添加反向代理的配置,以及环境变量、其他依赖应用程序和设置、用户、组以及我们的应用程序运行时应存在的其他属性。

部署

假设我们有一个正在运行的 NixOS 主机,并且具有 SSH 访问权限,我们可以部署你的配置

nixos-rebuild build --flake '.#my-hostname' --target-host root@our.host.tld

瞧,我们的应用程序正在运行!

关于 Docker 的说明

在介绍 nix 时,一个反复出现的问题是:“那么 docker 呢?”虽然 Nix 和 Docker 本质上是用于不同事物的工具,但毫无疑问人们会滥用两者来解决重叠的问题。

Docker 缺少可重复性

对于可重现的环境,Docker镜像可用于存档类似内容。请注意,这里特指构建镜像,因为 Dockerfile 或容器定义不可重现。这可以通过多次构建镜像并比较其校验和来轻松确认

docker save $(docker build --no-cache -q .) -o img1.tar
docker save $(docker build --no-cache -q .) -o img2.tar

sha256sum img1.tar
b830edb19a8653ef6ef5846a115b7ab90fdd8ce828a072c3698b21f13429e8c7 img1.tar

sha256sum img2.tar
c07301820e59aefad9b36feeca4c0da911e88b56b56a083fdea8d1763bd0c5f3 img2.tar

这可以归因于多种因素,例如 Dockerfile 命令

这个表达式中的“latest”是什么意思?

FROM ubuntu:latest

运行此代码时将安装哪个版本的 Python?

RUN apt-get update && apt-get install python -y

在可能的多个条目中哪一个$PATH将会运行?

CMD [ "somebin" ]

对于其中一些问题,有一些解决方法,但是 Docker(或者更具体地说是 Dockerfile)首先不是为可重现而构建的,并且今天有许多现实世界的映像构建示例,但几个月后就不会了。

Nix + Docker

但问题并不一定非此即彼。事实上,Nix 和 Docker 一起使用,可以完美地互补。

Nix 构建 Docker 镜像

Nix 可用于构建 docker 镜像。Nix 提供了多个实用函数,例如pkgs.dockerTools.buildImage和,pkgs.dockerTools.buildLayeredImage它们可用于将 docker 镜像构建为 flake 输出,就像任何其他包一样。Matthew Croughan 最近在 MCH2022 上发表了关于其使用的简短演讲。

它还可以用于对 Docker 层缓存进行更细粒度的优化,正如Graham Christensen 所详述的那样。

NixOS 部署容器

NixOS 提供了一种非常优雅的运行容器的方式。这是配置 NixOS 以运行容器的示例

virtualisation.oci-containers.containers = {
bitwardenrs = {
autoStart = true;
image = "bitwardenrs/server:latest";
environment = {
ADMIN_TOKEN = "myAdminTokenString";
DOMAIN = "https://pw.mydomain.com";
INVITATIONS_ALLOWED = "true";
SIGNUPS_ALLOWED = "true";
};
ports = [
"80:80"
];
volumes = [
"/var/docker/bitwarden/:/data/"
];
};
};

它将设置运行容器所需的一切,并生成匹配的 systemd 单元来启动、停止和管理容器。全部由哈希固定。

将 Nix 和 NixOS 与容器运行时结合使用是一个过于广泛的主题,无法在此完全涵盖,并且上述示例只能触及可能性的表面。

进一步阅读

这只是 Nix 和 NixOS 的冰山一角。上面和下面有多层抽象,还有简化使用和配置的工具。部署工具用于管理大量主机,如nixOps或lollypops,机密管理,如sops-nix或agenix ,以及 CI 系统,如Hydra 。Nix 与容器配合得很好,其生态系统不断发展和演变,仅上个月就有 534 人合并了 2,981 个 Pull 请求。


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

Commit Check 更新:新增两个实用功能提升代码质量保障

最近有用户提出两个需求:一是支持在 Pull Request 中增加评论,二是检查 Pull Request 是否已经 rebase。

经过几晚的努力,现在正式宣布在最新的 commit-check 以及 commit-check-action 中新增两个重要功能:pr-commentsbase-merge

这两个功能旨在进一步提升 Pull Request (PR) 的检查能力。

1. pr-comments: 自动添加检查结果到 Pull Request

在团队合作开发中,PR 通常是代码审核的主要入口。为了让代码检查结果更直观,pr-comments 提供了一种新方式:

当代码提交触发 CI/CD Pipeline 后,commit-check 会自动在 Pull Request 界面中以评论形式呈现检查结果。

无需额外点击或切换到日志文件,开发者可以直接在 PR 的对话区域查看检测结果,方便快速定位问题。

成功和失败的示例效果:

pr-comments success

pr-comments failure

注:pr-comments 仅支持 commit-check-action

2. base-merge: 确保分支基于目标分支

在开发过程中,有些团队希望每个 Pull Request 都基于最新的目标分支进行开发。

commit-check 提供了一个新的选项:base-merge,可以帮助团队确保分支已 rebase 到指定的目标分支(例如 main 或 master)。

  • 自动检查当前分支是否基于指定目标分支。
  • 如果检测到基线不正确,commit-check 会返回错误信息,让 CI Pipeline 失败,并提供明确的提示。

注: base-merge 支持 commit-checkcommit-check-action


什么是 Commit Check

如果你还不了解 Commit Check,这里简单介绍一下:

Commit Check 是一个免费且强大的工具,用于强制执行提交元数据标准,包括提交消息、分支命名、提交者姓名/邮箱以及提交签名。它的错误信息和建议命令可以完全自定义,确保团队之间的一致性。

作为 GitHub Enterprise 元数据限制 和 Bitbucket 付费插件 Yet Another Commit Checker 的替代方案,Commit Check 通过集成 DevOps 原则和基础设施即代码(IaC)脱颖而出。

它是目前针对 Conventional Commit 和 Branch 支持最好的免费开源解决方案。


配置

使用默认配置

如果没有设置 .commit-check.yml,Commit Check 将使用默认配置。提交消息将遵循 Conventional Commits 规则,分支命名遵循 Conventional Branch 规则。

自定义配置

如果需要更改配置,可以在 .commit-check.yml 中进行自定义:

checks:
- check: message
regex: '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)'
error: "The commit message should be structured as follows:\n\n
<type>[optional scope]: <description>\n
[optional body]\n
[optional footer(s)]\n\n
More details please refer to https://www.conventionalcommits.org"
suggest: Please check your commit message against the above regex.

- check: branch
regex: ^(bugfix|feature|release|hotfix|task|chore)\/.+|(master)|(main)|(HEAD)|(PR-.+)
error: "Branches must begin with these types: bugfix/ feature/ release/ hotfix/ task/ chore/"
suggest: Run command `git checkout -b type/branch_name`

- check: author_name
regex: ^[A-Za-z ,.\'-]+$|.*(\[bot])
error: The committer name seems invalid
suggest: Run command `git config user.name "Your Name"`

- check: author_email
regex: ^.+@.+$
error: The committer email seems invalid
suggest: Run command `git config user.email yourname@example.com`

- check: commit_signoff
regex: Signed-off-by:.*[A-Za-z0-9]\s+<.+@.+>
error: Signed-off-by not found in latest commit
suggest: Run command `git commit -m "conventional commit message" --signoff`

- check: merge_base
regex: main # it can be master, develop, devel etc. based on your project.
error: Current branch is not rebased onto target branch
suggest: Ensure your branch is rebased with the target branch

用法

作为 GitHub Actions

name: Commit Check

on:
push:
pull_request:
branches: 'main'

jobs:
commit-check:
runs-on: ubuntu-latest
permissions: # use permissions because of pr-comments
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # checkout PR HEAD commit
fetch-depth: 0 # required for merge-base check
- uses: commit-check/commit-check-action@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # required for pr-comments
with:
message: true
branch: true
author-name: true
author-email: true
commit-signoff: true
merge-base: false
job-summary: true
pr-comments: ${{ github.event_name == 'pull_request' }}

作为 pre-commit hook

将以下配置添加到 .pre-commit-config.yaml 文件:

-   repo: https://github.com/commit-check/commit-check
rev: the tag or revision
hooks:
- id: check-message # requires hook prepare-commit-msg
- id: check-branch
- id: check-author-name
- id: check-author-email
- id: check-commit-signoff
- id: check-merge-base # requires downloading all git history

作为 CLI 工具

从 PyPI 安装:

pip install commit-check

# example
commit-check --message --branch --author-name --author-email --commit-signoff --merge-base

更多用法详见 README


如果有任何问题或建议,欢迎在 GitHub Issues 中提出。


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

PowerShell is not recognized as an internal or external command

Recently, while setting up a new Windows Server 2022, I encountered an issue where my Ansible playbook, which previously worked without problems, failed to execute.

Here’s the configuration I used for the Windows host in my Ansible inventory:

[jenkins-agent-windows:vars]
ansible_user=
ansible_ssh_pass=
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_winrm_server_cert_validation=ignore

However, when I ran the playbook, the following error occurred:

winrm send_input failed;
stdout:
stderr 'PowerShell' is not recognized as an internal or external command, operable program or batch file.

Cause of the Issue

This is usually the case when the SYSTEM’s PATH environment variable has been changed and is no longer able to find PowerShell.exe in the path.

Please verify the PATH environment contains the entry C:\Windows\System32\WindowsPowerShell\v1.0 in there.

Solution

Right-click This PC > Properties > Advanced system settings > Environment Variables.

After adding C:\Windows\System32\WindowsPowerShell\v1.0 to PATH, the error disappeared, and my Ansible playbook executed successfully.

从早到晚,我的 DevOps 一天

很多人可能会好奇,作为一名 DevOps 工程师,每天究竟忙些什么呢?今天就来简单聊聊,作为 DevOps/Build/Release 工程师,我的日常工作节奏是怎样的。

工作准备

每天早上九点半到公司,第一件事就是打开 Slack 和邮箱,优先处理那些紧急或容易回复的消息。遇到比较复杂的内容,就会设置提醒,以防漏掉。之后,会把当天的任务列入 To-Do List,再检查 Jenkins 上是否有失败的任务需要关注。这一系列动作大概会花半小时左右。

咖啡时间

十点左右是咖啡时间——一天的正式开始。如果十点半有站会,那就是一个快速的回顾和计划环节,主要是分享昨天的进展、当天的任务安排,也和团队同步一下各自的状态。

日常工作

开始工作后,我会打开 VSCode,接着前一天没完成的任务。平时常用的代码仓库包括 pipeline-libraryansible-playbookdocker-imagesinfra,它们分别负责管理流水线、自动化脚本、容器和基础设施。几乎每天都会对这些仓库进行一些更新或优化。

Build 和 Release 也是我的主要工作之一。构建任务已经实现了自动化,团队成员通过 Multibranch Pipeline 自行构建;我主要负责分支管理、发布时的合并和冲突解决,确保发布信息的准确和版本的合规性。

此外,还有一些日常任务,比如:

  • 维护和升级构建环境
  • 收集代码覆盖率,生成报告
  • 升级编译器,处理相关问题
  • 管理虚拟机分配,帮团队解决环境问题

上午的主要工作还是消息回复和问题处理,之后再逐一处理 To-Do List。

午餐与休息

中午十二点半左右和同事一起午餐。吃饭时聊聊天,也是练习英语的机会。饭后,有时会和同事一起在附近散步,或者自己跑步运动一下。

下午

下午是主要的产出时间。从一点半到四点半,专心处理 To-Do List 上的任务,尽量推进工作进度。四点半之后,美国同事上线,可能会有会议或讨论需求。

晚间时光

晚上是家人时间。天气渐冷,不方便带孩子出门散步,我们偶尔会去超市采购。如果孩子自己看书或看动画片,我会利用时间给开源社区做点贡献,或是写文章。

这就是我在 DevOps 岗位上的一天,一边忙工作,一边兼顾家庭和爱好。希望这个小分享能让大家更了解这个岗位的日常。

​你更喜欢我分享一些技术,还是更偏爱这种工作、生活的日常?欢迎留言告诉我!


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

What Optimizations I Made During the Jenkins Upgrade

Background

Recently, I’ve been working on migrating and upgrading Jenkins. The main motivation is the vulnerability CVE-2024-23897.

Jenkins 2.441 and earlier, LTS 2.426.2 and earlier does not disable a feature of its CLI command parser that replaces an ‘@’ character followed by a file path in an argument with the file’s contents, allowing unauthenticated attackers to read arbitrary files on the Jenkins controller file system.

To address this, Jenkins needs to be upgraded to at least version 2.442 or LTS 2.426.3 or above. This was also an opportunity to rework parts of the setup that weren’t initially optimized.

Pre-Upgrade Jenkins

Before the upgrade, we were using Jenkins 2.346.3, the last version supporting Java 8. Because older operating systems don’t support Java 17, this blocked us from upgrading Jenkins.

That said, our initial setup was already well-structured:

  • We followed the Infrastructure as Code principle, deploying Jenkins through Docker Compose.
  • We adhered to the Configuration as Code principle, managing all Jenkins Pipelines with a Jenkins Shared Library.
  • We used Jenkins Multibranch Pipeline to build and test projects.

However, there were some limitations, such as:

  • The Jenkins server didn’t have a fixed domain name like jenkinsci.organization.com, but instead had a format like http://234.345.999:8080. Whenever the IP or hostname changed, Webhook configurations for this Jenkins instance had to be updated manually in the Git repository.
  • We hadn’t adopted Docker Cloud. While many tasks used Docker for builds, we weren’t utilizing Docker JNLP agents to create dynamic agents for builds that would automatically be destroyed upon completion.
  • The naming and code structure of the Jenkins Shared Library needed refactoring, as it was initially created for a single team, which limited repository naming.
  • We hadn’t yet used Windows Docker Containers.
  • Some Jenkins plugins were likely outdated or unused but still present.
  • Jenkins and its plugins weren’t regularly updated due to the Jenkins Agent version restrictions.

Post-Upgrade Jenkins

Building on prior best practices, we made the following improvements:

  • Continued following the Infrastructure as Code principle, and using Nginx as a reverse proxy, we deployed Jenkins with Docker Compose to ensure a stable domain name.
  • Continued to follow the Configuration as Code principle.
  • Continued using Jenkins Multibranch Pipeline for building and testing projects.
  • Where possible, implemented Docker Cloud for builds.
  • Renamed the Jenkins Shared Library to pipeline-library (aligning with Jenkins’ naming conventions) and refactored many Jenkinsfiles and Groovy files.
  • Introduced Windows Docker Containers to build Windows components.
  • Utilized the Jenkins Configuration as Code plugin and scheduled regular configuration backups.
  • Installed only necessary Jenkins plugins and exported the current plugin list using the plugin command.
  • Attempted to automate plugin backups before upgrading, enabling quick rollback if the upgrade fails.

Summary

I hope these efforts enable Infrastructure maintenance and Pipeline development to be managed through GitOps.

Through continuous exploration, experimentation, and application of best practices, I aim to establish CI/CD as a healthy, sustainable, self-improving DevOps system.

从 Jenkins 升级,我做了哪些优化

背景

我最近在做的一件事情是迁移并升级 Jenkins。主要动机是因为这个漏洞 CVE-2024-23897

Jenkins 2.441 及更早版本、LTS 2.426.2 及更早版本未禁用其 CLI 命令解析器的一项功能,该功能会将参数中文件路径后的“@”字符替换为文件内容,从而允许未经身份验证的攻击者读取 Jenkins 控制器文件系统上的任意文件。

因此需要将 Jenkins 至少升级到 2.442 或 LTS 2.426.3 及以上版本,也趁此机会重新重构之前没有做满意的部分。

升级之前的 Jenkins

升级之前我们使用的是 Jenkins 2.346.3,这是最后一个支持 Java 8 的版本。由于老的操作系统不支持 Java 17,导致无法升级 Jenkins。

实际上,在升级之前我们已经做得还不错:

  • 遵循了 Infrastructure as Code 原则,我们通过 Docker Compose 部署 Jenkins。
  • 遵循了 Configuration as Code 原则,使用 Jenkins Shared Library 来管理所有的 Jenkins Pipeline。
  • 使用 Jenkins Multibranch Pipeline 来构建和测试项目。

但也存在一些不足之处,比如:

  • Jenkins 服务器没有一个固定的域名,比如 jenkinsci.organization.com,而是 http://234.345.999:8080 这样的格式。所有配置到这台 Jenkins 上的 Webhook 当 IP 或 hostname 变化时,需要从 Git 仓库同时修改。
  • 没有使用 Docker Cloud,虽然很多任务已经使用 Docker 构建,但没有使用 Docker JNLP,也就是动态创建 Agent 来进行构建,完成后自动销毁。
  • Jenkins Shared Library 的名字和代码结构需要重构。当初创建时只是为一个团队而做,因此仓库名字比较受限。
  • 没有使用 Windows Docker Container。
  • 有的 Jenkins 插件可能已经不再使用,但仍然存在。
  • 由于 Jenkins Agent 版本的限制,Jenkins 和插件没有及时更新。

升级后的 Jenkins

在保留了之前好的实践的基础上,我们进行了以下优化:

  • 继续遵循 Infrastructure as Code 原则,同时通过 Nginx 作为代理,使用 Docker Compose 与 Jenkins 一起部署,确保拥有一个固定的域名。
  • 继续遵循 Configuration as Code 原则。
  • 继续使用 Jenkins Multibranch Pipeline 来构建和测试项目。
  • 尽可能使用 Docker Cloud 来构建。
  • 将 Jenkins Shared Library 重命名为 pipeline-library(与 Jenkins 官方命名一致),并对大量 Jenkinsfile 和 Groovy 文件进行了重构。
  • 引入 Windows Docker Container 构建 Windows 部分。
  • 使用 Jenkins Configuration as Code 插件,定期备份配置。
  • 仅安装必要的 Jenkins 插件,并通过 plugin 命令导出当前的插件列表。
  • 尝试在升级前自动备份插件,确保升级失败时能够快速回滚。

总结

我希望通过这些努力,将 Infrastructure 的维护和 Pipeline 的开发通过 GitOps 方式进行管理。

不断探索、尝试和应用最佳实践,使 CI/CD 成为一个健康的、可持续维护的、自我改进和成长的 DevOps 系统。


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

选择往往比努力更重要

偶尔深夜躺下时,我常常在想,我是怎么就走到这了?这都是源于毕业后的一系列选择吧!

也时常感慨,选择往往比努力更重要。回顾过去十余年,这几个决定对我走到今天起到了至关重要的影响。

1. 毕业之后去上海

2009年刚毕业时,我的目标很简单,就是找到一份和专业相关的工作,不论在哪,不论具体做什么,没任何计划,只要能提供一份能养活自己的工作就行。

当时,有同学已经找到手机测试的工作,并被派到上海出差,我得知之后他们还在招聘,也应聘了这家公司。

还记得应聘完不久,我就坐上了回家的火车。列车从沈阳北站出发时,我接到了公司的电话,通知我面试通过,可以来签合同了。就在火车到达沈阳站时,我毫不犹豫地下了车,还退掉了火车票,开始了人生的第一次真正选择。

我的第一份测试工作就这样开始了。那时候真的很敢闯,说走就走,然后就独自一个人去了上海。

上海对我来说是一个新鲜的、充满魔力的城市,即使是住在公司郊区的宿舍,生活依然快乐和精彩。

在上海,我去过世博会、首家苹果店开业,当然还有南京路、外滩、杭州西湖;还看过刘翔在钻石联赛跑110米跨栏,看周杰伦的上海演唱会。周末的晚上还会和同事一起聚餐到半夜,那时候大家都是刚毕业的小伙子,同事之间相处起来更像是同学。

2. 从上海回到沈阳

在上海出差了一年多,又到了选择的时候,是回到沈阳分公司还是辞职在上海找一份新的工作?我和一部分同事选择回到沈阳分公司。

回到沈阳,那里的办公室、食堂、工厂和宿舍都在一个大大的厂区里,周围是郊区,只有周末才能出去逛逛。

我感觉到在这个郊区,我就是这个工厂里的螺丝钉,看到了那种一眼望到头的生活。

日子虽然过得平稳,但不应该是我这个二十来岁的年龄该追求的,我知道这不会持续太久,如果不及时调整,等到有一天没什么一技之长时会很被动。我开始思考:如果将来我想去大连,我现在的这份手机测试是很难找到工作的,因此我要转做 Web 测试,哪里要我,我就去哪里,我需要的就是相关工作经验。

后来我是在沈阳东软面试上了北京东软的岗位,去北京的工资是3000,于是我毅然决然去了北京。

3. 从沈阳到北京

那是2011年3月,来之前我联系了大学同学刚哥。我可以在找到房子之前在他那里借宿一段时间。

就这样,我就坐上了去北京的火车。

我如愿做上了我心中真正的软件测试工作,也从那时候开始,我才开始上手了一点脚本、数据库相关的知识。

在北京东软,我经历了两个外派项目,发现我不喜欢这样的外派方式。一是上班无定所,二是定期更换并认识新同事。不到一年时间,我打算换工作了。

我第一个投递的简历是百度,面试了但不知道为什么反正就是没有通过,可能那时候确实是太菜了,才做了不到一年的 web 测试新手,还想面试百度?想想也不太可能。

后来又投了几个简历,误打误撞我就面试了京东,且最终通过了面试。记得当时的工资是6500,这对我来说真的是一笔巨款啊,足足比我刚来北京的时候翻了一倍。

在京东工作的两三年,是我真正入行测试的几年。身边确实有一些值得学习的同事,在他们身上我学到了 Python、Jenkins、性能测试、以及功能测试。

虽然我学到了这些技能,但我知道如果我想回到大连找到一份不错的工作,光会点技术还不够,我还得会英语,因为在大连只有外企的待遇还不错。

因此我在北京就开始搜索大连的外企,另外也开始准备学习英语。

我报名了新东方,学费好几千块钱,我记得上一堂课可能都要几十到上百,另外我觉得这样性价比不高。听了一两次试听课后,我果断退了学费。

我觉得最好的学习英语的环境就是加入外企。我开始在北京尝试去面试大连的外企,正好有一家在北京有分公司,我就去面试了,但可惜面试没通过。

4. 从北京回到大连

没有办法,在北京想找到大连外企实在不太现实,我辞掉了京东的工作回到大连找。

回到大连之后休息了几天,发现自己没有工作实在没心情做其他任何事情,然后就开始了找工作。

去面试过花旗的外派,也没有成功。那时候我还有一个想法就是转开发!

这是受在京东的同事影响。当时有一个测试同事,他会开发且技术不错,负责给开发团队写单元测试。我当时觉得这个很厉害,我也想做那种被认为有技术含量的工种。

因此我当时的另一个计划是:如果有任何一家公司愿意招聘我这个只有测试工作经验的人,培养我做开发,我其实愿意少拿钱,甚至免费为他们工作。我当时离开京东时的工资已经有一万二了,尽管如此但我也想要转开发,即使是从一个实习生开始。可惜当时市场没有给我这个机会,我没有在短期内找到这样的开发岗位。因为我需要一份工作,后来就找到一个6000多薪资的测试小主管工作。在这个岗位上我工作了几个月,发现这不是我想继续工作的环境,并在骑驴找马继续寻找一份外企工作。

后来我又误打误撞投了我之前在北京投递过的外企,这次面试得挺不错的,并正式被录用进入了外企。在这里开启了一段十年的职业生涯,是我最为努力的十年。

5. 在外企从测试转开发然后DevOps

上面说过我想转开发。在我加入到新公司后,组内有机会可以从测试转前端开发的机会。我当时极度羡慕这样的机会,可惜晚了一步,人够了,因此我就只能在测试岗位上继续发光发热。

直到2018年,因为公司业务调整,我又有了转开发的机会,但需要考核。

虽然对我来说是一个很大的挑战,但我认为这对我来说是在做对的事情。两个原因:

  • 如果编程技能比较强,我可以成为测试里技术最好的人;
  • 通常开发比测试有更多的话语权,更多的机会,比如说技术移民。
    我毫不犹豫地申请去做开发!

那是一段压力非常大的日子,我之前在#码农随笔系列里写过文章记录过那段日子。但最后我还是成功做了开发。再后来团队需要一个Build工程师,说真的,真是为我准备的角色,太适合我了!

之前这个角色还叫Build工程师,因为我非常有热情把这个工作做好,因此我做了很多Build之外的事情,因此我的职责也在慢慢扩大到DevOps相关领域,之后大家都称我为DevOps工程师,负责DevOps/Build/Release相关的事情。

6. 从大连到欧洲

早在几年前,我开始有了想走出去看看的想法,想在日本、欧美范围内找一个可以提供签证的DevOps工作。如果再走不出去,到了四十岁我可能就没什么机会了。

这个想法的产生可能源自于我此前自由行去过泰国、日本、美国的缘故。之后我喜欢听《静说日本》、《随口说美国》这些音频节目。

我更新了自己的LinkedIn,期间偶尔有人联系过我新加坡的机会。说实话,能不能去成还不好说,但我对那里不是很感冒,给我的感觉那边比较卷。

在经历了疫情、孩子出生后,这个想法就搁置了,也没有任何进展。在经历了众所周知的大环境后,突然有了机会。

但说实话这时候我顾虑比当初去上海,回沈阳、去北京、回大连时多得多。

因为家庭、因为孩子、因为父母,做出决定是不容易的。但在过往的所有选择里,没有完美的机会,在这个不确定的时代,唯一不变的就是变化。况且这样的机会以后几乎都不会再有了。

留下来可能需要被迫去卷无意义的事情,就像大人卷工作、教育,小孩卷学习。想到此,我知道又到了该选择的时候,那就是走出去。

最后

自毕业以来,特别是近十年的外企工作,我挺努力的。努力工作、不妥协地去完成;坚持业余时间以教促学的写了七八年的博客和公众号,贡献开源项目。

我坚信努力的价值,但同时也提醒自己不要陷入“自我感动”的误区。努力固然重要,但不能让战术上的勤奋掩盖战略上的懒惰。我们必须抬头看路,抓住关键的机会,做出明智的决策。毕竟,如果方向错误,再多的努力也可能是徒劳的。


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」

DevOps进阶:揭秘首席DevOps工程师的职责与技能

想象一下,你是一名 DevOps 工程师,不论初级、中级还是高级,老板总有一天拍拍你的肩膀说:“加油干,兄弟,未来你就是我们的首席 DevOps 工程师了!”你可能会心想:“啥是首席 DevOps?这是个什么新饼?”

今天就带你了解一下,所谓的“首席 DevOps 工程师”到底干啥,职责是什么?

我们一起看看,顺便找准未来的职业发展方向。毕竟,谁都希望能进阶到高级角色嘛,对吧?

首席 DevOps 工程师是干啥的?

在今天这个技术跑得比人快的世界里,首席 DevOps 工程师是关键角色,帮助企业搞定基础设施,让软件交付又快又稳。这可不光是架个服务器那么简单,真正的大活儿是当好开发和运营团队之间的“桥梁”,推动 DevOps 文化在公司生根发芽。

那么他们的日常是啥呢?总结起来,有三个主要工作:

  1. 设计并维护基础设施 —— 和开发团队配合,搭建弹性、可扩展的基础设施,满足业务需求。
  2. 自动化所有能自动化的事情 —— 减少手动操作,提升代码发布和测试的效率。
  3. 推动团队文化变革 —— 推广 CI/CD 最佳实践,优化大家的工作方式。

核心职责

1. 协调开发和运营

在你成为首席 DevOps 工程师后,你的头号任务就是让开发和运营两边配合得像一个人。持续集成、持续部署这些词你得说得像背诗一样顺溜,同时,基础设施得稳如老狗。

2. 实现自动化和流程优化

自动化是 DevOps 的灵魂,首席 DevOps 工程师就是得把那些繁琐的手动任务尽可能自动化,不断优化,让所有事情跑得又快又稳。

3. 保证系统可靠性和效率

系统跑不稳,CI/CD就得停摆,所以你要设计出能撑得住风浪的基数设施。遇到高负载或者故障,系统照样得稳住。定期监控、优化,是你的日常功课。

成为首席 DevOps 工程师需要哪些技能?

1. 技术要硬

技术基础是标配,Python、Bash 这些脚本语言得熟悉,Docker 这种容器技术也得懂,Ansible、Chef 这些配置管理工具是你日常操作。最重要的是,云平台(比如 AWS 和 Azure)管理经验不能少。

2. 领导力和管理能力

技术大牛不稀奇,领导力大牛才是硬通货。你得激励团队,帮他们成长,创造出协作的氛围。别忘了,技术再牛,不会跟不同层级的利益相关者沟通,那也白搭。

3. 解决问题的能力

技术上碰到过问题可以迅速找到问题的根源,给出靠谱的解决方案。更重要的是,做决策时得能平衡技术需求和业务目标,让公司上下都买账。

对公司有啥好处?

1. 加强沟通协作

作为首席 DevOps,你不仅仅写代码,还得跨团队沟通协调,让大家更默契,工作更顺畅。减少内部摩擦,提升效率。

2. 加快产品交付

优化流程、自动化任务,你能让产品的交付速度快得像坐火箭。市场变化快,你得让公司跟得上,产品能快速迭代,企业才能有竞争力。

3. 提高系统稳定性和安全性

稳定性和安全性很重要,你得建立起强大的监控体系,防止潜在的威胁,在安全和稳定方面给公司打下坚实基础。

总结一下

首席 DevOps 工程师可不是单纯的技术专家,你要靠技术提升效率,推动合作,保证产品交付和系统的稳定性。这过程里,你不仅是一个技术领袖,更是团队文化的推动者。

想成为首席 DevOps?那就不仅要技术过硬,还要培养领导力和解决问题的能力。

希望这篇轻松的文章能帮你找到未来的努力方向,毕竟,我们都在为更高的目标努力着!


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」