我们隔一流的软件生产工艺还有多远?在距离15000公里外,Amazon一年可以进行5000万次部署,在这一边某电商平台的研发部门里,让他们引以为傲的是他们正在进行“敏捷”开发模式,并对外号称他们是以每周为迭代来进行升级。时间是定在周四(因为这样如果出现问题,周五还可以修复,不用周六加班),但是周四的晚上,开发/测试/还有产品的负责人是妥妥的要留下来了奋斗到天明了,如果运气好的话还可以在 12点之前回家。运气这种事情,总是不太好说。

这是我们曾经经历的痛, 由于缺少自动化测试以及完整的上线发布流程,每次一上线,总能折腾个4到5小时。所以后来在我们自己实现这套新零售的saas系统的时候,从一开始我就在思考如何避免这个问题。我们采用了微服务架构,由30多个微服务组成, 部署在K8S上, 测试环境与生产环境都是借助于gitlab ci来完成的,并且同时可以支持腾讯和阿里云的k8s容器服务。这个花了3天调研和实施出来的持续集成方案在时间收益上已经给我们带来了超过 20倍的回报 。

微服务

微服务存在着多个服务独立部署的情况,在没有k8s之前需要自己实现一套完整的持续部署工具,这个复杂度及成本可以说80%的公司都承受不起。但是微服务部署在 k8s上之后一切就变的简单的多了。

单个服务在k8s中的部署可以用 kubectl set image的语句在ci job中实现

kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1

如果是30多个甚至更多的服务,我们把所有的资源定义文件存放在一个单独的代码仓库中进行维护和版本管理会更合适一些。在没有helm之前,我们可能通过 kubectl apply -f ./ 的方式基于整个文件夹来创建和更新 k8s资源。即使这样,我们在不同测试环境与生产环境由于不同的配置需要有两个文件夹来保存资源定义文件。

Helm


helm可以将多个k8s的资源定义文件打包在一起进行整体的部署、更新,就像一个应用程序一样。

这种场景就特别适合微服务,我们可以将所有的服务以及中间件、数据库、证书等资源定义在一个helm package下来进行部署和更新。

一个helm package的构成主要由模板和参数来构成,模板就是 k8s的资源定义文件,在模板中可以引用外部的参数,我们一组微服务的应用可以用同一个包只需要替换不同的参数即可。

我们以一个简单的单体应用来举例,它包括一个api, 一个mysql数据库,以及一个ingress配置将api就暴露在k8s集群之外。在本地安装好helm client之后可以使用helm create [name]来创建一个package。

helm create Helm

在templates中新建api-deploy.yaml, ingress.yaml, mysql-svc.yaml,这些文件的内容和我们平台创建k8s资源的定义文件是一样的,只不过我们在这里可以使用helm提供的参数。

比如命名空间我们就可以这样来使用

kind: Service
apiVersion: v1
metadata:
name: {{ .Values.image.api.name }}
namespace: {{ .Values.namespace }}
spec:
{{ if .Values.image.api.nodePort }}type: NodePort{{ end }}
ports:
- port: 80
targetPort: 80
{{ if .Values.image.api.nodePort }}nodePort: {{ .Values.image.api.nodePort }}{{ end }}
selector:
name:  {{ .Values.image.api.name }}

在模板中还支持条件判断,比如在测试环境我们可以配置nodePort来暴露服务,而生产环境中则不支持。

在values.yaml中我们定义以下内容供测试环境使用,在生产中可以将namespace改成生产环境对应的命名空间名以及移除nodePort节点即可。

namespace: hunterpro
image:
api:
name: hunterpro-api
version: 1.0.0.2991
nodePort: 31013

之后我们可以使用helm install -n [name] ./helm 来将这个helm package部署到k8s集群中 。 ./helm为包定义目录。helm 所连接的k8s集群为kubectl的配置。

Helm package Chartmuseum

一个helm的包存放在一个文件夹内,同时我们还可以使用 helm pakcage将它打包成一个文件来方便与其它人共享。同时也可以像上传docker我镜像一样上传helm package,并且同样可以在仓库上保存不同的版本。Chartmuseum就是一个开源的 helm package仓库服务。

我们可以使用docker将它快速安装

docker run --rm -it \  -p 8080:8080 \  -v $(pwd)/charts:/charts \  -e DEBUG=true \    -e STORAGE=local \ -e STORAGE_LOCAL_ROOTDIR=/charts \
chartmuseum/chartmuseum:v0.8.1

以上我们就可以拿到一个远程 helm package repository的地址,只需要将它加入本地的repo list中即可

helm repo add [name] [url]

官方还提供了helm push插件,让我们可以轻松地将本地的helm package推送到远程的仓库

$ helm push mychart/ [repo name]
Pushing mychart-0.3.2.tgz to [repo name]...
Done.

完整实践

有了对 helm以及helm package repository的初步了解,我们就可以进入到我们整个ci方案了。

1. 开发提交代码到dev分支

