你们好,我是来自阿里云容器服务团队的华相。首先简单解释一下何为 Kubernetes 来帮助你们理解。Kuberentes 是一个生产可用的容器编排系统。Kuberentes 一方面在集群中把全部 Node 资源作一个资源池,而后它调度的单元是 Pod,固然 Pod 里面能够有多个容器。 就像一我的左手抓着 ECS 资源或计算资源,右手抓容器,而后把它们两个匹配起来,这样它就能够做为一个容器的编排系统。
而 Cloudnative 这个概念如今会常常被你们提起,不少人迷惑 Cloudnative 又与 Kuberentes 有什么关联?咱们又该如何判断一个应用是 Cloudnative 呢?我认为有如下三个判断标准:
第一,它可以给资源作池化;
第二,应用能够快速接入池的网络。在 Kuberentes 里面有一层本身的独立网络,而后只须要知道我要去访问哪一个服务名就能够,就是各类服务发现的一些功能,它能够经过 service mesh 去作一个快速地访问;
第三是有故障转移功能,若是一个池子里面有一台主机,或者某一个节点 down 掉了,而后整个应用就不可用了,这确定不算是 Cloudnative 的应用。
比较这三点就能够发现 Kuberentes 作的很是好。首先咱们看一个资源池的概念,Kuberentes 一个大的集群就是一个资源池,咱们不再用去关心说我这个应用要跑在哪台主机上了,我只要把咱们部署的 yaml 文件往 Kuberentes 上发布就能够了,它会自动作这些调度,而且它能够快速地接入咱们整个应用的网络,而后故障转移也是自动。接下来我就来分享如何基于 Kuberentes 实现一个弹性的 CI/CD 系统。node
首先了解一下 CI/CD 的现状。CI/CD 这个概念实际上已经提出不少年了,可是随着技术地演进和新工具地不断推出,它在整个流程和实现方式上逐渐丰富。而咱们一般最先接触 CI/CD 就是代码提交,随之触发一个事件,而后在某个 CI/CD 系统上作自动构建。git
下图能够反映目前 CI/CD 的现状:
程序员
另外还有 Gitlab CI,它主要特色是与 Gitlab 代码管理工具结合地比较好。Jenkins 2.0 开始引入 pipeline as code 特性,pipeline as code 能够帮咱们自动生成一个 jenkins file。
在 Jenkins 1.0 时,若是咱们想要配置一条流水线,须要先登陆 Jenkins 建一个项目,而后在里面写一些 shell。这样虽然能达到一样的效果,可是它有一个最大的弊端,就是可复制性和迁移性很差。并且它与 Devops 有自然地割裂,好比通常是由运维人员来管理 Jenkins 系统,开发人员编写代码,可是这个代码怎么去构建,发布到哪里,开发人员彻底不知道。这就形成了开发和运维地割裂。但 pipeline as code 方式出现了以后,jenkins file 与代码源码能够放在一样的仓库里面。
首先它有一个很是大的好处是发布的流程也能够归入版本管理,这样对一个错误就可追溯。这是一个很是大地改动,可是实际上咱们在与客户沟通中发现,虽然不少人在 Jenkins 上都已经升到 2.0 系列了,可是它们的用法仍是彻底在 1.0 系列,不少用户都没有把 jenkins file 这种方式用起来。另一个就是对容器地支持,大概 2016 年左右,那时对容器的支持是很是弱的,在容器里面运行 Jenkins,同时构建的产物也是 Docker 会很是麻烦。
可是, Drone 对容器的支持力度就很是好。首先它彻底用 Docker 方式来运行,就是说你的构建环境也在一个容器里,你须要构建一个 Docker build 镜像,而后在推送出去的时候,它也在容器里面运行,而后它须要一个 privilege 权限。它这种方式有几个特别好的地方,首先它不会对宿主机产生任何残留,好比说你这个容器一销毁,构建中产生的一些中间文件彻底都跟着销毁了,可是你若是用 Jenkins 的话,随着用的时间愈来愈久会沉淀出不少临时文件,它占的空间会愈来愈大。你须要按期作一些清理,并且清理过程当中你又不能直接一键清空,因此这是很麻烦的过程。
而后插件的管理 Jenkins 还有一个特别让人头疼的地方,就是它的插件升级。首先你在 Jenkins 登陆进去,而后就作插件升级。若是说我想临时在一个新的环境里面,起一个 Jenkins 先测试一下或作一些调试可能每新建一个环境,都须要把这些插件升级一次。并且刚才咱们说的在 Jenkins 里面作的全部配置,也都须要从新配置一遍,这是一个很是繁琐的一个过程。
可是 Drone 这个工具它有一个特别好的地方,就是全部的插件都是 Docker 容器,好比说你在 pipeline 里用这个插件,你只要声明用这个插件就能够了,你不用去本身管理把插件下载到哪里,而后怎么安装,它这个一切都是全自动,只要说你网络能把插件容器镜像访问到就能够了,这很是便利。
而后关于生态的构建,Jenkins 的最大的优点就是它的插件很是多,就是你想用的各类东西都有,并且它基础的底座很是好,你的插件能够实现的能力很是的强。好比说 pipeline 就是这种方式,它从 1.0 到 2.0 虽然有了,可是它彻底是经过插件来实现的。可是如今 Jenkins 的发展又开始有点第二春的感受。他开始对 Kuberentes 的支持力度明显的加大了不少,首先从 JenkinsX 开始,它融合了一些 Kuberentes 生态相关的一些工具,好比 Harbor、Helm 它能够很是便利地在 Kuberentes 集群上来作一些构建,而且把一些作服务的固化的一些编排文件放到 Helm 里面。
另外,如今它有一个新的子项目叫 config as code,也就是说他把全部 Jenkin 里面作了一些配置,均可以输出成一个 code 的形式,就是对整个 Jenkins 的迁移,或者说复制都是一个很便利的改进。
讲了那么多,实际上最后咱们选择的东西仍是 Jenkins,由于最重要的是生态的构建,他们已经很好了。今天咱们要讲的在作一个弹性在 CI/CD 这个 Jenkins 上已经有这个插件了,可是在 Drone 的社区里面,有人提这个事,可是如今尚未看到。github
接下来,咱们看一下 CI/CD 这些工具的选择和他们的发展。首先最老牌的确定是 Jenkins。实际上在容器技术兴起以前,CI/CD 简直约等于 Jenkins。可是在出现容器技术以后,不少新生 CI/CD 的工具也应运而生,好比说图中 Drone 工具,它是一个彻底基于容器来实现的 CI/CD 工具。它与容器地结合地很是好,而且它的构建过程是彻底在容器中实现的。golang
第三个是 Gitlab CI,它主要特色是与 Gitlab 代码管理工具结合地比较好。Jenkins 2.0 时开始引入 pipeline as code 特性,什么叫 pipeline as code?pipeline as code 能够帮咱们自动生成一个 jenkins file。在 Jenkins 1.0 时,若是咱们想要配置一条流水线,须要先登陆 Jenkins,而后建一个项目,而后在里面写一些 shell。这样虽然能达到一样的效果,可是它有一个最大的弊端,就是可复制性和迁移性很差。并且它与 Devops 有自然地割裂,好比通常是运维人员来管理 Jenkins 这个系统。开发人员编写代码,可是这个代码怎么去构建,发布到哪里,他是彻底不知道的,是运维人员在Jenkins 里面配的。这个就形成了开发和运维地割裂。但 pipeline as code 这种方式出现了以后,咱们能够把 jenkins file 跟代码源码放在一样的仓库里面。
首先它有一个很是大的好处就是咱们发布的流程也能够归入版本管理,这样对一个错误就可追溯。这是一个很是大地改动,可是实际上咱们在与客户沟通中发现,虽然不少人在 Jenkins 上都已经升到 2.0 系列了,可是它们的用法仍是彻底在 1.0 系列,不少用户都没有把 jenkins file 这种方式用起来。另一个就是对容器地支持,大概 2016 年左右,那时对容器的支持是很是弱的,在容器里面运行 Jenkins,同时构建的产物也是 Doker 会很是麻烦。
可是, Drone 对容器的支持力度就很是好。首先它彻底用 Doker 方式来运行,就是说你的构建环境也在一个容器里,你须要构建一个 Doker build 镜像,而后在推送出去的时候,它也在容器里面运行,而后它须要一个 privilege 权限。它这种方式有几个特别好的地方,首先它不会对宿主机产生任何残留,好比说你这个容器一销毁,构建中产生的一些中间文件彻底都跟着销毁了,可是你若是用 Jenkins 的话,随着用的时间愈来愈久会沉淀出不少临时文件,它占的空间会愈来愈大。你须要按期作一些清理,并且清理过程当中你又不能直接一键清空,因此这是很麻烦的过程。而后插件的管理 Jenkins 还有一个特别让人头疼的地方,就是它的插件升级。首先你在 Jenkins 登陆进去,而后就作插件升级。若是说我想临时在一个新的环境里面,起一个 Jenkins 先测试一下或作一些调试可能每新建一个环境,都须要把这些插件升级一次。并且刚才咱们说的在 Jenkins 里面作的全部配置,也都须要从新配置一遍,这是一个很是繁琐的一个过程。
可是 Drone 这个工具它有一个特别好的地方,就是全部的插件都是 Doker 容器,好比说你在 pipeline 里用这个插件,你只要声明用这个插件就能够了,你不用去本身管理把插件下载到哪里,而后怎么安装,它这个一切都是全自动,只要说你网络能把插件容器镜像访问到就能够了,这很是便利。
而后关于生态的构建,Jenkins 的最大的优点就是它的插件很是多,就是你想用的各类东西都有,并且它基础的底座很是好,你的插件能够实现的能力很是的强。好比说 pipeline 就是这种方式,它从 1.0 到 2.0 虽然有了,可是它彻底是经过插件来实现的。可是如今 Jenkins 的发展又开始有点第二春的感受。他开始对 Kuberentes 的支持力度明显的加大了不少,首先从 JenkinsX 开始,它融合了一些 Kuberentes 生态相关的一些工具,好比 Harbor、Helm 它能够很是便利地在 Kuberentes 集群上来作一些构建,而且把一些作服务的固化的一些编排文件放到 Helm 里面。
另外,如今它有一个新的子项目叫 config as code,也就是说他把全部 Jenkin 里面作了一些配置,均可以输出成一个 code 的形式,就是对整个 Jenkins 的迁移,或者说复制都是一个很便利的改进。
讲了那么多,实际上最后咱们选择的东西仍是 Jenkins,由于最重要的是生态的构建,他们已经很好了。今天咱们要讲的在作一个弹性在 CI/CD 这个 Jenkins 上已经有这个插件了,可是在 Drone 的社区里面,有人提这个事,可是如今尚未看到。
web
而后咱们看一下 CI/CD 它的系统的业务场景,它有一个比较典型的场景与特色,首先它面向开发人员,这是比较少见的,由于开发人员通常都比较挑剔一点。因此你要是这个系统作的不够稳健了,或者说响应时间比较长一点的话,会被常常吐槽。docker
而后就是有时效性要求,由于咱们代码写完以后,往上提交,咱们都不但愿在这个代码的构建中一直排队,咱们但愿立刻就开始进行构建,而且资源足够丰富。另一个就是它的资源占用的波峰波谷是很是明显的。就由于开发人员不可能时时刻刻都在提交代码,有的人可能一天提交几回,有的人会提交不少次。
由于我以前看过有一个分享,有一我的画了一条反映自家公司构建任务的曲线。他们公司大概是天天下午3、四点的时候代码提交量最高,其余时间都比较平缓。这说明他们公司3、四点的时候,程序员提交代码开始划水了。而后随着 CI/CD 资源地需求愈来愈高,构建集群是一个必需要作的一件事情。就是提升负载能力,缩短任务的排队时间。固然真正的集群有一个让人以为很不太好的地方,就是它的 Master 实际上只有一个,固然这个也能够经过插件来作改进。
容器能够给咱们 CI/CD 系统来注入新的能力,就是环境隔离的能力。咱们能够经过 Kubernetes 来为 CI/CD 系统注入更多的能力,而后矛盾点就出现了。开发人员老是但愿 CI/CD 系统可以快速地响应代码提交的一个事件,可是每一个公司资源都不多是无限的。由于就像上面提到的,若是天天下午3、四点的时候是一个代码提交的高峰,这个时候可能须要 30 或 40 台机器才能知足构建的任务。可是我不可能天天就开着 30 或 40 台机器在这里,就为了天天下午3、四点,可能会构建1、两个小时。
Kubernetes 能够为 jenkins 注入新的能力,让 CI/CD 系统实现弹性的能力。咱们指望的目标是什么呢?有构建任务的时候,能够自动为咱们资源增长新的机器也好,或增长新的运计算能力也好,反正就是当我须要的时候,能够帮我自动地作一个资源扩张,可是同时也在我不须要的时候,能够自动把这些资源释放掉。shell
咱们指望的目标就是这样,Kuberentes 就能够为 Jenkins 来作这样的能力。Kuberentes 做为一个容器编排的系统,它所能提供的能力,它能够快速地弹出一些新的实例,而且把它们自动调度到空闲的机器上,作一个资源池,在资源池里面作一个调度,而且他执行完任务以后,它能够作一个回收。并且若是把这 Jenkins Master 也部署在 Kuberentes 之上,它能够对 Master 作一个故障转移,就是说若是咱们系统能够容忍的话,Master 就算挂了,我能够快速把它调到另一台机器上,这个响应时间不会很长。后端
这里面也是用一个插件来实现,这个插件名字比较直接叫 Kuberentes-plugin,它这个插件所能提供的能力就是说,他直接管理一个 Kuberentes 集群,它在 Jenkins 里面安装以后,它能够监听 Jenkins 的构建任务。有构建任务,在等待资源的时候,它就能够向 Kuberenetes 去申请一个新的资源,申请一个新的 Pod 去作自动地构建完以后,它就会自动的清理。
微信
先简单介绍一下它的能力,由于这个插件安装完以后,它对 pipeline 的语法也有一个改造,一会咱们来看一下实例。可是就算到了这一步,仍是不行的。首先,Kuberentes 的集群规划仍是一个问题。比说我有个集群有 30 个节点,真正的 master 部署在这上面,而后装了那些插件,作了一个管理以后,咱们能够发现来了一个新的任务,它就起一个新的 Pod,把这个构建任务给执行制定完。
执行完以后,这 Pod 自动销毁不占集群的资源。 平时咱们能够在这集群上作一些别的任务,但这个终究仍是有一点很差,就是咱们这个集群到底规划多大,而且这个集群咱们平时不作构建任务的时候,能够在上面作一些别的任务。可是若是正在作任务,忽然来了一些构建任务,它可能会出现资源的冲突问题。
总的来讲,仍是有一些不完美的地方,那么咱们能够利用 Kuberentes 一些比较没那么常见的特性,来解决咱们刚才说的这个问题。这两个东西一个是叫 Autoscaler,一个叫 Virtual node。咱们先看一下 Autoscaler,Autoscaler 是一个 Kubernetes 官方的一个组件。在 Kuberentes 的 group 下面支持三种能力:
我要讲的是 Cluster autoscaler,是对集群 node 节点数量作一个扩缩容。 首先咱们看一下,这个是在阿里云咱们容器服务上所实现的 Autoscaler 的一个方式。咱们看一下这个图,这个是 HPA 和 Autoscler 作结合使用的一个场景。
HPA 监听监控的事件时发现资源使用率上升到必定程度了以后,HPA 会自动通知 workload,来弹出一个新的 Pod,弹出一个新的 Pod,可能这时候集群资源就已经不够了,因此这个 Pod 可能就会 pending 在这里。它就会触发 Autoscaler 的事件,Autoscaler 就会根据咱们以前配置好的 ESS 这个模板来去弹出来一台新的 Node,而后自动地把 Node 加入到咱们集群里面。 它是利用了 ESS 定制的模板功能,而且它能够支持多种的 Node 实例的类型,能够支持普通实例,支持 gpu,还有抢占式实例。
而后第二种是 Virtual node,Virtual node 实现方式是基于微软开源的 Virtual Kubelet 这个项目。它作了一个虚拟的 Kubelet,而后向 Kubernetes 集群里面去注册上面。但若是不太好理解的话,能够想象一下 MySQL proxy ,而后他把本身假装成一个MySQL server,而后后端可能管理着很是多的 MySQL server,而且它能够帮你自动的作一些 SQL 查询的路由或者拼接。
Virtual kubelet 作的也是相似的工做,就是说它自己向着 Kubernetes 注册说我是一个节点,但实际上它后端管理的多是整个公有云上的很是多的资源,他可能对接公有云的一些 ECI 或者说对接的这些 VPC,这是一个它的大致的示意图。
在阿里云上他们对接的是阿里云的 ECI 作一个弹性的容器实例,它响应时间就很是快,由于它不须要把 Node 去加入到集群里面,它是大概可以到一分钟一百个 Pod 左右这种性能。并且咱们能够在 Pod 上声明这种资源的使用状况,这是一个很是快的响应速度时间。
而后刚才说咱们利用这两种方式,就能够对咱们 CI/CD 弹性的系统作出新的改造,咱们不用很是早规划好咱们集群的规模,咱们可让集群规模在须要的时候自动的作一些伸缩的动做。可是你作了这些动做以后,咱们作了这些把真正的放在容器里面的这些动做以后,引入了一些新的门槛:docker-outside-of-docker 和 docker in docker。
咱们在 Docker 中运行 Jenkins 时,一般有两种方式,一个是把宿主机的 docker.sock 挂载到容器里面,让 Jenkins 经过这个文件来和本机的 docker daemon 作一个通讯,而后它在这里面作 docker build 构建镜像,或者把这些镜像 push 到远程的仓库里面,因此它中间产生的全部镜像都会堆积在本机上,这是一个问题。
在一些 serverless 的那些场景上使用,它就会有一些限制,由于 serverless 自己就不容许把 socket 文件给挂在进去。另一个就是 docker in docker 这种方式,它的优势就在于在容器里面它启动一个新的 Docker daemon,它全部的中间产物、构建产物随着容器都一块儿销毁,可是它有问题,它就是须要 privilege 的权限。
不少时候咱们是尽可能不要用它。另一个就是说你作 docker build 的时候能在宿主机上作的时候,它若是有已经有镜像了,它会直接就使用这个镜像,可是你用 docker in docker 这种方式来使用的,它每次都会从新拉进项,拉镜像也是须要必定时间,这个取决于咱们各个使用场景来判断。
这时又引入了一个谷歌开源的新工具——Kaniko。它作的东西是 docker in docker 的方式。它有一个很是大的好处就是不依赖 Docker,并且因此它不须要 privilege 权限就能够在容器里面用用户态的模式,来彻底构建 docker image。用户态执行 Dockerfile 的命令,它把这个镜像彻底构建出来。
这算是一个比较指望的弹性的 CI/CD 系统。而后这个时候就是说从真正的节点到底层的计算资源所有是弹性扩缩的,并且知足交付的需求,能够很是精细化地管理咱们的资源。
而后咱们能够看一下 Demo 演示:
https://github.com/hymian/webdemo 这里是我准备好的一个例子,重点在这个 Jenkinsfile 文件,里面定义了agent 的 pod template,包含两个容器,一个用来作 golang 的 build,一个用来作 image 的 build。
而后咱们如今构建它。开始构建了,刚开始的,由于是如今咱们在这环境里面只有一个,只有一个 master,因此他就是没有不会有构建节点。你们能够看到,它如今新启动了一个 Pod,这个 Pod 是做为节点加进来的,可是由于我在这个 Pod 模板里面定义了一个 label,因此它没有这个节点,因此它 Pod 状态是 pending 的。因此咱们在构建日志里面显示的这个是 agent 节点是离线的。
可是咱们在这个集群里面定义了一个弹性伸缩的一个东西,当没有节点的时候,它会自动作一个新节点分配加入,能够看到有一个节点正在加入,这个我就能够稍等一下。就是说这段时间可能会有个一分钟两分钟的时间。
这个是异常,是由于这个节点正在向集群加入,因此它显示是异常,这是咱们从命令行看一下,好,已是四个节点了,加了一个节点,这时候咱们看 Pod,这时候在 agent 正在建立,这时候你们可能有一个小的细节,你们能够看一下,就是 0/3 是显示 Pod,它有三个容器,可是我刚才在这个里面定义的,它其实是 Pod 里面只有两个容器,这就是咱们刚才 PPT 上写的一个地方。
JNLP 那个容器,是 plugin 自动注入的一个容器,它经过这个容器实时的向 master 汇报构建的一个中间的状态,我把它的日志给发送出去。这个是 agent 的节点在初始化的一个过程一个事情这时候 slave节点已经在运行了。我这边已经输出完了,构建完成。个人分享内容就这些,谢谢你们。
原文连接 更多技术干货 请关注阿里云云栖社区微信号 :yunqiinsight