前言

2018年既是微服务架构火爆的一年,也是容器和Kubernetes收获赞誉盆满钵满的一年;在kubernetes的引领下,以容器为中心部署微服务已成为一种事实标准,并不断加速着微服务架构模式落地,持续地发挥着它的魔力。企业,特别是互联网公司,为了快速响应前端用户的需求,缩短产品从需求到交付的周期,常常需要快速地、细腻度地迭代产品,以抢占市场先机;在微服务模式下,可以很好地满足这个要求,只发布变化的服务,从而最小化单次迭代的风险,实现敏捷开发和部署。

当采用微服务模式后,整个业务流程将被垂直拆分成多个小单元;每个小单元都是一个独立开发、独立部署和独立扩展的微处理服务,这样的灵活性非常适合敏捷开发模式,但也给开发和运维带来了固有的复杂性和难度。对于开发者而言,由于微服务应用整体作为一个分布式系统提供服务,需要选择合适服务通讯协议,并处理潜在的网络分化瞬时故障等情况,除此之外,还需要建设服务发现、配置中心等基础设施;对于运维人员,需要利用容器的可移植性,持续地集成和部署微服务到不同的集群环境,这些都要求运维人员具有非常全面的能力,比如:熟悉容器及k8s、能编写Linux Shell运维脚本、熟练一种持续集成部署工具(比如:gitlab、jenkins)等。

综上所述,如何搭建一条成熟稳定、且符合微服务特色的高度自动化DevOps管道又成为了另一个难题。

目标

以最小的学习成本,搭建一条成熟稳定、且符合微服务特色的高度自动化DevOps管道,按需地持续集成/部署微服务到kubernetes。

工具 - 最小的学习成本

kubernetes + gitlab + shell

方案 - 愿景

1. 持续集成 - CI

在kubernetes的master节点部署gitlab-runner,充当gitlab服务器的客户端;当提交或合并代码到指定的分支时,gitlab-runner自动从gitlab拉取代码,利用master主机提供的边缘计算能力来执行已编排好的DevOps CI管道=》编译代码、运行单元和集成测试、容器化微服务成镜像,最后上传到企业镜像仓库,这就是持续集成流程,该阶段交付的产物为镜像。

2. 持续部署 - CD

在kubernetes的master节点部署gitlab-runner,充当gitlab服务器的客户端,当持续集成阶段交付了新版本的镜像后,从企业镜像仓库拉取最新版本的镜像,利用master主机提供的边缘计算能力执行已编排好的DevOps CD管道=》同步服务配置信息到配置中心(k8s的ConfigMap),并滚动更新kubernetes集群镜像版本。

部署环境

安装目录:/root/gitrunner

工作目录:/home/devops/gitrunner

> mkdir -p /root/gitrunner && mkdir -p /home/devops/gitrunner;

1. 部署gitlab-runner

在kubernetes的master节点部署gitlab-runner,命令如下:

> wget -O /root/gitrunner/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64;
> cd /root/gitrunner;
> chmod +x gitlab-runner;
> # 注意:建议使用root用户进行安装,以避免不必要的权限问题。
> ./gitlab-runner install --user=root --working-directory=/home/devops/gitrunner;
> ./gitlab-runner start;

详情请参考: Install GitLab Runner manually on GNU/Linux

2. 注册gitlab-runner

gitlab支持注册两种类型的runner:

1. Specific Runners

这是隶属于特定项目的专有工人,不接受其他项目调遣。

2. Shared Runners

这是隶属于gitlab-server的工人,可以共享给所有的项目调遣。

这两种Runner各有千秋,如果为每一个项目都注册专用Runner,会显得比较繁琐和多余,而使用共享Runner就很省事,但是一个工人一次只能做一件事情,当同时调遣一个工人时,那么就会出现竞争等待,故大家还是实际情况来注册工人吧,只要不延误工期就行,嘿嘿。

注册runner

在开发、预生产、生产环境注册Runner,并贴上标签:build、staging、prod。

备注:后面搭建DevOps管道时,将根据标签来调遣工人。

