与之正在迁移到Azure,我想分享我对迄今为止所面临的最大挑战之一的思考:协调集装箱基础架构.Jenkins项目的许多必威国际有限公司应用程序都是作为Docker容器运行的,这使得Kubernetes成为运行容器的一个合乎逻辑的选择,但它也带来了一些挑战。例如,从开发到生产的工作流是什么样的?

在更深地进入挑战之前,让我们回顾我们开始的要求:

Git.

我们发现必须跟踪Git存储库中的所有基础架构更改,包括秘密,以便于审查所有INFRA的审核,验证,回滚等。

测试

基础设施贡献者是地理位置分布式的,并以不同的时区分布。获得反馈可能需要时间,所以我们在可以合并任何更改之前严重依赖大量测试。

自动化

更改提交人不一定是部署它的人。重复任务易于出错,浪费时间。由于这些原因,所有步骤必须自动化并保持尽可能简单。

我们的“代码”工作流程的“基础设施”的高级概述看起来像:

基础架构作为代码工作流程
__________ _________ ______________ | | | | | | | 变化  | ---->| 测试  |----->| 部署  | |_________| |________| ^ |_____________| | ______________ | | | 验证  | |_____________|

我们确定了使用Kubernetes实现容器编排的两种可能方法:

  1. Jenk必威国际有限公司ins Way:Jenkins被Git提交触发,运行测试,验证后,Jenkins部署了进入生产的变化。

  2. 傀儡方式:Jenkins被Git必威国际有限公司提交触发,运行测试,验证后,它触发了傀儡部署到生产。

让我们详细讨论这两种方法。

Jenk必威国际有限公司ins Way.

工作流
_________________ ____________________ ______________ | | | | | | | 詹金斯詹金斯Github必威国际有限公司: | |: | |: | |提交触发  | ---->| 测试和验证  | ---->| 部署  | |________________| |___________________| |_____________|

在这种方法中,Jenkins用于测试必威国际有限公司、验证和部署Kubernetes配置文件。kubectl.可以在目录上运行并是幂等。这意味着我们可以随时运行它:结果不会改变。从理论上讲,这是最简单的方式。唯一需要的是运行kubectl.指令每次jenkins检测到更改。必威国际有限公司

下面的Jenkinsfile必威国际有限公司给出了这个工作流的一个示例。

