为SpringBoot项目配置Docker maven插件

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

或者直接可视化操作,依次执行packagedocker: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中的密码也可以不加密的

评论