步骤
  1. 获取项目地址和注册token,依次查找路径:Settings => CI / CD => Runners settings,如下:

  2. 注册:

    > cd /root/gitrunner;
    > ./gitlab-runner register
    > # 回车,根据提示填写项目地址、注册Token、标签、执行器
    > # 假如,项目地址为:http://gitlab.justmine.cn:8002/, 项目注册token为:6iS4GBCh18NR4GPoMyef。
    > ## 以开发环境为例(仅供参考)
    > Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
    http://gitlab.justmine.cn:8002/
    > Please enter the gitlab-ci token for this runner:
    6iS4GBCh18NR4GPoMyef
    > Please enter the gitlab-ci description for this runner:
    [justmine.com]: development environment
    > Please enter the gitlab-ci tags for this runner (comma separated):
    build
    > Registering runner... succeeded runner=4iS4GwCh
    > Please enter the executor: ssh, docker+machine, kubernetes, virtualbox, docker-ssh+machine, docker, docker-ssh, parallels, shell:
    shell
    > Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
    > # 其他环境同理

搭建DevOps管道 - PipeLines

上面的方案仅仅描述了愿景,也就是期望达成目标的最后结果,但对于如何落地一条真正的管道而言,还是显得非常的空洞。其实这正是DevOps的难点,大体流程上都晓得有个持续集成、持续部署,讲起来如数家珍,落地时都之乎者也。

同样,秉承微服务的思想,分而治之,我们将管道分为两个部分:创建、更新,即先创建一个主板次,然后再基于此主板次进行小版本迭代,不断地扩展新功能。通过这样有效的拆分,是不是就不那么的空洞了,就像领域驱动设计的CQRS模式一样,区别地对待读写,从而大大地减少了阻抗,也非常地切合产品的创新迭代,比如将需求拆分为3期,每一期都对应一个主版次,然后再小版本迭代每一期的需求,完成一期,封板一期,彼此隔离,互补影响,同时也方便追溯。

理清了整个管道的脉络,现在就需要思考一些实际问题了,比如:

1. 如何将持续集成/部署微服务流程脚本化,即如何实现基础设施代码化

2. 如何动态解析git当前变化日志,实现准确地按需发布微服务

3. 如何保留现场,并以最小的成本重试管道

4. 在不修改管道脚本的情况下,如何手工控制按需发布、自动伸缩和回滚微服务

5. 如何兼容新增的微服务

6. 如何快速调试整个管道脚本

只有把上面的问题都处理了,才算是一条成熟可用的、企业级别的CI/CD管道,才符合高度自动化、稳定、快速、容错等特点;在互联网公司,可能一天要提交好几个版本到不同的环境,不能因为考虑不周而影响连续部署的进度,管道一旦投入使用就需要对修改闭合,只对扩展开放。

管道一览图

示例项目(AspnetCore)已分享到github,请参考:MicroService.AutoDevOpsPipeLines,欢迎start,欢迎fork,欢迎issue

为了验证管道的特性,我特意做了以下测试:

1. 创建环境 - 发布主板本

这是一个从0到1、从无到有的过程,这里一小步,却是落地DevOps管道的一大步。

版本迭代的第一步就是创建微服务集群环境,那么如何快捷地创建这个环境呢?我将使用kubernetes的包管理器helm来完成这个任务,可能很多同学都没用过这个工具,平时部署组件都是手工编写好yaml资源部署文件,虽然这种方式方便快捷,但是对于大量组件,以及需要实现基础设施代码化的场景,手工处理这种方式就不能满足需求了。

模板文件请参考示例项目,下面是创建环境的脚本化命令:

helm install /root/AutoDevOpsPipeLinesCharts \
--name=${releaseName} \
--set environment.upper=${Environment} \
--set environment.lower=${environment} \
--set namespace=${namespace} \
--set image.registryhost=${RegistryHost} \
--set image.username=${registryUserName} \
--set image.version=${version} \
--set replicas=${replicas}

从上面可以看出,实现部署服务脚本化的目的已经达到了。

下面我们在来看看如何脚本化整个创建环境管道线:

# 001 Continuous integration image to registry.
bash ./devops/PipeLines/Creation/001_CI.sh # 002 Create config information to k8s's configmap.
bash ./devops/PipeLines/Creation/002_CreateConfig.sh # 003 Release major to k8s's cluster.
bash ./devops/PipeLines/Creation/003_ReleaseMajor.sh # 004 Create gateway route.
bash ./devops/PipeLines/Creation/Gateways/Kong/004_CreateGatewayRoute.sh

