目录

记录第一次开源经历

  好久没写博客了,这半个月确实有点浪,剧本杀阿瓦隆喝酒唱歌聚餐样样没落下,还“努力”上了个王者,简直读了个假研究生。

  不过这半个月里,我也完成了一个开源任务,给hmily-admin 增加docker打包部署方式,提交了pr并合并了。老早就在师兄的安利下,想要接触开源了,这次算是第一次真正参与了一个开源项目,虽然这个只是个小项目(属于hmily 的展示平台),但也收获了挺多东西。

/开源/first.png

一、需求分析

hmily-admin原本是一个单体项目,部署方式是将项目打包成一个zip包,再通过shell脚本的方式来启动。这种方式比起上传jar包,再通过命令行的方式运行,确实是方便了一点。

我的任务是,仿照apache/shenyu ,给hmily-admin增加docker打包部署方式以及完善相应文档。

shenyu的docker部署只需要make build-all-image一条命令,就能将项目打包成镜像了,接下来就是通过docker run传入配置文件参数绑定数据卷的方式,跑起服务。shenyu是通过Makefile + 打包模块来实现的,我仿照shenyu实现了hmily-admin的docker部署。

二、操作步骤

1.更改项目结构

  由于需要新建打包模块,需要将原来的单体项目修改为多模块项目,这个可以去参考一下微服务项目的构建方法。

2.新建hmily-admin-dist模块

  基本照抄shenyu的打包模块,改的地方只有路径、项目名、主启动类名等。我认为这个模块最重要的就是maven-assembly-plugin插件以及binary.xml文件,至于具体是怎么生成目标文件的,我准备之后研究研究,可以期待一下我的后续博客。

3.编写Makefile与Dockerfile

  • Makefile

  Makefile主要来完成两件事情:maven打包项目、docker生成镜像。Makefile文件如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
HMILY_HOME :=  "."
REGISTRY ?= "docker.io"
REPOSITORY_PREF ?= "dromara/hmily"
ADMIN_REPOSITORY ?= "${REPOSITORY_PREF}-admin"
TAG ?= latest
VERSION ?= "1.0.2"
COMMIT_ID := $(shell git rev-parse HEAD)


default: build-hmily-admin-image
# docker生成镜像
build-hmily-admin-image: build-hmily-admin
	@echo "build-hmily-admin-image"
	@docker buildx build --load \
    		-t ${REGISTRY}/${ADMIN_REPOSITORY}:${TAG} \
    		-f ${HMILY_HOME}/hmily-admin-dist/docker/Dockerfile \
    		--build-arg APP_NAME=hmily-admin-${VERSION}-admin-bin \
    		--label "commit.id=${COMMIT_ID}" \
    		${HMILY_HOME}/hmily-admin-dist

# maven打包项目
build-hmily-admin:
	@echo "build hmily admin"
	@mvn -am \
		-pl hmily-admin-dist \
		-Dmaven.javadoc.skip=true \
		-Drat.skip=true \
		-Djacoco.skip=true \
		-DskipTests \
		-Prelease \
		clean package

  maven打包项目:指定了打包的模块是hmily-admin-dist-Prelease用来指定pom文件中的release方式,用于生成hmily-admin-1.0.2-admin-bin.tar.gz

  docker生成镜像:指定Dockerfile的位置,通过Dockerfile生成镜像。

  • Dockerfile

  将生成hmily-admin-1.0.2-admin-bin.tar.gzadd到镜像中,配置entrypoint.sh,使得用户能通过命令行传入需要配置的信息,如数据库用户密码等。现在的entrypoint.sh还是有改进空间的,因为用户能传入的内容还不足以覆盖全部的配置信息。

4.运行测试

  如何运行可参考README.md 。运行过程中也遇到了几个问题:

  • self4j-log4j12依赖冲突问题。通过mvn dependency:tree命令查找哪个依赖中还有self4j-log4j12包,剔除就好。mvn dependency:tree命令很重要,依赖冲突时能排查!
  • -v数据卷绑定方式传入配置文件,控制台日志不输出问题。后来发现日志输出在容器的/opt/log目录下,就建立一个日志的数据卷,就能方便查看日志文件了。
  • 用Java11编译运行项目时报错。一开始以为是项目pom文件里定义的Java版本是java8而导致的错误,修改了pom里的版本后还是有错。后来网上找了找,发现是lombok版本太低导致的。 看来pom里定义的Java版本并没什么用。

