在上一篇基于 Kubernetes 的基础设施即代码一文中,我概要地介绍了基于 Kubernetes 的 .NET Core 微服务和 CI/CD 动手实践工作坊使用的基础设施是如何使用代码描述的,以及它的自动化执行过程。

如果要查看基于 Kubernetes 的基础设施即代码架构全图,以及实现代码,请回到文章基于 Kubernetes 的基础设施即代码

本文,我们深入探讨其中 CI/CD 软件部分的“基础设施即代码”的实现原理。

变量模板引擎

在工作坊中,由于所有与会者使用的都是同一个 Kubernetes 集群,因此我们需要一种方法来标识当前用户。Kubernetes 的命名空间提供的逻辑隔离功能可以很轻松地实现这个效果。因此,我们要为每个工作坊与会者创建他的一批命名空间:

  • cicd-<suffix> 用于部署 CI/CD 软件
  • dev-<suffix> 作为“开发环境”,部署微服务
  • stage-<suffix> 作为“预生产环境”,部署微服务

显然,对于每一个与会者来说,这里的 suffix 会有所不同,因此它是一个变量。除了在启动安装 CI/CD 软件时需要使用,这个变量还需要以某种形式保存到 Jenkins 上,因为当 Jenkins 运行部署任务时,它也需要知道目标命名空间的名字。

为了处理变量,我们自己发明了一个小型的“模板引擎”。其作用是,使用变量文件中指定的值,替换各个文件中的变量,输出最终的内容。这个模板引擎以双美元符号 $$ 作为变量起始字符。打开 cicd-infra/jenkins.yaml 并搜索 $$ 就可以发现其中大量地引用了各个变量。

模板引擎的实现位于 ./tmpl.sh 脚本文件,它能从指定的变量文件和环境变量读入各个变量的值,并将待处理文件中的变量占位符替换为对应的值,最后向标准输出(stdout)打印最终的文件内容。借助流水线指令 |,这些内容随后被 kubectl apply -f - 命令读取,用于安装配置对应的 Kubernetes 资源。

在 kubelet 1.14 及以上的版本中,新增加了 kustomize 子命令。它提供更多编写模板化、嵌套式 Yaml 文件的方法。在工作坊中,我们需要兼容支持低一些版本的 kubelet,就不得不借助这样的模板引擎。

自动化安装 Jenkins

打开 cicd-infra/jenkins.yaml 会发现接近 600 行,可以说不短了。其中包含如下几个关键的 Kubernetes 资源:

  • ServiceAccount jenkins 是 Jenkins 本身,以及 Jenkins 用于生成容器镜像并部署微服务时所用的 Pod 要使用的集群账号
  • RoleBinding jenkins_edit 为上述集群账号赋予相应权限
  • Service jenkins-jnlp 供 Jenkins 构建运行器(Slave)启动期间连接 Jenkins 主机(Master)时用的集群 Service
  • Service jenkins 是供 Ingress 用于把 Jenkins Web 界面暴露给用户用的集群 Service
  • Ingress jenkins-ingress 是负责把用户请求转发到集群 Service 的流量入口处理规则
  • ConfigMap jenkins-jobs 可挂载为 Jenkins 内置任务的配置
  • ConfigMap jenkins 一系列用于初始化 Jenkins 的配置
  • Deployment jenkins 用于部署 Jenkins Web 服务

这里需要重点介绍的是 configmap/jenkins,以及 deployment/jenkins。后者挂载前者,以文件的方式读入内容并完成 Jenkins 的初始化配置工作。具体来说,deployment/jenkins 声明了两个容器,在这两个容器上共享多个存储卷,以实现共享文件的目的:

  1. 在 Jenkins 启动之前运行的初始化容器 installer,它按照 plugins.txt 先将插件安装到磁盘上,并为工作坊的所有微服务创建内置 Jenkins 任务
  2. 在 installer 运行完成之后才启动的容器 jenkins,它就是 Jenkins Web 服务本身所在的容器