必威国际有限公司Jenkinsfile.
管道{代理任意阶段{阶段(在里面){步骤{shcurl -lo https://storage.googleapis.com/kubernetes-release/release/$$$$$$$$$$$$$$$$$$$$ ease/kubernetes-release/release/table.txt )/bin/linux/amd64/ kubectl.} } 阶段(测试){步骤{sh运行测试} } 阶段(部署){步骤{sh./kubectl apply -R true -f my_project . txt}}}}}

当然,魔鬼在细节中,它并不像乍一看那么容易。

顺序很重要

在其他人之前需要部署一些资源。解决方法是使用数字作为文件名。但这在文件名级别添加了额外的逻辑,例如:

Project / 00-Nginx-Ingress项目/ 09-www.jen必威国际有限公司kins.io

可移植性

部署环境需要在开发机器和Jenkins主机上相同。必威国际有限公司虽然这是一个众所周知的问题,但解决问题并不容易。项目越多,我们的脚本所需的额外工具就越多(制作蝙蝠JQ.gpg, 等等)。我们使用的工具越多,出现了越多的问题是因为使用的不同版本。

在处理不同环境时出现的另一个挑战是:我们如何管理特定环境的配置(DEV,PROD等)?定义每个环境的不同配置文件会更好吗?也许,但这意味着代码复制,或使用需要更多工具的文件模板(sedjinja2erb.)和更多的工作。

没有我们发现的黄金法则,答案可能在某个地方。

无论如何,好消息是必威国际有限公司Jenkinsfile.提供从Docker Image执行任务的简单方法,并且图像可以包含环境中的所有必要工具。我们甚至可以在路上使用不同的Docker图像。

在以下示例中,我使用my_env.Docker图像。它包含测试,验证和部署更改所需的所有工具。

必威国际有限公司Jenkinsfile.
管道{代理{docker {映像my_env:1.0}} options{buildDiscarder(logRotator()}numToKeepStr10))disableconcurrentbuilds()超时(时间1单元小时)}触发{pollSCM(* * * * *)}阶段{阶段(在里面){ 脚步{// init部署我们的内部所需的一切上海制作init.} } 阶段(测试){ 脚步{//运行测试以验证更改上海制作测试} } 阶段(部署){ 脚步{//在生产中部署更改上海部署}}帖子{始终{sh制作通知}}}

秘密凭据

管理秘密是一个重要的主题,并带来了许多不同的要求,这非常难以实现。出于显而易见的原因,我们无法发布INFRA项目中使用的凭据。另一方面,我们需要跟踪并共享它们,特别是针对部署我们群集的Jenkins节点。必威国际有限公司这意味着我们需要一种方法来加密或解密这些凭据,具体取决于权限,环境等。我们分析了两个不同的处理方法来处理:

  1. 在密钥管理工具中存储秘密,例如钥匙拱顶或者拱顶并像Kubernetes“秘密”类型的资源一样使用它们。
    →不幸的是,这些工具还没有集成到Kubernetes中。但我们稍后可能会回到这个选项。Kubernetes问题:10439

  2. 使用公共GPG密钥发布和加密。
    这意味着每个人都可以为基础设施项目加密凭证,但只有私钥所有者才能解密凭证。
    该解决方案意味着:

    • 脚本:由于秘密需要在部署时间解密。

    • 模板:由于秘密值将根据环境而变化。
      →每个Jenk必威国际有限公司ins节点只有私钥才能解密与其环境相关的秘密。

脚本

最后,我们建造的系统很难与之合作。我们最初必威国际有限公司Jenkinsfile.只有一个kubectl.命令慢慢成为一堆脚本以适应:

  • 只有在某些情况下才需要更新资源。

  • 需要加密/解密的秘密。

  • 需要运行的测试。

最后,部署Kubernetes资源所需的脚本数开始变得笨拙,我们开始询问自己:“我们不是重新发明轮子吗?”

傀儡方式

Jenk必威国际有限公司ins项目已经使用了Puppet,所以我们决定使用Puppet来协调Kubernetes的容器部署。

工作流
_________________ ____________________ _____________ | | | | | | | 詹金斯Github: |必威国际有限公司 |: | |木偶:| |提交触发  | ---->| 测试和验证  | ---->| 部署  | |________________| |___________________| |____________|

在此工作流程中,Puppet用于模板并部署协调我们群集所需的所有Kubernetes配置文件。木偶也用于自动化基本kubectl.基于文件更改的各种资源,例如“应用”或“删除”的操作。

木偶的工作流
______________________ |||木偶代码:||.||├──应用.pp || ├── kubectl.pp | | ├── params.pp | | └── resources | | ├── lego.pp | | └── nginx.pp | |_____________________| | _________________________________ | | | | | Host: Prod orchestrator | | | /home/k8s/ | | | . | | | └── resources | | Puppet generate workspace | ├── lego | └-------------------------------------->| │ ├── configmap.yaml | Puppet apply workspaces' resources on | │ ├── deployment.yaml | ----------------------------------------| │ └── namespace.yaml | | | └── nginx | v | ├── deployment.yaml | ______________ | ├── namespace.yaml | | Azure: | | └── service.yaml | | K8s Cluster | |________________________________| |_____________|

这种方法的主要好处是让Puppet管理环境并运行常见任务。在以下示例中,我们为DataDog定义了一个傀儡类。

用于资源Datadog的Puppet类
# #在kubernetes集群上部署datadog资源# #类:profile::kubernetes::resources::datadog # #这个类在每个kubernetes节点上部署一个datadog代理# #参数:# $apiKey: #包含datadog api键。$apiKey = base64('encode', $::datadog_agent::api_key, 'strict')){include::stdlib include profile::kubernetes::params require profile::kubernetes::kubectl文件{"${profile::kubernetes::params::resources}/datadog":确保=> 'directory', owner => $profile::kubernetes::params::user,} profile::kubernetes::apply {'datadog/secret. txt ';{'datadog/daemonset. aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx . aspx。} profile::kubernetes::apply {'datadog/deployment. txt ';yaml':} #因为秘密的改变不会触发豆荚更新,#我们必须手动重新加载豆荚,以使用更新的秘密。如果我们删除了一个由守护进程定义的pod,那么这个守护进程将自动重新创建pod。exec {'Reload datadog pods': path => ["${profile::kubernetes::params::bin} "], command => 'kubectl delete pods -l app=datadog', refreshonly => true, environment => ["KUBECONFIG=${profile::kubernetes::params::home}/ "]。kube/config"], logoutput => true, subscribe => [Exec['apply datadog/secret. txt '] . txt] . txtyaml '], Exec['应用datadog / daemonset。Yaml '],],}}

让我们将傀儡方式与Jenkins Way所发现的挑战进行比较。必威国际有限公司

命令很重要

使用Puppet,将优先级定义为Puppet提供关系元参数和功能“要求”(另请参阅:木偶关系)。

在我们的Datadog例子中,我们可以确定部署将遵循以下顺序:

datadog /秘密。yaml - > datadog / daemonset。yaml - > datadog / deployment.yaml

目前,我们的Puppet代码仅在检测到文件更改时应用配置。更好地将本地文件与群集配置进行比较以触发所需的更新,但我们还没有找到一种实现这一目标的好方法。

可移植性

由于Puppet用于配置工作环境,因此更容易确保所有工具都存在并正确配置。复制环境和使用工具在环境上运行测试也更容易RSpec-puppetserverspec.或者流浪汉

在我们的DataDog示例中,我们还可以根据环境轻松更改DataDog API键艾拉

秘密凭据

我们已经使用了神庙GPG用傀儡,我们决定继续使用它,为容器进行管理秘密非常简单。

脚本

当然,使用傀儡DSL,即使似乎在开头似乎较难,Puppet也简化了Kubernetes配置文件的管理。

结论

只要Kubernetes项目本身保持基本,在Jenkins中使用完整的CI工作流引导项目就会容易得多。必威国际有限公司但是随着项目的发展,我们开始在每个环境中部署具有不同配置的不同应用程序,将Kubernetes管理委托给Puppet就变得更容易了。

如果您有任何评论,请随时发送消息必威国际有限公司Jenkins Infra邮件列表

谢谢

感谢Lindsay Vanheyste,Jean Marc Meessen和Damien Duportal反馈。

关于作者
Olivier Vernin.

Olivier是Jenkins必威国际有限公司基础设施官员和CloudBees的高级运营工程师。作为Jenkins基础设施项目的正规贡献者,他涉及从服务可靠性到必威国际有限公司应用程序维护的广泛任务。