三、遇到的问题与收获

1. maven相关

maven命令

  以前操作maven都是靠idea的图形界面,点一点就好,这次算是熟悉maven的常用命令了。其实每次点击idea里的打包命令,控制台第一行会输出打包命令。

  pom文件里,可以通过<profiles>标签定义多套配置,maven打包时通过mvn package -P 配置名指定配置即可。

maven wrapper

  使用start.spring.io生成项目,会发现里面有mvnwmvnw.cmd两个文件。这两个文件其实就是用于使用maven wrapper的。shenyu使用的打包命令就是mvnw,而不是mvn

  感觉我们生成项目时,会习惯性的删掉mvnwmvnw.cmd等文件,hmily-admin就删掉了。因此一开始,Makefile里我用mvnw命令去打包,就报错了,后面就改用了mvn

  maven wrapper属于项目级别的maven,在主机里没安装maven或者maven版本与项目所需不一致时,就会自动下载一个项目级别的maven,供项目使用。它的好处就是,打包项目时,不用在意主机有没有安装maven了,肯定能帮你打包好坏处就是,没有配置国内镜像,下载jar包的速度贼慢。而且虽然官网说的是在找不到maven的时候,它会自动下载一个,但我用了几个服务器来打包shenyu,发现本机的maven都没有生效,用的都是maven wrapper,所以打包速度贼慢。因此我还是会选择用mvn

2. 项目打包插件

  以前写项目,一直注重的是开发方面,对运维部署就没放在心上,所以对打包插件也没多注意。这次看了hmily-admin里的打包插件,比如maven-assembly-plugindocker-maven-pluginmaven-checkstyle-plugin等,是真的牛逼,直接把程序连同脚本一起,打包成一个压缩包的形式,配合Dockerfile打包成镜像,方便部署。我准备之后在项目里试一试这些插件,成功部署后再来细讲。

3. 脚本

  看了一些开源项目的部署方式,基本都会涉及到脚本,一键启动是真方便。但是shell脚本是真难看懂,我现在也只能照着被人的脚本改改,慢慢摸索吧。

4. 依赖冲突问题

  当初写毕设的时候,就遇到过依赖冲突,当时稀里糊涂就解决了,这次遇到了self4j-log4j12的依赖冲突,算是总结到了解决依赖冲突的方法。

  • 首先,根据报错信息,找到冲突的依赖包

  • 项目根目录(pom所在目录)执行mvn dependency:tree命令,会输出项目用到的依赖包以及依赖包下含有的依赖包。hmily-admin里,我发现zookeeper包中也含有self4j-log4j12

  • 冲突的依赖包下剔除重复的包。本项目中,在zookeeper包里,使用<exclusions>进行剔除self4j。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.14</version>
        <exclusions>
            <exclusion>
                <artifactId>slf4j-log4j12</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency
    

5.数据卷

docker run -v 宿主机目录:容器目录,执行命令时,宿主机目录里的东西会覆盖掉容器目录里的东西。容器执行过程中,容器目录里生成的文件或者修改过的文件,会实时同步到宿主机目录中。以前理解错了,现在的理解绝对是对的🤡。

6.写开源项目时,使用git的技巧

可参考:

总之就是,对代码的修改在分支中进行,一切都是为了解决或者防止冲突。

6. 沟通的重要性

 一开始我对完成这个开源项目都没什么信心,像那些脚本、打包模块什么的,见啊没见过。开始修改项目时,报了一堆错,比如上面说过的mvnw。。一筹莫展时,多问问身边的大佬,不要怕别人说你菜狗🐶。

 很多问题都是眼界不够导致的,没见过就无从下手,有大佬指点一二,就会发现很多问题迎刃而解了。

 还有就是得仔细听需求,不懂的就及时问。一开始以为遇到问题网上查就行,结果刚开始做的时候都觉得无从下手。后面再次询问师兄,才大概懂了流程。。和京东的项目负责人聊也是,一开始没理解什么叫“新建父模块”,导致了两三天的摆烂,后来去询问了一下他,问题马上解决了。。


后面要学的东西还很多,下一步,研究研究插件,自己实现一遍打包模块。向k8s进发。