从 deployment/jenkins 的 yaml 配置中,我们不难发现,installer 运行的具体过程位于脚本文件 /var/jenkins_config/apply_config.sh 中,它的内容是从 configmap/jenkins 挂载而来的。这个脚本中还将用到很多其他文件,比如安装插件用的 plugins.txt,它们都是从这个 configmap/jenkins 挂载而来。为了加速 Jenkins 插件的安装过程,我们在 installer 容器里使用 JENKINS_UCJENKINS_UC_DOWNLOAD 这两个环境变量来让它从国内的服务器源下载插件。

configmap/jenkins/plugins.txt 定义了工作坊中我们需要用到的插件列表:

  • git
  • dashboard-view
  • pipeline-stage-view
  • workflow-aggregator
  • kubernetes:1.20.0

其中的 kubernetes 插件让我们的 Jenkins 可以与它所在的 Kubernetes 集群集成,从而实现几乎能把任何容器镜像作为构建运行器(Slave)节点来使用,并且这些节点将以独立的 Pod 的方式“按需”在 Kubernetes 集群中运行,并自动连接到 Jenkins。这大大简化了 Jenkins 的运行器节点的维护工作。如果进一步研读 configmap/jenkins/config.xml 配置内容可以发现,我们的 Jenkins 将内置支持 dotnet 和 image-builder 两种 Slave 节点。

阅读 configmap/jenkins/apply_config.sh 可以看到,它使用了 Jenkins 支持的多种自动化配置功能:

  • 运行 /usr/local/bin/install-plugins.sh 脚本文件可以预先安装指定的插件
  • 在 /var/jenkins_home/init.groovy.d 目录中创建的 groovy 脚本将在 Jenkins 启动后自动运行,我们这里用来向 Jenkins 中植入容器镜像注册表的登录信息
  • 通过预先定义 /var/jenkins_home/config.xml 及其他 xml 文件可以定制 Jenkins 的各类全局系统设置
  • /var/jenkins_jobs 目录下的子目录将自动被视为内置任务自动被 Jenkins 加载

上面第一种自动化功能,是内置在 Jenkins 安装包中的一个实用工具,它的源代码位于 GitHub 上。第二种自动化功能是 Jenkins 的初始化脚本,它支持以 Groovy 语言为 Jenkins 开发自动运行的脚本钩子。后面两种自动化功能则是根据 Jenkins 的配置存储机制而预先写入配置来达到内置配置和任务的目的。

deployment/jenkins 还让这两个容器共享 jenkins-home 和 plugin-dir 这两个存储卷,这样就可以让 jenkins 容器从 installer 容器继承已经初始化完成的 Jenkins 配置和插件。这样就确保 Jenkins 主容器运行起来时,就已经具备了已经下载好的插件,以及正确的全局配置。

自动化安装 Gogs 和 Nexus

比起 Jenkins 自动化的过程,Gogs 和 Nexus 的自动化安装就简单得多了。虽然 Gogs 需要 Postgre 数据库的支持,我们在工作坊环境中,还是为数据库配置了 emptyDir 类型的临时存储。因此并不提供持久化存储的支持。给 Nexus 提供的存储也一样用的是 emptyDir 临时存储。

值得一提的是这两个软件启动后的初始化操作。在工作坊的自动化脚本中,分别对这两个软件执行了如下自动化初始化:

  • 在 Gogs 中自动创建账号,从 GitHub 导入各个微服务的源代码库,并配置 WebHook
  • 修改 Nexus 的默认登录信息为 admin/admin

这些过程,都是借助独立的集群任务 cicd-installer 完成的。在该任务中,它首先读入当前 Kubernetes 环境给定的 Service Account 凭据,配置好 kubectl 命令行工具。接着执行以下工作:

  1. 等待 gogs-postgresql 和 gogs 部署完成,调用 Gogs 的 RESTful API 接口,完成用户注册和代码库导入工作
  2. 等待 nexus 部署完成,调用 Nexus 的 Scripting API(脚本编程)接口,完成管理员密码的修改