备注:管道线脚本请参考示例项目(AspnetCore):MicroService.AutoDevOpsPipeLines/devops/PipeLines/Creation

1.1、测试

将刚刚创建的helm模板文件上传到gitlab-runner所在服务器的/root目录下,并添加配置,如下:

<Project>
<PropertyGroup>
<Major>1</Major>
<Minor>0</Minor>
<Patch>0</Patch>
</PropertyGroup>
</Project>

然后合并代码到分支release/staging,如下:

从上面可以,第一个主板次(1.0.0)已经成功发布到预生产环境。

生产环境同理,在预生产环境跑完各种测试后,合并代码到分支release/production即可。

2. 滚动更新 - 迭代小版本

这个阶段将模拟在第一个主板次(1.0.0)上进行小版本迭代需求,距离上次发布已经一周了,开发部门也完成了第一个小版本的开发工作,现在需要发布版本1.0.1到预生产环境进行测试,首先修改文件version.props,如下:

<Project>
<PropertyGroup>
<Major>1</Major>
<Minor>0</Minor>
<Patch>1</Patch>
</PropertyGroup>
</Project>

除了发布本次需求修改的两个微服务:Identity.API、Marketing.API以外,还需强制发布微服务Basket.API,添加配置,在gitlab仓库依次查找 (Settings => CI/CD => Secret variables),如下:

最后合并代码到分支staging。

  • 先来看看是否正确解析git变更日志和全局变量,准确地实现自动化和手工控制:

  • 再来看看整个管道的执行情况:

  • 最后看一下预生产环境的效果

从上面可以看出,第一个小版本(1.0.1)已经按需自动发布到预生产环境,一共滚动更新了三个微服务。如果当管道的某个阶段执行异常,只需要点击重试此阶段即可;如果需要重新手工干预,只需要添加配置信息,然后重试analysing-git-changes阶段,再依次重试后面的Job即可,整个过程无需修改CI/CD管道脚本,真正实现高度自动化、快速等特点。

生产环境同理,在预生产环境跑完各种测试后,合并代码到分支master即可。

3. 自动伸缩

3.1、伸缩单个微服务

经过一段时间的观察发现预生产环境的购物车(Basket.API)微服务吞吐量颇高,故决定扩容它的实例数量到2个,首先修改项目属性文件deploy.props,如下:

<Replicas>2</Replicas>

然后添加配置,如下:

最后合并代码到分支scaling/staging,如下:

3.2、伸缩所有微服务

同理,首先修改项目属性文件deploy.props,如下:

<Replicas>2</Replicas>

然后添加配置,如下:

最后合并代码到分支scaling/staging,或者直接重试管道的auto-scaling阶段,如下:

从上面测试看到,只需要修改配置,就可以支持不同粒度地伸缩微服务,也不用修改CI/CD管道脚本。

生产环境同理,只需要合并代码到分支scaling/production。

4. 回滚

4.1、回滚单个微服务

经过一段时间的观察,发现刚刚发布到预生产环境的版本1.0.1有问题,故决定回滚到上一个版次1.0.0,首先修改项目属性文件deploy.props,如下:

<!--回滚步长-->
<RollBackStep>1</RollBackStep>

然后添加配置(只回滚购物车微服务),如下:

最后合并代码到分支rollback/staging,如下:

4.2、回滚所有微服务

同理,首先修改项目属性文件deploy.props,如下:

<!--回滚步长-->
<RollBackStep>1</RollBackStep>

然后添加配置回滚所有微服务,如下:

最后合并代码到分支rollback/staging,或者直接重试管道的roll-back阶段,如下:

生产环境同理,只需要合并代码到分支rollback/production。

5. 可扩展性 - 兼容新增微服务

5.1、添加新的搜索微服务

经过一段时间的迭代,一期已经完工,二期新增了搜索微服务,这时修改helm模板文件支持部署搜索微服务,然后合并代码到release/staging,测试如下:

  • k8s

  • 网关路由

从上面可以看到,新增的搜索微服务已经成功发布到第二个主版次了。除了修改helm模板文件以外,整个过程并没有修改CI/CD管道脚本,圆满完成了兼容新增微服务的特性。

备注:我们可以将helm模板看成服务编排文件。

运维说明

