SpringBoot项目相比传统项目的部署方式,少了Tomcat的安装,使得我们部署项目时Tomcat是透明的,开发者只需:
① 在当前项目执行 mvn clean package
② 然后将生成 jar包拷贝到服务器的工作目录
③ 挑一个未被使用的端口,执行 setsid java -jar app.jar --server.port=8081 &
④ 编辑nginx.conf,添加反向代理、绑定域名等
至少Tomcat目录的复制工作已经省下了。
但是我们仔细一想,上面的步骤依旧繁琐,特别是修改nginx配置文件,一不小心漏了标点符号就会导致nginx出错,一不小心就影响了其它项目的运行。特别是当我们需要配置ssl证书时,更是麻烦。
现在,让我们用Docker来解决部署的痛点。
1、先通过IDEA的Spring Initializr新建一个SpringBoot项目:
勾选web依赖
写一个简单的控制器
package xyz.itmx.dockermaven.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by ITMX on 2018/6/3.
*/
@RestController
public class IndexController {
@GetMapping("/")
public String index(){
return "OK! Now:" + System.currentTimeMillis();
}
}
2、前往阿里云“容器镜像服务”创建一个镜像仓库或自己搭建一个(下一篇会介绍)。
创建一个用于保存本项目镜像的一个仓库,建议和项目名一致
如果不记得密码,可以在镜像管理首页修改密码:
到此,私有仓库就准备好了,我们可以点管理按钮查看仓库详情。
3、配置项目pom文件
在properties
节点下添加
<!--docker仓库地址-->
<docker.repostory>registry.cn-hangzhou.aliyuncs.com</docker.repostory>
<!--docker命名空间-->
<docker.registry.name>itmx</docker.registry.name>
在build
节点下添加
<!--项目打包后的完整文件名-->
<finalName>${project.artifactId}-${project.version}</finalName>
在plugins
节点下添加
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.14</version>
<configuration>
<!--指定服务器ID,待会会从maven的配置文件中获取该id对应的登录凭证-->
<serverId>aliyun-docker-blog-demo</serverId>
<!--指定仓库地址-->
<registryUrl>https://${docker.repostory}</registryUrl>
<!--构建镜像完成后即推送-->
<pushImage>true</pushImage>
<!--指定构建镜像的名称-->
<imageName>${docker.repostory}/${docker.registry.name}/${project.artifactId}</imageName>
<!--指定构建镜像的标签-->
<imageTags>
<imageTag>${project.version}</imageTag>
<imageTag>latest</imageTag>
</imageTags>
<!--指定一台用于构建镜像的运行了docker服务的服务器, 因为我使用的是win系统,安装了VirtualBox,未安装docker服务, 所以我使用一台虚拟机帮助我完成构建, 如果你的系统中运行了docker, win下你可以使用http://127.0.0.1:2375, linux下你可以使用unix:///var/run/docker.sock, 如果你也想使用一台虚拟机,可以在安装完成docker后,搜索关键字:docker开启远程访问 -->
<dockerHost>http://192.168.1.253:2375</dockerHost>
<!--指定构建镜像时使用的基础docker镜像, 参考Dockerfile的 FROM 参数-->
<baseImage>daocloud.io/library/java:openjdk-8u40</baseImage>
<!--指定镜像运行时执行的命令, 参考Dockerfile的 ENTRYPOINT 参数-->
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
<!--指定镜像暴露的端口, 注意此处只是声明了改镜像会暴露什么端口, 运行时仍然需要指定一个主机端口映射到该端口方可访问, 参考Dockerfile的 EXPOSE 参数-->
<exposes>
<expose>8080</expose>
</exposes>
<!--指定需要添加到容器内的资源, 参考Dockerfile的 ADD 参数-->
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
<!-- 运行命令 mvn clean package docker:build 打包并生成docker镜像 -->
</plugin>
4、配置maven的setting.xml文件,添加访问仓库的密码
首先查看当前ide下maven使用的配置文件的位置
第一步,生成maven的主密码,如果有可以省略
mvn --encrypt-master-password myMasterPassword
将主密码添加到 settings.xml
同目录的 settings-security.xml
配置文件中,不存在可手动创建
<?xml version="1.0" encoding="UTF-8"?>
<settingsSecurity>
<master>{FMTO39zA+IkHU90r/t9pX5oAn9g8ae/LKj3exqVhUSZVLwk*************}</master>
</settingsSecurity>
第二步,使用主密码加密我们的登录密码,得到加密后的密码
mvn --encrypt-password mypassword
将生成的密码添加到settings.xml
文件的servers
节点下
<server>
<id>aliyun-docker-blog-demo</id>
<!-- 登录registry的用户名是您的阿里云账号全名,密码是您开通服务时设置的密码。 -->
<username>itmx@foxmail.com</username>
<password>{UUP5LaqdzU0Hwajbdj2NKCRYOxQZJI7y**********}</password>
<configuration>
<email>itmx@foxmail.com</email>
</configuration>
</server>
保存,关闭,大功告成
5、打包、推送
mvn clean package docker:build
或者直接可视化操作,依次执行package
、docker:build
命令
构建成功的日志,出现了 Successfully built xxxxxx 即为构建成功
推送成功的日志,出现了xxxxxxxxxxxx: Pushed 即为推送完成
如果失败了,请参考:文末常见错误
项目构建时会在target/docker下生成临时文件
jar即当前项目打包后的产物,是本项目的可执行文件。jar包和dockerfile会一起被post到dockerHost填写的地址中进行构建。
Dockerfile的内容如下,与我们在plugin中配置的一致
FROM daocloud.io/library/java:openjdk-8u40
ADD /docker-maven-demo-0.0.1-SNAPSHOT.jar
// EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/docker-maven-demo-0.0.1-SNAPSHOT.jar"]
如果登录你用于构建镜像的虚拟机,执行docker images
命令可以查看到成功构建的镜像
在这台机子上你是可以直接docker run的,但是我们要在远程的服务器上运行,所以我们要连接远程的服务器把这个镜像从仓库拉下来。
6、部署
连接上远程服务器,执行以下操作
#首先登录
docker docker login --username=itmx@foxmail.com registry.cn-hangzhou.aliyuncs.com
#一句话跑起来
docker run -P -d registry.cn-hangzhou.aliyuncs.com/itmx/docker-maven-demo
#查看实例情况
docker ps -a
可以看点镜像成功地被拉下来并运行成功,docker
监听了主机的0.0.0.0:32771
端口,并映射到了容器内的8080
端口,也就是说此时我们访问主机的32771
端口即可访问到我们的项目了
可以看到我们通过curl
命令可以成功访问我们创建的index接口。但是着仅限于本机访问,一般情况下云主机的安全组会默认只开放web端口(80、443)和ssh端口(22),并且项目的32771端口也是docker在运行时随机选了一个未被占用的,在生产环境下一般会指定端口运行实例,或者使用nginx-proxy或同类产品
※ 指定运行时映射的端口端口,注意-p是小写
docker run -p 8081:8080 -d registry.cn-hangzhou.aliyuncs.com/itmx/docker-maven-demo
※ 使用 nginx-proxy 方案 (推荐)
注意替换域名
docker run -e VIRTUAL_HOST=dmd.itmx.xyz -e HTTPS_METHOD=nohttps -d registry.cn-hangzhou.aliyuncs.com/itmx/docker-maven-demo
如果没有安装nginx-proxy
,参考:
DaoCloud镜像市场(中文文档)
作者原文文档
到此,你可以打开浏览器输入你的域名愉快地欣赏你的作品了。
7、使用编排文件
创建工作目录,创建docker-compose.yml
文件
app:
image: registry.cn-hangzhou.aliyuncs.com/itmx/docker-maven-demo:0.0.1-SNAPSHOT
expose:
- "8080"
environment:
- VIRTUAL_HOST=dmd.itmx.xyz
- HTTPS_METHOD=nohttps
restart: always
docker-compose up -d
世界从未如此简洁
8、温故而知新
来总结一下我们的步骤:
A、新部署项目步骤
=>在阿里云创建一个镜像仓库
=>配置pom文件
=>mvn clean package docker:build
=>登录服务器,创建编排文件docker-compose.yml
=>docker-compose up -d
B、项目更新步骤
=>mvn clean package docker:build
=>登录服务器,修改编排文件镜像版本
=>docker-compose up -d
C、项目集群
=>登录服务器进入工作目录
=>docker-compose scale app=20
即可开启二十份实例,没有其它操作了
D、项目签移到新服务器
=>复制项目文件夹到新服务器
=>docker login --username=itmx@foxmail.com registry.cn-hangzhou.aliyuncs.com
=>docker-compose up -d
=>修改DNS域名解析。没有更多操作了
一旦你使用docker,很多配置其实在各项目中都是通用的,直接拷贝过去就可以了,也就改改项目名。
9、常见问题
Failed to execute goal com.spotify:docker-maven-plugin:0.4.14:build (default-cli) on project docker-maven-demo: Exception caught: java.util.concurrent.ExecutionException: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: org.apache.http.conn.HttpHostConnectException: Connect to 192.168.1.254:2375 [/192.168.1.254] failed: Connection refused: connect
这种问题一般是dockerHost地址错误或者dockerHost中填写的主机没有开启docker远程管理端口,或是防火墙导致,从这个方向入手检查即可。
Failed to execute goal com.spotify:docker-maven-plugin:0.4.14:push (default-cli) on project docker-maven-demo: Exception caught: org.sonatype.plexus.components.cipher.PlexusCipherException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
这种问题一般是密码错误导致,检查setting.xml
中配置的密码或重新生成密码。
[WARNING] Failed to push registry.cn-hangzhou.aliyuncs.com/itmx/docker-maven-demo, retrying in 10 seconds (1/5).
这种问题有比较多种情况,解决需要使用排除法。
①可能是镜像仓库登录用户名或密码错误
在虚拟机上使用docker login --username=阿里云登录账号 registry.cn-hangzhou.aliyuncs.com
登录私服,看能否出现Login Succeeded
,不能出现则登录阿里云修改密码,然后重试该步骤、并重新生成密码,不需要重新生成主密码。如果能出现,则②
②镜像名称(即镜像地址)与在阿里云创建的镜像仓库不一致
在你构建镜像的虚拟机中运行docker images
检查镜像名称(REPOSITORY)是否与阿里云控制台中的镜像仓库一致。如果不一致,修改pom文件即可,无需重新配置密码
③如果上面两步都能通过,重新配置setting.xml
中的密码吧
maven中的密码也可以不加密的