不难发现,虽然都是自动化配置,却使用了不同的技术。比起 RESTful API 接口,Nexus 的脚本编程接口由于是直接注入脚本,似乎功能会更灵活和强大。不过,过于强大的功能也通常会带来额外的安全风险。

总结

简单总结一下,在上面的讲解中,用到过的自动化技术有:

  1. 基于 Deployment 实现容器应用自动化部署(自动化部署 Jenkins、Gogs、Nexus 和 Sonarqube 等软件)
  2. 借助 Pod 的初始化容器(initContainer)实现提前运行自动化任务(在 Jenkins 主容器启动之前,在 initContainer 中安装插件)
  3. 借助 Pod 多容器共享存储卷来跨容器共享文件(在 initContainer 中安装插件后,由 Jenkins 主容器直接使用)
  4. 借助 Pod 环境变量向应用注入预置的配置(为 Jenkins 指定插件下载源)
  5. 借助 ConfigMap 向应用中直接挂载预置的配置文件(为 Jenkins 预设配置)
  6. 借助 Pod 就绪探针和存活探针,配合 kubectl rollout status 跟踪检测应用部署状态(等待 Gogs、Nexus 部署完成)
  7. 借助 Job 执行一次性任务(cicd-installer)
  8. 使用 Dockerfile 构建容器镜像(Jenkins 上的自定义 Slave 节点)
  9. 调用应用准备好的脚本自动完成配置(使用 Jenkins 提供的 install-plubins.sh 安装插件)
  10. 调用应用的 RESTful API 接口导入数据(为 Gogs 注册用户并自动导入代码库)
  11. 调用应用的 Script API 编程接口自动配置(向 Jenkins 和 Nexus 设置登录凭据)
  12. 使用模板引擎替换变量引用

到目前,我们详细地解读了如何有机地结合使用各种自动化技术,让工作坊的各个 CI/CD 软件在 Kubernetes 上完成启动之后,自动地完成各项自动化配置。由于 Kubernetes 部署 Yaml 文件以及各类自动化配置脚本都是文本文件,因此我们上一篇文章基于 Kubernetes 的基础设施即代码中关于“基础设施即代码”的两个要求仍然成立。

最后,工作坊的自动化脚本还没有提供存储支持,在实际的项目中应该会有对应的需求;基本上,只要在你的 Kubernetes 集群中配置好集群的存储类和自动存储供给支持,要支持存储并不困难。