1、分支

  1. build

    构建和编译代码。

  2. release/staging

    创建预生产环境。

  3. staging

    滚动更新预生产环境。

  4. release/production

    创建生产环境。

  5. master

    滚动更新生产环境。

  6. scaling/staging

    伸缩预生产环境

  7. scaling/production

    伸缩生产环境

  8. rollback/staging

    回滚预生产环境

  9. rollback/production

    回滚生产环境

2、配置文件

  • 应用程序配置 - app.props

    <!-- k8s命名空间前缀,比如:microservice-autodevopspipeline-v1 -->
    <NameSpace>microservice-autodevopspipeline</NameSpace>
    <!-- 应用程序名称,主要用于Tips -->
    <AppName>MicroService.AutoDevOpsPipeLine</AppName>
    <!-- 解决方案名称,用于生成项目 -->
    <SolutionName>MicroService.AutoDevOpsPipeLines.sln</SolutionName>
  • 版本配置 - version.props

    <!-- 主板次,不兼容升级 -->
    <Major>1</Major>
    <!-- 次板次,兼容升级 -->
    <Minor>0</Minor>
    <!-- 补丁版次,静默修复接口 -->
    <Patch>1</Patch>
  • 部署配置 - deploy.props

    <!-- Auto-scaling 实例数量 -->
    <Replicas>1</Replicas>
    <!-- Rollback 步长 -->
    <RollBackStep>1</RollBackStep>
    <!-- 镜像仓库用户名 -->
    <ImageUserName>devopspipelines</ImageUserName>

    特定环境配置,如:deploy.staging.props

    <!-- 镜像仓库主机域名 -->
    <RegistryHost>registry.staging.com:8100</RegistryHost>
    <!-- k8s restful地址 -->
    <K8sApiServer>https://192.168.2.110:6443</K8sApiServer>
    <!-- k8s 接口访问令牌 -->
    <AccessToken>utyeyerye.ytryeryeryyyyyyr.jhddghdhdhdhd</AccessToken>
    <!-- kong restful地址 -->
    <KongApiServer>http://192.168.2.110:81</KongApiServer>
    <!-- kong 域名绑定 -->
    <KongRouteDomain>staging.devops.com</KongRouteDomain>
  • 分支环境配置 - branch.env.props

    <!-- 解耦,目前用于滚动更新 -->
    <!-- key: branch name(last keyword), value: environment -->
    <staging>Staging</staging>
    <master>Production</master>

总结

上面的测试几乎涵盖了结合k8s管理应用生命周期的所有流程(部署、伸缩、回滚、发布),大家可以放心地运用或者扩展这个管道到自己的微服务项目中,比如:目前仅支持自动创建路由到kong网关,建议大家fork项目后,自行扩展,测试完成后,也可以提取PR。如果你采用示例一样的项目结构,只需要修改配置信息,然后开箱即用。

如果你有什么需求无法实现,欢迎加入QQ群:564095699,一起探讨k8s实践微服务的方方面面。

最后

如果有什么疑问和见解,欢迎评论区交流。

如果你觉得本篇文章对您有帮助的话,感谢您的【推荐】。

如果你对微服务实践感兴趣的话可以关注我,我会定期的在博客分享我的学习心得。

欢迎转载,请在明显位置给出出处及链接

