纯手工无缝升级JavaWeb微服务程序
一起想写一篇这样的文章,但是通过其他的工具也可以实现,比如说Kubephere,或者rancher都可以帮助我们无缝升级程序。
比如说我们通过kubesphre里的各种升级方式,灰度升级,蓝绿部署,流量镜像之类的。通过控制流量的方式来控制访问。
当新的程序跑起来了,才按特定的比例放流量过去。
但是把这些东西装上,你的服务器配置不少呀。
我只把基础的装上,8个g用掉了,如果加上DevOps的话基本上没有32G的内存不够用的。
当我看到别人的截图128G的内存,馋死了,哈哈。
那么阳光沙滩跑在8G的内存上是如何节省的呢?
当然是全手动的,而DevOps是半自动的。
构建使用虚拟机构建,构建完了就关掉,而不是在线的服务器构建。
那么我们纯手工部署的话,如何去实现呢?
环境
docker,maven,git,镜像仓库
git用于代码管理,maven用于打包,docker用于跑容器
git仓库可以使用腾讯云的工蜂,或者github都可以,或者其他也行。
前提条件
微服务,有服务注册中心
理论就是新旧服务都注册到服务注册中心,调用的时候不需要知道ip和端口号,只通过名称就可以调用了。
所以多个名字一样的程序,注册到服务注册中心,等到新的程序上线完成了,再把旧的程序下线。
代码管理
在代码管理方面,除了基础代码以外,我们还包括Dockerfile,还有build.sh构建脚本
build.sh在最外层目录,Dockerfile在各个模块上。
类似于这样子,通过git把内容管理起来。
Dockerfile
FROM adoptopenjdk/openjdk8-openj9:alpine-slim
LABEL maintainer=sunofbeach.net
ENV PARAMS="--spring.profiles.active=prod"
ADD target/*.jar /app.jar
ENTRYPOINT ["/bin/sh","-c","java -Dfile.encoding=utf8 -jar app.jar ${PARAMS}"]
修改环境为生产环境,因为代码会根据这个环境来拉取配置文件,详情同学们可以去学习一下摸鱼君相关的课程,这些知识都在里面有的。
然后拷贝编译好的jar包,打包到容器里。
有了这个Docker我们的build.sh脚本里就可以去打包镜像了。
build.sh
以构建用户中心为例子,如果有更多的模块,我们照着添加既可,脚本嘛,可以任意修改。
#!/bin/bash
isUcenterCompile=1
sob_ucenter_version=v1
# 输出版本号
var_sob_ucenter=sob-ucenter:$sob_ucenter_version
echo $var_sob_ucenter
# 打包内容
mvn clean package -Dmaven.test.skip=true
# Docker构建镜像
# 构建SobUcenterService镜像 #
if [ $isUcenterCompile == 1 ];then
docker build -t $var_sob_ucenter -f SobUcenterService/Dockerfile ./SobUcenterService/
fi
###################
# 显示当前的镜像列表
docker images
# 打标签
if [ $isUcenterCompile == 1 ];then
docker tag $var_sob_ucenter $REGISTRY/sob/sob-ucenter:$sob_ucenter_version
fi
# 显示当前的镜像列表
docker images
# 登录镜像仓库
REGISTRY="仓库地址"
REGISTRY_PASSWD='密码'
echo $REGISTRY_PASSWD | docker login $REGISTRY -u "账号" --password-stdin
# 推送仓库
if [ $isUcenterCompile == 1 ];then
docker push $REGISTRY/sob/sob-ucenter:$sob_ucenter_version
fi
# 删除仓库
if [ $isUcenterCompile == 1 ];then
docker rmi -f $REGISTRY/sob/sob-ucenter:$sob_ucenter_version
docker rmi -f $var_sob_ucenter
fi
# 显示当前的镜像列表
docker images
脚本内容看我写的注释既可,同学们可以去使用腾讯云的镜像仓库,这个比阿里的要多,哈哈。
主要步骤很简单:
- maven打包程序为jar包
- 根据前面写的Dockerfile构建镜像,名称:版本号
- 给镜像打标签
- 登录远程镜像仓库
- 推送镜像到远程仓库上
- 删除仓库记录
升级步骤
提交代码
写完代码以后,提交代码
修改版本号和控制标记
在我们的build.sh脚本里,我们有一个isXxxxCompile,如果有多个模块,我们可以通过这个标记控制哪些模块是需要编译的。
修改版本号,每次编译前都要有一个提交是修改版本号的。修改完以后,通过git,把代码提交到代码仓库上。
构建打包镜像
当我们把代码提交到远程仓库上以后,我们可以创建一个虚拟机用于专门做构建和打包的。
环境需要有git,maven(在超级管理员帐户下安装)
切换到超级管理员
sudo su
-
通过git把代码拉取下来
-
然后修改build.sh为可执行的权限
chmod +x build.sh
-
调用构建脚本
./build.sh
走完上面这些步骤,完成了:
- 代码编译,打包成jar包
- 把jar包打包成docker镜像
- 把镜像推送到远程仓库
程序 上线
服务器上要有docker环境,docker-compose。
-
首先要在服务器上登录镜像仓库
-
拉取对应版本的镜像
-
编写docker-compose.yml
version: '3.1' services: icgateway: image: 仓库地址:版本号 container_name: 程序名称-版本号 restart: always deploy: resources: limits: memory: 600M network_mode: host
从这个文件可以看出,我没有暴露版本号,并且网络模式是host。其实就是为了后面的无缝升级做准备的。
-
程序启动
docker-compose up # 守护式启动 docker-compose up -d
不停机更新
由前面的原理,我们是服务间的调用是通过注册中心进行调用的,新旧程序的名字一样,等新的程序上来就可以调用了。
要解决的问题,端口冲突,如果我们的程序硬编码端口号,那么只能启动一个实例。
所以我们的配置文件的port这样写:
#端口
server:
port: ${random.int[10000,19999]}
反正根据配置它会向服务注册中心注册自己上去
而服务注册中心可以通过名字进行调用的,所以端口号无所谓了,随机既可。
第一个版本程序上线
- 创建一个文件夹ucenterV1
- 根据前面程序上线的步骤完成第一个程序上线。
第二个版本的程序上线
-
把文件夹ucenterV1考本一个为文件夹ucenterV2,当然你已经把新版本的镜像打包好上传到远程仓库上了。
-
修改里面的docker-compose.yml文件
-
拉取新版本的镜像
-
直接跑起来,此时已经有两个程序在跑了,会绑定到服务注册中心的
当然我这里只有一个,因为我已经把旧的程序下线了。我用的是nacos,同学们也可以使用eureka,我个人比较喜欢用nacos。
这个时候,可以去前端看看网页呀,做一些操作,然后一会来看看新版本程序的log
docker logs 容器名称/容器ID
当你看到有请求进来的时候,可以把旧的程序生活停掉了,这个时候新的程序就上线成功了。