基于 Kubernetes 的 CICD 基础设施即代码的更多相关文章

  1. 解读与部署(三):基于 Kubernetes 的微服务部署即代码

    在基于 Kubernetes 的基础设施即代码一文中,我概要地介绍了基于 Kubernetes 的 .NET Core 微服务和 CI/CD 动手实践工作坊使用的基础设施是如何使用代码描述的,以及它的 ...

  2. 基于jenkins+kubernetes的cicd流程实践一:环境搭建及方案原理实现

    1.基础环境:Centos7.9,kubernetes:v1.21.5 node-1@112(master):docker,containerd,harbornginx(80),git,etcd no ...

  3. 云原生之旅 - 4)基础设施即代码 使用 Terraform 创建 Kubernetes

    前言 上一篇文章我们已经简单的入门Terraform, 本篇介绍如何使用Terraform在GCP和AWS 创建Kubernetes 资源. Kubernetes 在云原生时代的重要性不言而喻,等于这 ...

  4. 腾讯基于Kubernetes的企业级容器云平台GaiaStack (转)

    GaiaStack介绍 GaiaStack是腾讯基于Kubernetes打造的容器私有云平台.这里有几个关键词: 腾讯:GaiaStack可服务腾讯内部所有BG的业务: Kubernetes:Gaia ...

  5. 基于Kubernetes 构建.NET Core技术中台

    今天下午在腾讯云+社区社区分享了<基于Kubernetes 构建.NET Core技术中台>,下面是演讲内容的文字实录. 我们为什么需要中台 我们现在处于企业信息化的新时代.为什么这样说呢 ...

  6. 基于kubernetes自研容器管理平台的技术实践

    一.容器云的背景 伴随着微服务的架构的普及,结合开源的Dubbo和Spring Cloud等微服务框架,宜信内部很多业务线逐渐了从原来的单体架构逐渐转移到微服务架构.应用从有状态到无状态,具体来说将业 ...

  7. 039.[转] 基于 Kubernetes 和 Spring Cloud 的微服务化实践

    http://dockone.io/article/2967 基于 Kubernetes 和 Spring Cloud 的微服务化实践 写在前面 网易云容器平台期望能给实施了微服务架构的团队提供完整的 ...

  8. 基于Kubernetes实现前后端应用的金丝雀发布

    基于Kubernetes实现前后端应用的金丝雀发布 公司的研发管理平台实现了Gitlab+Kubernetes的Devops,在ToB和ToC场景中,由于用户量大,且预发布环境和生产环境或多或少存在差 ...

  9. 基础设施即代码(IAC),Zalando Postgres Operator 简介

    Postgres Operator 在由 Patroni 提供支持的 Kubernetes (K8s) 上提供易于运行的高可用性 PostgreSQL 集群.它仅通过 Postgres 清单 (CRD ...

  10. 白瑜庆:知乎基于Kubernetes的kafka平台的设计和实现

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文首发在云+社区,未经许可,不得转载. 自我介绍 我是知乎的技术中台工程师,现在是负责知乎的存储相关组件.我的分享主要基于三个,一个是简单 ...

随机推荐

  1. Go语言的100个错误使用场景(61-68)|并发实践

    目录 前言 9. 并发实践 9.1 context 的不恰当传播(#61) 9.2 开启一个协程但不知道何时关闭(#62) 9.3 在循环中没有谨慎使用协程(#63) 9.4 使用 select 和 ...

  2. Python 潮流周刊第 46 期(摘要)+ 赠书 7 本

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  3. IDEA操作MyBatis实现数据库增删改查

    "感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" 前置环境 ...

  4. 力扣605(java&python)-种花问题(简单)

    题目: 假设有一个很长的花坛,一部分地块种植了花,另一部分却没有.可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去. 给你一个整数数组  flowerbed 表示花坛,由若干 0 和 1 ...

  5. 力扣394(java)-字符串解码(中等)

    题目: 给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次.注意 k 保证为正整数 ...

  6. 第 10 章 使用pyecharts 进行数据展示

    第 10 章 使用pyecharts 进行数据展示 10.1 安装 pyecharts pyecharts 是一个用于生成 Echarts 图表的类库, Echarts 是百度开源的一个数据可视化JS ...

  7. POJ4151:电影节

    4151:电影节 总时间限制:  1000ms 内存限制:  65536kB 描述 大学生电影节在北大举办! 这天,在北大各地放了多部电影,给定每部电影的放映时间区间,区间重叠的电影不可能同时看(端点 ...

  8. Dubbo-go 服务代理模型

    ​简介:HSF 是阿里集团 RPC/服务治理 领域的标杆,Go 语言又因为其高并发,云原生的特性,拥有广阔的发展前景和实践场景,服务代理模型只是一种落地场景,除此之外,还有更多的应用场景值得我们在研发 ...

  9. 阿里开源支持10万亿模型的自研分布式训练框架EPL(EasyParallelLibrary)

    ​简介:EPL背后的技术框架是如何设计的?开发者可以怎么使用EPL?EPL未来有哪些规划?今天一起来深入了解. ​ 作者 | 王林.飒洋 来源 | 阿里技术公众号 一 导读 最近阿里云机器学习PAI平 ...

  10. 从技术到科学,中国AI向何处去?

    ​简介: 如果从达特茅斯会议起算,AI已经走过65年历程,尤其是近些年深度学习兴起后,AI迎来了空前未有的繁荣.不过,最近两年中国AI热潮似乎有所回落,在理论突破和落地应用上都遇到了挑战,外界不乏批评 ...