需求
微服务的架构下,服务的数量多起来之后,一定会面对到开发联调的问题,不同的人维护不同的服务,互相直接有调用依赖,如果同时在做修改工作,互相之间就会有冲突和影响,很多时候会非常影响开发和调试的效率。
由于我们是使用kuberneters来部署服务的,所以很自然的想到一个解决的办法就是利用kuberneters的命名空间的特性,在需要的时候,基于稳定版本快速的复制一份全新的部署出来,开发可以独立享用这个环境,不会有任何的冲突。实现的方式非常简单:
解决方案
- 在git上维护一个单独的服务部署文件的仓库,里面是每个服务的k8s部署文件,大概是这样子的:
server1.yaml
server2.yaml
server3.yaml
- 在jenkins上建一个job,执行这个job就可以一键复制出一份全新的部署环境,我们使用的是pipeline的方式来配置的job:
#!groovy
def nodeName = env.node
node(nodeName) {
def branch = env.branch
def profileName = env.profileName
println("build branch: ${branch}")
//拉取部署配置文件
stage('checkout') {
def scmVars = checkout([$class: 'GitSCM', branches: [[name: branch]],
doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [],
userRemoteConfigs: [[credentialsId: '****', url: 'http://****/base-deploy-config.git']]])
String commitHash = scmVars.GIT_COMMIT
println("checkout branch: ${commitHash}")
}
//清理k8s环境
stage('clean') {
sh "/usr/bin/kubectl delete namespace " + profileName
sh "/usr/bin/kubectl create namespace " + profileName
//这里是为了在新的k8s命名空间中创建一个docker仓库的访问令牌
sh "/usr/bin/kubectl apply -n " + profileName + " -f secret.yaml"
}
//部署服务
stage('deploy') {
fileList = [
"server1": "1.48.0-20200409",
"server2": "1.48.0-20200408",
"server3": "1.46.0-20200323",
...
]
//遍历并部署所有的服务到新的命名空间
fileList.each{fileName, buildTag ->
println("apply ${fileName}")
if(fileName == "ingress"){
String replaceStr = "s/NAMESPACE/${profileName}/g"
def sed = 'sed -i "' + replaceStr + '" ' + fileName + '.yaml'
sh sed
}else{
String replaceStr = "s/BUILD_ID/${buildTag}/g"
def sed = 'sed -i "' + replaceStr + '" ' + fileName + '.yaml'
sh sed
}
sh "/usr/bin/kubectl apply -n " + profileName + " -f " + fileName + '.yaml'
}
}
}
潜在的问题
- 复制新的环境是需要硬件资源的,我们目前服务数量还不是很多,还不到20个容器,开发团队规模也不足20人,需要的硬件资源还不是很多,这个方案还足以支持。如果是规模更大的团队和系统,就需要考虑做进一步的优化,比如阿里的这个方式: alibaba.github.io/virtual-env…
- k8s的service配置不要有nodePort方式的,在同一个集群中,nodePort是不能复用的,有这个用法的就很麻烦。
- 其他的基础设施,比如数据库,redis这些,我们目前依然是共享的,只能说可以满足现阶段的需求,后期如果这些也有很强的隔离需求,这些基础设施也可以部署到k8s集群中,方便重新部署。