前言:什么是 CICD 与 为什么要学 CICD
版本说明:本系列基于 Docker 20.10 / Kubernetes 1.23 / CentOS 7 编写。当前环境建议:Docker 27.x、Kubernetes 1.31+、操作系统使用 Ubuntu 24.04 或 Rocky Linux 9(CentOS 7 已于 2024-06 EOL)。CI/CD 核心概念与 K8s 资源编排方式不变,仅安装命令和版本号需对应更新。
什么是 CI/CD
在开发阶段,许多编译工具会将我们的源码编译可使用的文件。例如 vue-cli 的项目会被 webpack 打包编译为浏览器的文件,Java 项目会被编译为 .class/jar 文件以供服务器使用。
但是,开发人员过多关注构建和部署过程是很浪费时间的。以之前古老的的构建部署流程为例子,需要经历以下步骤:
- 开发人员将源代码,经过编译、压缩等一系列流程打包为制品(意思为打包后的成品)
- 将制品上传到服务器。
- 在服务器将编译后的文件,手动可用的容器服务内(例如
Nginx,Tomcat,Apache等服务)
显而易见,这种流程不仅繁琐,且容易出错,是非常影响开发效率的。开发人员要花一些时间浪费在这上面。那么有没有高效率,简单便捷一些的方式呢?
这就要提到 CI/CD 了。CI 的意思是 持续构建 。负责拉取代码库中的代码后,执行用户预置定义好的操作脚本,通过一系列编译操作构建出一个 制品 ,并将制品推送至到制品库里面。常用工具有 Gitlab CI,Github CI,Jenkins 等。这个环节不参与部署,只负责构建代码,然后保存构建物。构建物被称为 制品,保存制品的地方被称为 “制品库”
CD 则有2层含义: 持续部署(Continuous Deployment) 和 持续交付(Continuous Delivery) 。 持续交付 的概念是:将制品库的制品拿出后,部署在测试环境 / 交付给客户提前测试。 持续部署 则是将制品部署在生产环境。可以进行持续部署的工具也有很多: Ansible 批量部署, Docker 直接推拉镜像等等。当然也包括我们后面要写到的 Kubernetes 集群部署。
为什么要学 CI/CD
了解其用途后,常见的疑问有:
- 这不是运维干的活吗?
- 好像和业务代码不相关,那我了解它有何意义?
- 全是服务器知识,我不了解相关知识怎么学习?
这些疑问很常见。那学习 CI/CD 的意义在哪里?
但是当我通过学习这些知识和在团队中实践这些流程后,我在知识面上得到了很大的扩展。对操作系统,对实际的构建部署,甚至对工程化拥有了全新的认识。甚至可以提出建议,如何更好的优化这些流程。这些都是你可以获得成长和学习的地方。你也可以选择将这部分知识点写入你的简历,作为面试和筛选的加分项。从更高的角度看整个项目的全貌,往往产生思考的维度是和一般的角度不同的。你会成长更快,渐渐地突破思维天花板。
当然,如果你对 Linux 操作系统不是很熟悉,建议先补习下基础的系统安装,操作命令,基础概念等知识(系统推荐 CentOS / Ubuntu ),在本系列中将不会对基础Linux命令有过多解释。当然,如果遇到部分不懂的现场搜索也可以,相信你学起来这部分知识可以更加得心应手。
系列整体架构设计
在开始学习之前,我们先来了解下本系列的整体内容技术架构设计:
上面是一张全景架构图,系列内容和章节将围绕该图展开编写内容。其中不包含单元测试和代码扫描环节,只关注构建和部署环节。
换成文字叙述就是这样的:
- 你写完了代码,提交到了
Git代码库 - 随后,代码库配置的
WebHook钩子或人工手动启动了Jenkins的构建流程 Jenkins启动构建流程。按照你之前配置好的构建脚本,将代码编译成功。- 编译成功后,将编译后的文件打包为
docker镜像,并将镜像上传到私有镜像库。 - 随后,使用
kubectl指定远程的k8s集群,发送镜像版本更新指令 - 远程的k8s集群接收到指令后,去镜像库拉取新镜像
- 镜像拉取成功,按照升级策略(滚动升级)进行升级,此时不会停机。
- 升级完毕。
服务器搭配方案
学习本系列,动手能力要具备,当然服务器资源也要准备好。这里推荐几种服务器搭配方案用来学习测试使用:
系统建议选用 Ubuntu 24.04 LTS 或 Rocky Linux 9(CentOS 7 已于 2024-06 EOL)
1. 全本地虚拟机 / 全上云
这里所有主机都必须为云服务器/本地虚拟机。要保持统一
| 配置 | 技术栈 | 类型 | 标签 |
|---|---|---|---|
| 2核4G | Jenkins + Nexus + Docker | 本地虚拟机 / Cloud | 构建机 |
| 2核4G | Docker + Kubernetes | 本地虚拟机 / Cloud | Kubernetes Master |
| 1核1G | Docker + Kubernetes | 本地虚拟机 / Cloud | Kubernetes Node |
2. 半云半本地虚拟机
构建机器放本地,要部署的机器放云上面。否则的话构建机找不到要部署的机器
缺点:无法使用 Git 的 Webhook
| 配置 | 技术栈 | 类型 | 标签 |
|---|---|---|---|
| 2核4G | Jenkins + Nexus + Docker | 本地虚拟机 | 构建机 |
| 2核4G | Docker + Kubernetes | Cloud | Kubernetes Master |
| 1核1G | Docker + Kubernetes | Cloud | Kubernetes Node |
进入 CD 的世界
在前几章,我们部署了 Docker + Jenkins,并走通了构建镜像的流程,接下来的几章,我们将专注于 CD(持续部署的讲解)。内容包括:
- 如何安装一套
Kubernetes集群? - 如何在
Kubernetes集群内部署自己的服务? - 如何实现灰度发布和滚动发布?
- 如何更好地管理自己应用的状态?
- 如何存储服务内的机密信息?
- 如何更好的调度你的服务部署?
- 如何管好你的环境变量?
在后面的几章,我们会全方位地了解到一个项目如何部署,应该怎样部署,如何更好部署。可以更好地支撑我们服务运行和维护。
Kubernetes 污点与容忍:更好地分配集群资源
前言
前面的部分,我们已经可以从工程角度合理地去部署一个应用了。可是场景总是复杂的,有时候还会遇到以下问题:
自动调度集群节点部署很不错。但我其中几台服务器计划只给后端服务准备使用,这要怎么调度呢? > 后端服务依赖的服务器配置都很高,让前端服务也能调度过去显然不合适。如何干预 Pod 部署到指定的其中几个服务器上去呢?.......
这种问题在实际情况中还比较常见的。因为架构设计,前端服务器所需资源低一些是常事。而资源强占总是不合理的。
这时候我们就需要借助 Kubernetes 中的污点与容忍度去实现了
什么是污点?容忍度又是什么?
我们一般说污点,一般指生活中的脏东西。但是在 Kubernetes 中,污点的意义却有所不同。
在 Kubernetes 中, Pod 被部署到 Node 上面去的规则和逻辑是由 Kubernetes 的调度组件根据 Node 的剩余资源,地位,以及其他规则自动选择调度的。但是有时候在设计架构时,前端和后端往往服务器资源的分配都是不均衡的,甚至有的服务只能让特定的服务器来跑。
在这种情况下,我们选择自动调度是不均衡的,就需要人工去干预匹配选择规则了。这时候,就需要在给 Node 添加一个叫做污点的东西,以确保 Node 不被 Pod 调度到。
当你给 Node 设置一个污点后,除非给 Pod 设置一个相对应的**容忍度,**否则 Pod 才能被调度上去。这也就是污点和容忍的来源。
污点的格式是 key=value,可以自定义自己的内容,就像是一组 Tag 一样。**
给 Node 设置污点
在给 Node 设置污点之前,我们再创建一个新的 deployment 版本,版本是 v3 。并将之前的 pod 名称, service 名称从 v2 也改成 v3 :
cp ./v2.yaml v3.yaml
vim v3.yaml # 里面的Pod名称,service改成v3
kubectl apply -f ./v3.yaml随后,我们用 kubectl get pods 命令获取Pod列表,用 kubectl describe pod 命令看下 Pod3 的运行详情:
我们看 Node 一栏, k8s 将我们新创建的 Pod 调度部署到了新增加的 Node2 节点上。接下来,我们给 Node2 设置污点,让 Pod 不会调度到 Node2 节点上。
当然,给 Node 设置污点是第一步操作,只有设置了污点 Pod 才不会被调度上去。给 Node 添加污点的命令很简单,我们只需要使用 kubectl taint 命令即可给 Node 设置一个污点:
kubectl taint nodes [Node_Name] [key]=[value]:NoSchedule其中,Node_Name 为要添加污点的 node 名称;key 和 value 为一组键值对,代表一组标示标签;NoSchedule 则为不被调度的意思,和它同级别的还有其他的值:PreferNoSchedule 和 NoExecute (后面我们会写到)
我们给 Node3 添加完一个污点后,提示报 node/node2 tainted 代表添加成功:
我们删除掉已经创建的 v3 版本的 Pod ,让 Kubernetes 重建 Pod ,看看新 Pod 还会不会被调度到 node2 上面去:
kubectl delete pod [POD_NAME]
kubectl describe pod [POD_NAME]这时候我们看到, Pod 被调度到了 Node1 上面去。因为 Node2 添加了污点,不会被调度到 Node2 上面去。此时污点生效。
给 Pod 设置容忍度
可以看到,给 Node 添加完污点后,新创建的 Pod 都不会调度到添加了污点的 Node 上面。所以我们想让 Pod 被调度过去,需要在 Pod 一侧添加相同的容忍度才能被调度到。
我们编辑 front-v3 的 deployment 配置文件,在 template.spec 下添加以下字段:
tolerations:
- key: "KEY"
operator: "Equal"
value: "VALUE"
effect: "NoSchedule"字段的含义是在给 Pod 设置一组容忍度,以匹配对应的 Node 的污点。 key 和 value 是你配置 Node 污点的 key 和 value; effect 是 Node 污点的调度效果,和 Node 的设置项也是匹配的。
operator 是运算符,equal 代表只有 key 和 value 相等才算数。当然也可以配置 exists ,代表只要 key 存在就匹配,不需要校验 value 的值
修改保存后,我们使用 kubectl apply -f 命令让配置项生效,接着删除已存在的 Pod,查看下新Pod的调度结果:
可以看到,在容忍度的作用下, Pod 重新被调度到了 Node2 节点上。
修改/删除 Node 的污点
修改污点的方式也很简单,像创建一个污点一样,我们依然使用 kubectl taint 命令就可以完成修改:
kubectl taint nodes [Node_Name] [key]=[value]:NoSchedule --overwrite这里的 key 依然是要修改的 key 值,只需要对 value 和作用的值进行修改即可。后面添加参数 --overwrite 代表覆盖之前的数据。
**
删除污点也依然很简单。我们只需要加个 - 号就可以删除污点:
kubectl taint nodes [Node_Name] [key]-当提示: node/[NODE_NAME] untainted 代表删除成功。
总结:结束语
知识回顾
本系列共 15 章,覆盖了从零搭建一套完整 CI/CD 流程的全部环节:
| 阶段 | 章节 | 核心内容 |
|---|---|---|
| CI 持续构建 | 01-04 | Docker + Jenkins 环境搭建、镜像构建、私有镜像库(Nexus) |
| CD 持续部署 | 05-08 | Kubernetes 集群搭建、应用部署、灰度/滚动发布策略 |
| K8s 资源管理 | 09-13 | 探针、Secret、DNS、ConfigMap、污点与容忍 |
| 综合实战 | 14 | 前后端分离项目完整 CI/CD 流水线 |
完整流水线架构
Git Push → Webhook 触发 → Jenkins 构建 → Docker 镜像打包 → 推送至 Nexus → kubectl 更新 K8s Deployment → 滚动升级完成进阶方向
本系列聚焦于 CI/CD 的核心流程,以下方向值得继续深入:
- 高可用集群:多 Master 节点、etcd 集群、负载均衡
- Helm:Kubernetes 包管理器,简化复杂应用的部署和版本管理
- GitOps:ArgoCD / Flux,以 Git 仓库为唯一事实来源驱动部署
- 服务网格:Istio / Linkerd,细粒度流量管理和可观测性
- 监控告警:Prometheus + Grafana + AlertManager 全链路监控
- 安全加固:RBAC 权限控制、NetworkPolicy 网络隔离、镜像漏洞扫描
总结:结束语
结束语
如果你看到这段文字,说明你已经打卡完毕本系列!
本系列15章节,可实践的章节高达13章。如果你是0基础操作的话,想必需要花起码1个月左右的时间才能学完。
在这1个月左右的时间里,你可能在安装部署时出现了问题;可能在学习知识时遇到了困惑;可能在遇到新概念时无法理解头皮发麻;但,都一路走过来了,不是吗?
当然,写本系列的我和学习本系列的你同样辛苦。本系列在2020年2月份立项,于疫情居家办公时开始编写,历时半年时间才确定初稿。里面很大一部分知识都来自于我和我的团队实践。
为了写好本系列,虚拟机跑了N个,凌晨赶稿的时刻常有。但为了给你一份靠谱的学习资料,我知道我的付出是值得的。
在11月份我受邀参加早早聊演讲时,有位同学在直播后问了我如何学习cicd。当时我找遍全网资料,也没有一份成体系的,好入门的,较全的资料出现。可是,现在有了。
当然,本系列由于时间和其他原因,内容相对有限。对于 kubernetes Jenkins docker 的许多许多知识点都没有写到讲到。例如如何去创建一套高可用架构,如何使用 helm 安装应用等等。但是,这也刚好是你要去学习和探索的部分。我经常对许多朋友说,千万不能浅尝辄止。一定要继续学下去
当然,本系列也许有疏漏和错误的地方,欢迎大家指出,我个人不胜感激。也欢迎大家入群和我一起交流