2. 触发项目dev构建流水线  gitlab ci开始进行代码的构建,使用项目内dockerfile来构建 docker镜像

3. 镜像构建成功之后推送到镜像仓库 (我们根据不同的分支会把镜像分别推到阿里或者镜像云)

4. 触发buildscript dev构建流水线 (传送参数 :当前版本以及当前更新服务名称)

5. build script 下载最新代码并将helm package的参数内的对应服务的镜像版本更新至当前版本

6. 提交更改之后的代码

7.  helm package 并且helm push将最新的包推送到远程镜像

8. 用最新的 helm package来更新开发的集群

我们使用gitlab ci来做持续集成,如果不了解gitlab ci可以查看这篇之前的文章。

GitLab CI 自动部署netcore web api 到Docker

.Net & Docker(二)5分钟快速用Docker部署你自己的GitLab

当我们的gitlab runner配置好之后,由于涉及到k8s我们还需要做以下事情。

- 安装kubectl 并配置连接到集群

- 安装helm client (helm client会直接使用kubectl 的连接操作对应集群)

- 安装 helm push 插件

- 由于我们在流水线执行过程中更新代码并推送用到了python脚本,所以我们需要安装python3.6

安装kubectl

与k8s相关的学习最大的问题是它有比较多新的概念,刚开始学习会比较难。而第二大问题就是那堵墙,在很多情况下会让我们直接想放弃。在安装kubectl 的时候,如果是 centos我们可以使用阿里的镜像:

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

然后再安装kubectl

yum install -y kubectl

安装helm

centos 可以使用snap来安装并添加阿里的稳定仓库源来进初始化,默认使用谷哥的稳定源会失败 。

sudo snap install helm --classic   helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.14.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
https://yq.aliyun.com/articles/159601

安装python和 PyYAML库

我们上面提到我们要通过 buildscript的构建流水线去更新helm pakcage内某个服务的镜像版本

image:
auctionapi:
name: auction-api
nodePort: 31100
version: 1.0.2532
deliveryapi:
name: delivery-api
nodePort: 31049
version: 1.0.2542
fundapi:
name: fund-api
nodePort: 31034
version: 1.0.2538
gatewaymp:
name: gateway-mp-api
nodePort: 31039
version: 1.0.2544

比如我们的 values.yaml 参数配置是这样的。当我们提交gateway-mp-api 之后,当前的版本号会升级主为 1.0.2545 。gateway-mp-api的构建流水线会将版本号为 1.0.2545的镜像推到镜像仓库,接下来我们要做的就是通过 helm upgrade 来更新我们在k8s中的服务。

gitlab ci中可以通过 web hook 的方式触发另一个仓库的ci,所以我们在这里每一个 api推送完镜像之后都会触发 buildscript的更新,并传入参数:当前服务名称(对应values.yaml中的 服务key) 和最新版本号。

然后借助一段python脚本来更新values.yaml, 下面的代码用到了python的 yaml库,可以比较方便的操作yaml格式的文件。

import sys
import yaml with open("values.yaml") as f:
value = yaml.load(f)   value['image'][sys.argv[1]]['version'] = sys.argv[2]
with open("values.yaml","w") as f:  yaml.dump(value, f)

buildscript 的.gitlab-ci.yaml文件 script

script:  - helm init --client-only --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts  - helm repo add $helmRepoName $helmRepoUrl  - cd BuildScript/dev-wotui/wotui-dev    - python3.6 update.py $image $version   - git add . - git commit -m "upgrade to $version" || true - git push origin wotui/develop - cd ../    - helm push ./wotui-dev $helmRepoName -v $version   - helm repo update  - helm upgrade $helmReleaseName $helmPackageName

所完成的步骤包括:

- 初始化helm 仅客户端

- 添加远程 helm 仓库

- 更改 helm chart values.yaml 对应的服务镜像版本

- 提交buildscript 代码

- 推送 helm package

- 更新微服务

服务项目的构建流水线 

每一个服务自己的gitlab-ci文件中只需要完成构建自己的镜像并推送到镜像仓库,之后再用curl发起buildscript 项目的构建并传入对应参数即可。

stages:    - image - deploy
variables:  versionNo: $MAIN_VERSION.$SECONDARY_VERSION.$CI_PIPELINE_ID registry: registry-vpc.cn-shanghai.aliyuncs.com/    registryUser: ********  registryPwd: ********   repository: namespace/delivery-api  docker image:   stage: image    tags:   - wotui only:   - wotui/develop script: - docker build -t "$registry$repository:$versionNo" ./Collectin.Delivery.API  - docker login -u $registryUser -p $registryPwd $registry   - docker push "$registry$repository:$versionNo"   deploy: stage: deploy   variables:  GIT_STRATEGY: none  tags:   - wotui only:   - wotui/develop script: - curl -X POST -F token=${PUBLISH_TRIGGER_TOKEN} -F ref=wotui/develop -F "variables[version]=$versionNo" -F "variables[image]=deliveryapi" http://code.collectin.cn/api/v4/projects/50/trigger/pipelin

