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

我们隔一流的软件生产工艺还有多远?在距离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资源。即使这样,我们在不同测试环境与生产环境由于不同的配置需要有两个文件夹来保存资源定义文件。


640?wx_fmt=png



Helm


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


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


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

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

helm create Helm

640?wx_fmt=png

在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来更新开发的集群


640?wx_fmt=png


我们使用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中的服务。


640?wx_fmt=png


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月重启录制,开放购买。 点击左下角阅读原文了解更多信息。


640?wx_fmt=jpeg


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

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round #579 (Div. 3) F1. Complete the Projects (easy version) 排序 + 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 比较直观的想法就是对于bi≥0b_i\ge0bi​≥0的项目&#xff0c;我们将aia_iai​从小到大排序&#xff0c;让后依次加bib_ibi​&#xff0c;如果有取不到的&#xff0c;显然就无解。否则再看…

历久弥新 - 微软万亿市值背后的文化支撑(下)|DevOps案例研究

内容来源&#xff1a;DevOps案例深度研究-Microsoft文化支撑研究战队&#xff08;本文只展示部分PPT研究成果&#xff0c;更多细节请关注案例分享会&#xff0c;及本公众号。&#xff09;本案例内容贡献者&#xff1a;陈飞&#xff08;Topic Leader&#xff09;、陈雨卿、郭子奇…

Codeforces Round #579 (Div. 3) F2. Complete the Projects (hard version) dp + 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 排序方式跟easyeasyeasy版本的一样&#xff0c;但是hardhardhard版本是输出最多能选多少&#xff0c;所以我们对b<0b<0b<0的情况不能直接贪心的来选了&#xff0c;考虑用dpdpdp来…

D:Ehab the Xorcist

或许更好的阅读体验 Ehab the Xorcist 思路 刚看时确实是一脸懵&#xff0c;最怕的就是这种构造题了&#xff0c;然后细想好像能写啊。 判断不可行的条件&#xff0c;只有两种情况&#xff1a; 一、v<uv < uv<u是一定不可能的&#xff0c;一串数的异或值一定小于…

架构杂谈《九》

微服务与轻量级通信机制微服务架构是一种架构模式&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间胡亮协调、互相配合&#xff0c;为用户提供最终价值。在微服务架构中&#xff0c;服务与服务之间通信时&#xff0c;通常是通过轻量级的通信机制&#…

Codeforces Round #585 (Div. 2) E. Marbles 状压dp + 逆序对

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 考虑数列最终的状态一定是相同颜色在一起&#xff0c;所以我们发现他的颜色是有顺序的&#xff01;显然可以用状压dpdpdp来枚举颜色的顺序&#xff0c;但是又有问题了&#xff0c;你怎么确…

E:Sleeping Schedule(DP)

或许更好的阅读体验 Sleeping Schedule 思路 这道题读题就感觉像时DPDPDP&#xff0c;读完题后更加坚定了&#xff0c;这是一道DPDPDP题目。 我们考虑状态转移方程&#xff0c;dp[i][j]dp[i][j]dp[i][j]表示在第iii次入睡时间是jjj的时候的时间最优值&#xff0c;所以显然有…

GitLab CI 自动部署netcore web api 到Docker

前端篇文章中&#xff0c;我们已经成功的将asp.net core webapi在Docker容器中运行&#xff0c;并且部署了一套自己的GitLab环境。.Net & Docker&#xff08;二&#xff09;5分钟快速用Docker部署你自己的GitLab.Net & Docker&#xff08;一&#xff09;在Docker容器上…

Codeforces Round #585 (Div. 2) F. Radio Stations 2-sat + 神仙建模

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 你现在有ppp种电台&#xff0c;有nnn对关系(x,y)(x,y)(x,y)代表xxx电台或yyy电台中至少有一个&#xff0c;mmm对关系(x,y)(x,y)(x,y)代表xxx电台或yyy电台中最多有一个&#xff0c;每个电台有两个参数li,ril…

C. Orac and LCM(数论lcm, gcd)