[dotnet core]落地微服务特色的DevOps管道,持续集成/部署到kubernetes。的更多相关文章

  1. 手把手教你使用spring cloud+dotnet core搭建微服务架构:服务治理(-)

    背景 公司去年开始使用dotnet core开发项目.公司的总体架构采用的是微服务,那时候由于对微服务的理解并不是太深,加上各种组件的不成熟,只是把项目的各个功能通过业务层面拆分,然后通过nginx代 ...

  2. spring cloud+dotnet core搭建微服务架构:服务发现(二)

    前言 上篇文章实际上只讲了服务治理中的服务注册,服务与服务之间如何调用呢?传统的方式,服务A调用服务B,那么服务A访问的是服务B的负载均衡地址,通过负载均衡来指向到服务B的真实地址,上篇文章已经说了这 ...

  3. spring cloud+dotnet core搭建微服务架构:Api网关(三)

    前言 国庆假期,一直没有时间更新. 根据群里面的同学的提问,强烈推荐大家先熟悉下spring cloud.文章下面有纯洁大神的spring cloud系列. 上一章最后说了,因为服务是不对外暴露的,所 ...

  4. spring cloud+dotnet core搭建微服务架构:配置中心(四)

    前言 我们项目中有很多需要配置的地方,最常见的就是各种服务URL地址,这些地址针对不同的运行环境还不一样,不管和打包还是部署都麻烦,需要非常的小心.一般配置都是存储到配置文件里面,不管多小的配置变动, ...

  5. spring cloud+dotnet core搭建微服务架构:配置中心续(五)

    前言 上一章最后讲了,更新配置以后需要重启客户端才能生效,这在实际的场景中是不可取的.由于目前Steeltoe配置的重载只能由客户端发起,没有实现处理程序侦听服务器更改事件,所以还没办法实现彻底实现这 ...

  6. spring cloud+dotnet core搭建微服务架构:Api授权认证(六)

    前言 这篇文章拖太久了,因为最近实在太忙了,加上这篇文章也非常长,所以花了不少时间,给大家说句抱歉.好,进入正题.目前的项目基本都是前后端分离了,前端分Web,Ios,Android...,后端也基本 ...

  7. 微服务探索之路02篇liunx ubuntu服务器部署k8s(kubernetes)-kubernetes/dashboard

    本章介绍所需环境:ubuntu18.04,建立在上一篇微服务探索之路01篇已经安装了docker的基础上. 1 替换k8s镜像源为国内镜像 进入目录 cd /etc/apt/sources.list. ...

  8. spring cloud+.net core搭建微服务架构:服务注册(一)

    背景 公司去年开始使用dotnet core开发项目.公司的总体架构采用的是微服务,那时候由于对微服务的理解并不是太深,加上各种组件的不成熟,只是把项目的各个功能通过业务层面拆分,然后通过nginx代 ...

  9. spring cloud+.net core搭建微服务架构:Api授权认证(六)

    前言 这篇文章拖太久了,因为最近实在太忙了,加上这篇文章也非常长,所以花了不少时间,给大家说句抱歉.好,进入正题.目前的项目基本都是前后端分离了,前端分Web,Ios,Android...,后端也基本 ...

随机推荐

  1. CentOs 6 或 7 yum安装JDK1.8 (内含报 PYCURL ERROR 6 - "Couldn't resolve host 'mirrors.163.com'"错误解决方案)并分析为什么不能yum安装

    查看JDK的安装路径 # java -version============================查看Linux系统版本信息# cat /etc/redhat-releaseCentOS r ...

  2. Chatbot思考录

    人工分词产生不一致性的原因主要在于人们对词的颗粒度的认知问题.在汉语里,词是表达意最基本的意思,再小意思就变了.在机器翻译中会有一种颗粒度比另外一种颗粒度更好的情况,颗粒度大的翻译效果好. 为了解决词 ...

  3. maxSubArray

    Description: Find the contiguous subarray within an array (containing at least one number) which has ...

  4. C#备份及还原数据库的实现

    使用前要导入SQLDMO.dll 下载地址:http://down.51cto.com/data/853937 1.在用户的配置时,我们需要列出当前局域网内所有的数据库服务器,并且要列出指定服务器的所 ...

  5. RabbitMQ在windows系统安装部署文档

    1.RabbitMQ简介 MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它 ...

  6. Mac下MySQL无my-default.cnf

    转自https://www.jianshu.com/p/628bcf8bb557 As of MySQL 5.7.18, my-default.ini is no longer included in ...

  7. Python之路,进程、线程、协程篇

      本节内容 进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者 ...

  8. python_code list_2

    >>> import math>>> math.sin(0.5)0.479425538604203>>> >>> import ...

  9. mac 登录亚马逊云服务器报错:Permission denied (publickey).

    申请的亚马逊云服务器EC2,实例为ubuntu系统 一.打开终端,定位到放置密钥的文件夹: 二.确保私有秘钥不是公开可见的: p.p1 { margin: 0.0px 0.0px 0.0px 0.0p ...

  10. python实现邮件的发送

    一.163邮箱设置 进入163邮箱,点击设置中的pop3/smtp/imap 开启smtp服务,如果没有开启,点击设置,手机号验证后勾选开启即可,开启后图如下: 主要用到的就是smtp服务器:smtp ...