以上,当你提交代码到服务的分支,接下来就是视频中全自动的编译,打包,部署流程。


关于微服务与K8S

只要找到了合适的方法,微服务就没有那么复杂 。即使不是粒度非常细的微服务,哪怕是粗粒度的服务,同样可以借用于K8S来进行运维管理。 在现在它可以节省大量的运维操作时间,在未来它也可以很好地适应业务快速扩展。 随着企业对于开发人员的要求不断增高,如果你希望在未来的两到三年晋升成为架构师,那么微服务架构和K8S是你不得不掌握的必要技能。

下面是一套根据我们近两年微服务项目实战开发以及k8s运维经验中提取出来的课程,8月重启录制,开放购买。 点击左下角阅读原文了解更多信息。


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

可落地微服务on k8s的持续集成/部署方案相关推荐

  1. 24岁秃头程序员教你微服务交付下如何持续集成交付,学不会砍我

    微服务如何持续集成交付 在微服务架构下,每一个微服务都是职责单一的,可独立部署单元,但是众多分散的微服务也带来了代码共享.微服务功能依赖.版本管理等复杂问题,微服务需要解决配置管理.服务持续集成.持续 ...

  2. 私有化轻量级持续集成部署方案--05-持续部署服务-Drone(上)

    Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/cou ...

  3. 利用UK8S落地微服务,加速元年科技业务迭代

    "使用UK8S,开发者可以像使用普通云服务器一样迅速搭建K8S环境.在享受K8S带来的便利的同时,能够让开发人员集中注意力在业务实现的细节,而不必在基础架构搭建上浪费太多的精力.UCloud ...

  4. javaweb k8s_K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程...

    K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程 课程内容是关于Kubernetes微服务架构学习课程,基于K8S开展ASP.NET核心进行微 ...

  5. CI Weekly #5 | 微服务架构下的持续部署与交付

    CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...

  6. 微服务架构下,DLI的部署和运维有何奥秘?

    华为云数据湖探索DLI是支持多模引擎的Serverless大数据计算服务,其很好的实现了Serverless的特性: 1.弱化了存储和计算之间的联系: 2.代码的执行不再需要手动分配资源: 3.按使用 ...

  7. GAF安装部署-微服务架构下的云原生部署

    GAF安装部署指南-微服务架构下的云原生部署 从上一篇文章<GAF简介-基于SuperMap GIS基础软件的GIS应用框架>我们知道SuperMap GAF分为社区版和企业版,本篇文章主 ...

  8. Jenkin持续集成部署-Jenkins常用插件篇

    Jenkin持续集成部署-Jenkins常用插件篇 前言 1. maven插件 2. pipeline 3. SSH 4. Docker 5. Blue Ocean 6. 自定义配置JDK 前言 本篇 ...

  9. 在低容错业务场景下落地微服务的实践经验

    "健康体检是一个低容错的场景,用户到医院体检,由于 IT 原因导致无法完成预约的项目,会对用户体验造成极大的影响." --禾连健康 CTO 邓志豪 禾连健康成立于 2014 年,是 ...

最新文章

  1. flask中的CBV , flask-session在redis中存储session , WTForms数据验证 , 偏函数 , 对象里的一些小知识...
  2. eureka 其它语言_SpringCloud之Eureka-Go语言中文社区
  3. java 英文字符串排序_英文字符串排序算法
  4. call 和 apply 的使用
  5. javascript小技巧 JavaScript[对象.属性]集锦 [zz]
  6. envi窗口滤波_高光谱ENVI图像处理之滤波
  7. 【leetcode 简单】第四十一题 Excel表列序号
  8. Windows开发——DLL 文件导出和使用
  9. linux 查找py文件命令_小命令大作用---linux 下快速查找
  10. NPDP产品经理认证班将于近期开课
  11. 中国知网论文免费下载的4个方法分享
  12. 读良葛格初心者之路有感
  13. tt服务器系统,TT服务器使用手册.doc
  14. PAT/C++甲级题解——图
  15. 基于 PCA 的人脸识别系统及人脸姿态分析
  16. 452. 用最少数量的箭引爆气球
  17. iPhone4/4s 5.1.1版本越狱后无法连接iTunes,出现0xE8000012错误的解决方法
  18. C语言求解距多个点最短长度,算法设计技巧与分析课后习题答案沙特
  19. Nmap入门:隐私刺探
  20. DROO memory.py

热门文章

  1. vue mock模拟后台接口数据
  2. 面向对象进阶(二)----------类的内置方法
  3. 898A. Rounding#数的舍入
  4. express 4 简单实现自动注册路由功能
  5. ObjectiveC 深浅拷贝学习
  6. C# WPF中添加调试信息查看窗体
  7. BeetleX进程服务管理组件应用
  8. 【分享】154页微软WPF官方手册(含.NETCore和.NET Framwork双版本)
  9. MIPS衰落 LoongArch崛起
  10. “工业互联网平台“将成为工业制造企业的标配