C. Orac and LCM 思路 题目非常简单&#xff0c;就是求gcd(lcm(i,j))foriinrange(n),forjinrange(n),i<jgcd(lcm_(i,\ j))\ for\ i\ in\ range(n),\ for\ j\ in\ range(n),\ i\ <\ jgcd(lcm(​i, j)) for i in range(n), for j in range(n), i < j 对于包含a1a_1a1…

.net core 实现基于 cron 表达式的任务调度

.net core 实现基于 cron 表达式的任务调度Intro上次我们实现了一个简单的基于 Timer 的定时任务&#xff0c;详细信息可以看这篇文章 。但是使用过程中慢慢发现这种方式可能并不太合适&#xff0c;有些任务可能只希望在某个时间段内执行&#xff0c;只使用 timer 就显得不是那…

P6378 [PA2010] Riddle 2-sat + 前缀和优化建图

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你nnn个点mmm调变的无向图被分成kkk个部分&#xff0c;每个部分包含若干点&#xff0c;请选择一些关键点&#xff0c;使得每个部分恰好有一个关键点&#xff0c;且每条边至少有一个是关键点。 1≤k,w≤n≤…

E:Tree Queries(假树链剖分写法)

博客园地址 E&#xff1a;Tree Queries 思路 当我写完A完这道题后&#xff0c;百度了一下&#xff0c;发现好像没有人是用类树链剖分来写的&#xff0c;都是LCALCALCA&#xff0c;于是我就来水一篇树链剖分题解了。 第一步&#xff1a;贪心取点 我们可以发现&#xff0c;要…

ASP.NET Core Identity自定义数据库结构和完全使用Dapper而非EntityFramework Core

前言原本本节内容是不存在的&#xff0c;出于有几个人问到了我&#xff1a;我想使用ASP.NET Core Identity&#xff0c;但是我又不想使用默认生成的数据库表&#xff0c;想自定义一套&#xff0c;我想要使用ASP. NE Core Identity又不想使用EntityFramework Core。真难伺候&…

Educational Codeforces Round 17 E. Radio stations cdq分治 + 树状数组

传送门 文章目录题意思路&#xff1a;题意 有nnn个电台&#xff0c;对于每个电台iii有三个参数xi,ri,fix_i,r_i,f_ixi​,ri​,fi​&#xff0c;分别指他们的坐标、作用半径、频率。如果两个电台频率差值在kkk以内&#xff0c;并且他们的作用范围都能覆盖到彼此&#xff0c;那么…

Educational Codeforces Round 89 (Rated for Div. 2)(A, B, C, D)

Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords 思路 题意非常简单&#xff0c;就是得到最多的物品嘛&#xff0c;我们假定a,ba, ba,b中aaa是最小的一个&#xff0c;分两种情况。 如果2∗a<b2 * a < b2∗a<b&#xff0c;那么我们只需…

什么是微服务?为什么你要用微服务?

前言最近几年微服务很火&#xff0c;大家都在建设微服务&#xff0c;仿佛不谈点微服务相关的技术&#xff0c;都显得不是那么主流了。近几年见识到身边朋友的很多公司和团队都在尝试进行微服务的改变&#xff0c;但很多团队并没有实际微服务踩坑经验&#xff0c;很多团队甚至强…

P5367 【模板】康托展开

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 存个板子 // Problem: P5367 【模板】康托展开 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P5367 // Memory Limit: 64 MB // Time Limit: 1200 ms // // Powered by …

微软开源基于.NET Core的量子开发工具包 QDK

微软最近开源了量子开发工具包&#xff08;Quantum Development Kit&#xff0c;QDK&#xff09;&#xff0c;旨在使“量子计算和算法开发对开发人员来说更容易、更透明”。微软 QDK 包括 Q#编译器、量子库和量子模拟器。微软在 2017 年底的 Ignite 大会上发布了量子开发工具包…

UVA11525 Permutation 逆康托展开

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 逆康托展开板子 // Problem: UVA11525 Permutation // Contest: Luogu // URL: https://www.luogu.com.cn/problem/UVA11525 // Memory Limit: 0 MB // Time Limit: 3000 ms // // Power…