在持续交付的过程中,我喜欢将服务容器化,包括后端,前端都是。
当然移动端肯定就不在能容器化之列了,这个是额外要考虑的。
本篇,继续从零到一,构建你的持续交付流程,这是第四篇,本系列其它文章是:
提醒
持续交付的形态应该与最终项目或产品的部署形态二进制保持一致。如果你最终在生产上的部署形态是rpm包,那持续交付也应该是rpm包。不保持一致的持续交付,则失去了它本来应有的价值。
我更喜欢用Docker将服务容器化,我觉得这样在服务管理上比较方便。
明确点说就是:
而且,对持续集成来说,管理docker服务非常方便,重启,停止或更新
#启动XX服务
docker start XXService
#关闭XX服务
docker stop XXService
如上,服务的管理都是比较方便的。
当然,这并不意味着只能用Docker,如果你是Jar或War,或RPM也好,DEB也好,Systemctl服务也行,都可以。但是切记,持续交付的二进制产物必须与实际生产保持一致,否则价值就大大降低了。
接下来,我将分别简单就三种模式进行阐述:
我需要再解释下,这个系列并不是技术教程,不会就涉及到的Docker知识一步一步的解释与说明。后续我会做Docker的专题系列。本系列的目标着重在让大家知道一个持续交付是如何构建起来的。这个过程中涉及到的技术仅做简单解释。
为了便于演示,整个过程,我会用我的myddd starter生成一个后端项目及一个前端项目来配合说明。访问https://starter.myddd.org 来快速生成项目。
如图所示,请使用myddd starter来快速生成项目,以配合后续的操作。
请在myddd starter中,随便生成一个myddd-java的项目就好。生成的项目是基于gradle的,带了一些示例代码,也带了单元测试。非常方便我们接下来的演示。
之所以使用myddd-java,是因为这是Java+Spring Boot,大家熟悉,而且默认数据库是H2内存数据库,方便我们操作。而myddd-vertx则是kotlin+vertx结合,大多数人可能并不熟悉。
#如果需要本地编译,请安装gradle,我当前用的是gradle 7.2
gradle build
尝试gradle build,你可以成功的构建它。
生成与编译项目
比如,我生成了一个名称为test-backend的myddd-java项目,构建完后,可以在test-backend-bootstrap的build的libs目录下,找到最终运行的Jar。
你可以尝试在本机,使用java来运行
java -jar test-backend-bootstrap-1.0.0-SNAPSHOT.jar
这是一个基于Spring Boot的最终的fat jar。只要你的JDK不低于11,它就能正常运行。
当然,我们的目的不是这样,我们是希望以docker的容器化的模式来管理这个服务。
构建镜像
在项目的根目录下,新建名称为Dockerfile的文件。
# syntax=docker/dockerfile:1
#构建镜像
FROM openjdk:11.0.12-jre-slim
WORKDIR /app
COPY ./test-backend-bootstrap/build/libs/test-backend-bootstrap-1.0.0-SNAPSHOT.jar .
CMD ["java","-jar","/app/test-backend-bootstrap-1.0.0-SNAPSHOT.jar"]
在这里中,我仅仅简单解释下
在项目当前目录下,执行以下构建镜像的命令
docker build -t test-backend:1 .
我们构建一个名为"test-backend"的镜像,tag为1。
第一次可能会下载一些基础镜像,时间会有点久。
然后,运行docker images来查看是否在本地生成成功。
REPOSITORY TAG IMAGE ID CREATED SIZE
test-backend 1 9455edc604ee 4 minutes ago 274MB
如上所示,出现这么个东西,表示你的镜像就生成成功啦 。
运行镜像
docker run --name=test-backend -d -p 8080:8080 test-backend:1
#如果你想查看日志
docker logs -f test-backend
如无意外,你能看到服务启动成功了。
是不是挺简单的?
好,我们再来搞个前端的项目。
我们要学会举一反三,前端也好,后端也好,构建docker镜像服务的原理是一模一样的。
生成前端项目
好,再次访问https://starter.myddd.org, 生成一个myddd-web项目,这是一个基于typescript+react的项目。
举例说明,你生成了一个名称为test-front的项目。
生成完成后,执行以下命令
# 编译项目
npm install
# 以开发的模式运行它
npm run serve
访问https://127.0.0.1:3000, 你能见到这样的一个默认首页
如果需要编译生成包
npm run buildProd
成功后,dist目录下的文件就是最终的静态文件了,一般情况下,我们会把这上放到nginx上去。
制作镜像
同样,我们的目的还是要把这个也做成容器服务。
在项目目录下,创建一个Dockerfile的文件
# syntax=docker/dockerfile:1
FROM nginx:alpine
COPY ./dist /usr/share/nginx/html
好吧,这个就更简单了。
下一步,执行以下命令
docker build -t test-front:1 .
同理,我们用docker images来查看
REPOSITORY TAG IMAGE ID CREATED SIZE
test-front 1 813afab9fac1 33 seconds ago 23.5MB
test-backend 1 9455edc604ee 29 minutes ago 274MB
运行镜像
docker run --name=test-front -d -p 80:80 test-front:1
#如果要查看日志
docker logs -f test-front
同理后,访问https://127.0.0.1, 你可以见到刚刚在开发模式下一样的页面了。
是不是挺简单的?
我们已经把后端,前端都做成了镜像服务,并且都能基于docker来方便的管理这些服务。
但是通常一个项目或产品,有前端,后端,数据库,可能还有缓存redis等,如果一个个来管理,非常麻烦。
在单台机器上,我们可以利用docker compose来集中式的管理服务,这个就非常方便了。
docker compose非常适合开发或测试环境,在单台机器上进行部署与管理服务。(如果是生产,则不适合了,生产你需要考虑docker swam或更复杂的k8s等技术了)
创建docker compse文件
先在合适的地方,创建一个test-compose目录(名称无所谓)
在test-compose目录下,新建docker-compose.yml文件。
文件内容如下:
version: "3.9"
services:
test-backend:
image: test-backend:1
container_name: test-backend
ports:
- "8080:8080"
test-front:
image: test-front:1
container_name: test-front
ports:
- "80:80"
depends_on:
- test-backend
简单解释下:
具体请参阅docker compose文档。
服务集的的启动与停止
基于docker compose来管理多个服务,它们的启动与停止就非常方便
#启动服务,-d表示运行在后台
docker-compose up -d
#停止服务
docker-compose stop
就是这么简单。
docker compose非常适合你的开发环境,或者你的测试环境。
提醒
在实际中,测试环境尽量应该是生产环境的mini版本,包括部署方式。因为生产大多不可能是docker compose来部署的,所以测试环境最好也不要使用docker compose。
如上所说,将我们的服务,包括后端+前端用docker来管理,其实原理上非常简单,并不复杂。
虽然这个示例极其简单,但复杂的东西无非是在简单的东西之上再添加。只要你能理解这个过程,后面添加新的复杂的东西,就更轻易能理解了。
好了,我们已经学会怎么让我们的服务容器化了。
上面的过程我们都是手动在操作。这当然不是我们的目的。
上面这些过程,我们完全可以让Jenkins Pipeline来帮我们自动化的执行。这样就并不需要人工反复的执行这些东西了。
下一篇:从零到一,构建你的持续交付流程(四):使用Jenkins Pipeline,让一切自动化与流程化
本篇文章中所涉及到的所有用myddd starter生成的项目,已放在github上,你可以访问https://starter.myddd.org, 来生成这些项目,也可以使用github上现成的示例。
https://github.com/lingen/continuous_delivery_example.git
同时,这个地址我们在下一篇文章中使用Jenkins会用到
备注:myddd.org是我个人维护的基于DDD理念的全栈式领域驱动开源基础框架,官网是https://myddd.org