docker部署jar包的几种方式
- 前言
- 使用Dockerfile手动打包jar
-
- 简单打包运行
- 进化:可复用容器
- 究极进化:jdk镜像直接创建可服用容器
- 超究极进化:maven插件打包(不推荐)
- 无聊的进化:maven打包自动推送镜像到指定服务器(不推荐,研发环境随便玩)
- 关于docker容器启动后注册到nacos的ip是docker容器ip问题!
- 总结
前言
简单记录一下docker打包jar部署的几种方式,避免以后忘记,不过这种手动的方式应用应该不多!
现在微服务大多数采用集群部署方式,使用k8s或者swarm配合docker+jenkins等实现自动化部署集群及动态扩展等,后面再慢慢写相关的吧。没有服务器资源演示,懒得弄 !
使用Dockerfile手动打包jar
简单打包运行
docker安装和使用基础看这里:manjaro安装docker及基本命令(dokcer系列一)
我这里就用前几天写的SpringCloudAlibabaDemo做演示吧,需要演示工程的看这里:SpringCloudAlibaba项目搭建nacos+gateway
user模块已久打包成jar了,如下:
把jar上传到你的服务器,我这里就在本机演示,直接cp到/opt/java_app_docker目录下
在相同目录下创建Dockerfile
sudo vim Dockerfile
然后输入:
# 拉取jdk8作为基础镜像
FROM java:8
# 作者
MAINTAINER zbdemo <zbdemo@163.com>
# 添加jar到镜像并命名为user.jar
ADD user-0.0.1-SNAPSHOT.jar user.jar
# 镜像启动后暴露的端口
EXPOSE 8001
# jar运行命令,参数使用逗号隔开
ENTRYPOINT ["java","-jar","user.jar"]
然后使用docker命令打包:
docker build -t user .
user表示镜像名称
最后的.表示Dockerfile在当前目录
打包完成后使用docker images查看镜像
使用docker run命令创建并运行容器:
docker run -d --name user -p 8001:8001 user
命令解释如下:
命令 | 功能 |
---|---|
docker run | 创建并启动容器 |
–name | 指定一个容器名称 |
-d | 后台运行容器,并返回容器ID |
-p | 指定端口 |
user | 需要启动的镜像(名称+版本)不指定版本默认最新版本 |
: | 符号左边为宿主机,右边为容器空间 |
启动完成,查看启动日志:
docker logs -f -t user
jar日志启动成功,查看容器:
docker ps
访问一下,测试效果:
localhost:8001/hello/hello
没错,手动docker打包jar镜像并运行完成了,但是这样搞就显得有点呆,还不如直接java -jar运行呢!操作这么麻烦,每次更新还要删除容器,删除镜像重新创建,而且日志文件等重要信息也会丢失!当然如果你使用jenkins等shell自动化的工具当我没说
进化:可复用容器
首先停止并删除刚刚创建的容器和镜像
停止容器:
docker stop user
删除容器:
docker rm user
删除镜像:
docker rmi user
修改Dockerfile文件
sudo vim Dockerfile
修改后内容如下(给jar安排了一个目录,方便挂载到宿主机):
# 拉取jdk8作为基础镜像
FROM java:8
# 作者
MAINTAINER zbdemo <zbdemo@163.com>
# 添加jar到镜像并命名为user.jar
ADD user-0.0.1-SNAPSHOT.jar /app/user.jar
# 镜像启动后暴露的端口
EXPOSE 8001
# jar运行命令,参数使用逗号隔开
ENTRYPOINT ["java","-jar","/app/user.jar"]
然后在/opt/java_app_docker文件夹下面创建jar挂载目录
sudo mkdir app
把你的jar包cp一份到宿主机/opt/java_app_docker/app目录下并改名为user.jar 这里一定要在app目录下存放你的jar,不然容器启动会失败,找不到jar
打包镜像-创建并运行容器
打包镜像:
docker build -t user .
创建并运行容器:
docker run -d --name user -p 8001:8001 -v /opt/java_app_docker/app:/app user
命令解释如下:
命令 | 功能 |
---|---|
docker run | 创建并启动容器 |
–name | 指定一个容器名称 |
-d | 后台运行容器,并返回容器ID |
-p | 指定端口 |
user | 需要启动的镜像(名称+版本)不指定版本默认最新版本 |
-v | 挂载目录到宿主机 |
: | 符号左边为宿主机,右边为容器空间 |
这样的方式启动完成之后,更新服务时只需要更换宿主机/opt/java_app_docker/app目录下的jar包,然后重启容器即可实现更新,省略了每次更新删除打包创建等过程
究极进化:jdk镜像直接创建可服用容器
上面的方式在单应用情况下是可行的,但是如果我是微服务架构呢?比如现在我要部署我的gateway网关服务,是不是还要重新走一遍流程?很呆!!!!!
首先停止并删除刚刚创建的容器和镜像
停止容器:
docker stop user
删除容器:
docker rm user
删除镜像:
docker rmi user
查看jdk版本
docker images
我这里是openjdk8
创建并运行容器(直接基于jdk镜像创建容器):
docker run -d --name user -p 8001:8001 -v /opt/java_app_docker/app:/app java:8 /usr/bin/java -jar /app/user.jar
命令解释如下:
命令 | 功能 |
---|---|
docker run | 创建并启动容器 |
–name | 指定一个容器名称 |
-d | 后台运行容器,并返回容器ID |
-p | 指定端口 |
-v | 挂载目录到宿主机 |
java:8 | 需要启动的镜像(名称+版本)不指定版本默认最新版本 |
/usr/bin/java -jar /app/user.jar | jar启动命令及jar所在位置,因为创建的容器挂在了宿主机/opt/java_app_docker/app目录,所以里面映射了我们上面放进去的user.jar |
: | 符号左边为宿主机,右边为容器空间 |
这样的方式省略了创建Dockerfile并把jar打包成镜像的操作,无论多少个服务,只要有jdk镜像,一条命令搞定!比如现在我需要增加gateway服务,那就把gateway.jar放在任意目录下,直接执行:
docker run -d --name user -p ${任意外部端口}😒{任意容器端口} -v ${你的gateway.jar存放目录}:/${任意容器内目录名称} java:8 /usr/bin/java -jar /${任意容器内目录名称}/gateway.jar
这种方式也是直接替换挂载目录下jar,然后docker restart 容器ID or 名称 就行
超究极进化:maven插件打包(不推荐)
为什么不推荐呢?首先是maven插件直接打包docker镜像的方式污染工程,反正就很奇怪的感觉,其次你的项目是要发布生产环境的,直接打包镜像给运维,太卷了吧?
所以综上所属,我就简单介绍下
pom添加docker打包方式
<!--docker 镜像插件-->
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.2</version>
<configuration>
<imageName>${project.artifactId}</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
创建Dockerfile文件
内容如下:
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zbdemo
# 将jar包添加到容器中并更名为app.jar
ADD gateway-0.0.1-SNAPSHOT.jar gateway.jar
EXPOSE 8000
ENTRYPOINT ["java","-jar","gateway.jar"]
命令方式
打包:
mvn package -Dmaven.test.skip=true docker:build
本机docker
保存镜像到本地docker:
docker save -o /gateway.jar gateway
查看镜像:
docker images
创建并运行容器:
docker run --name gateway -p 8000:8000 -d gateway
服务器docker
或者上传到服务器:
scp /gateway.jar root@ip:/opt/app
加载镜像:
docker load </opt/app/gateway.jar
查看镜像:
docker images
创建并运行容器:
docker run --name gateway -p 8000:8000 -d gateway.tar
或者这样
打包
推送
无聊的进化:maven打包自动推送镜像到指定服务器(不推荐,研发环境随便玩)
准备工作
开启服务器的docker远程访问权限:自行百度?反正我不想这样玩
pom修改如下:
<!--docker 镜像插件-->
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.2</version>
<configuration>
<imageName>${project.artifactId}</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<!-- docker容器地址 -->
<dockerHost>http://192.168.101.1:2375</dockerHost>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
</project>
打包:
mvn package -Dmaven.test.skip=true docker:build
或者
完成!!!!!!!!!!!!!!!!!!!!!!去服务器docker images看一下应该有了
关于docker容器启动后注册到nacos的ip是docker容器ip问题!
1.可以在docker run的时候加 –network=host 参数解决(主机网络模式),这个时候我们无需-p 80:80指定服务端口运行,因为–network=host模式会使用服务本身启用的端口。
2.容器创建启动时动态指定ip和端口:-Dspring.cloud.nacos.discovery.ip=xx -Dspring.cloud.nacos.discovery.port=xxx
或者在yaml配置文件配置:
spring:
cloud:
nacos:
discovery:
ip: xx
port: xx
总结
后面两种maven插件打包镜像的方式都不推荐,反正不要太卷了,哈哈!虽然在dev或者test环境用起来可能真的爽,但是你确定要手动吗?后续应该会写jenkins+k8s或者jenkins+swarm集群部署,你会发现你所谓的爽不过如此!!说这么多干啥呢,反正主要是写给自己看的
差点忘了,感谢大佬,参考地址:地址1,地址2