Maven插件之spotify的docker-maven-plugin和dockerfile-maven-plugin,docker部署

2,034 阅读8分钟

docker-maven-plugin能有效帮助我们在面对数量众多的微服务项目时,自动化构建和容器化部署,提高部署效率。

docker-maven-plugin文档

dockerfile-maven-plugin文档

禁止转载!!!禁止转载!!!禁止转载!!!

首发地址:xu.vercel.app

一、修改docker配置

修改宿主机的docker配置,让其可以远程访问


vi /lib/systemd/system/docker.service
# 在ExecStart=后添加配置 
‐H tcp://0.0.0.0:2375 ‐H unix:///var/run/docker.sock

修改后配置如下:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock

刷新配置重启服务:

# 通知docker服务做出的修改
systemctl daemon-reload
# 重启docker服务
systemctl restart docker

接下来测试一下看是否能连接到docker api

ps -ef | grep docker 
[root@localhost ~]# curl -X GET http://192.168.122.22:2375/info
{"ID":"XHRK:S4AH:7YDS:X43Y:BFCZ:XQ5N:VBIV:K6V4:SUVK:VFPM:JJYS:KZBB","Containers":7,"ContainersRunning":4,"ContainersPaused":0,"ContainersStopped":3,"Images":7,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","xfs"],["Supports d_type","true"],["Native Overlay Diff","true"],["userxattr","false"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","ipvlan","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","local","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"KernelMemoryTCP":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":true,"IPv4Forwarding":true,"BridgeNfIptables":false,"BridgeNfIp6tables":false,"Debug":false,"NFd":50,"OomKillDisable":true,"NGoroutines":55,"SystemTime":"2021-11-11T15:21:22.728142607+08:00","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","CgroupVersion":"1","NEventsListener":0,"KernelVersion":"3.10.0-957.el7.x86_64","OperatingSystem":"CentOS Linux 7 (Core)","OSVersion":"7","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":[],"AllowNondistributableArtifactsHostnames":[],"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":["https://pee6w651.mirror.aliyuncs.com/"],"Secure":true,"Official":true}},"Mirrors":["https://pee6w651.mirror.aliyuncs.com/"]},"NCPU":2,"MemTotal":2928689152,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"localhost.localdomain","Labels":[],"ExperimentalBuild":false,"ServerVersion":"20.10.7","Runtimes":{"io.containerd.runc.v2":{"path":"runc"},"io.containerd.runtime.v1.linux":{"path":"runc"},"runc":{"path":"runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"d71fcd7d8303cbf684402823e425e9dd2e99285d","Expected":"d71fcd7d8303cbf684402823e425e9dd2e99285d"},"RuncCommit":{"ID":"b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7","Expected":"b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7"},"InitCommit":{"ID":"de40ad0","Expected":"de40ad0"},"SecurityOptions":["name=seccomp,profile=default"],"Warnings":["WARNING: API is accessible on http://0.0.0.0:2375 without encryption.\n         Access to the remote API is equivalent to root access on the host. Refer\n         to the 'Docker daemon attack surface' section in the documentation for\n         more information: https://docs.docker.com/go/attack-surface/","WARNING: bridge-nf-call-iptables is disabled","WARNING: bridge-nf-call-ip6tables is disabled"]}

1.2 启动失败的问题

启动报错Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.

[root@localhost ~]# systemctl start docker
Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
[root@localhost ~]# systemctl start docker.service
Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.

[root@localhost ~]# systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: failed (Result: start-limit) since 四 2021-11-11 14:54:01 CST; 1min 14s ago
     Docs: https://docs.docker.com
  Process: 23534 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ‐H tcp://0.0.0.0:2375 ‐H unix:///var/run/docker.sock (code=exited, status=1/FAILURE)
 Main PID: 23534 (code=exited, status=1/FAILURE)

11月 11 14:54:01 localhost.localdomain systemd[1]: start request repeated too quickly for docker.service
11月 11 14:54:01 localhost.localdomain systemd[1]: Failed to start Docker Application Container Engine.
11月 11 14:54:01 localhost.localdomain systemd[1]: Unit docker.service entered failed state.
11月 11 14:54:01 localhost.localdomain systemd[1]: docker.service failed.
11月 11 14:54:13 localhost.localdomain systemd[1]: start request repeated too quickly for docker.service
11月 11 14:54:13 localhost.localdomain systemd[1]: Failed to start Docker Application Container Engine.
11月 11 14:54:13 localhost.localdomain systemd[1]: docker.service failed.
11月 11 14:54:18 localhost.localdomain systemd[1]: start request repeated too quickly for docker.service
11月 11 14:54:18 localhost.localdomain systemd[1]: Failed to start Docker Application Container Engine.
11月 11 14:54:18 localhost.localdomain systemd[1]: docker.service failed.

1.3 解决启动失败

因为修改的是/usr/lib/systemd/system/docker.service下的服务配置文件: ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

那么就应该加载该目录下的system服务systemctl start docker.service


[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl stop docker.service
Warning: Stopping docker.service, but it can still be activated by:
  docker.socket
[root@localhost ~]# ps -ef | grep docker 
root      47375  18279  0 15:13 pts/0    00:00:00 grep --color=auto docker
[root@localhost ~]# systemctl start docker.service
[root@localhost ~]# systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since 四 2021-11-11 15:13:43 CST; 37s ago
     Docs: https://docs.docker.com
 Main PID: 47559 (dockerd)
   CGroup: /system.slice/docker.service
           ├─47559 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
           ├─47751 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 6379 -container-ip 172.17.0.2 -container-port 6379
           ├─47756 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 6379 -container-ip 172.17.0.2 -container-port 6379
           ├─47783 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3306 -container-ip 172.17.0.3 -container-port 3306
           ├─47788 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 3306 -container-ip 172.17.0.3 -container-port 3306
           ├─47822 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 9000 -container-ip 172.17.0.4 -container-port 9000
           ├─47836 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 9000 -container-ip 172.17.0.4 -container-port 9000
           ├─47884 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 30443 -container-ip 172.17.0.5 -container-port 443
           ├─47893 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 30443 -container-ip 172.17.0.5 -container-port 443
           ├─47924 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 30080 -container-ip 172.17.0.5 -container-port 80
           └─47939 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 30080 -container-ip 172.17.0.5 -container-port 80

11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.097948827+08:00" level=info msg="ClientConn switching balancer to "pick_...ule=grpc
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.103540123+08:00" level=info msg="[graphdriver] using prior storage driver: overlay2"
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.109459318+08:00" level=info msg="Loading containers: start."
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.226585154+08:00" level=info msg="Default bridge (docker0) is assigned wit...address"
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.944106192+08:00" level=info msg="Loading containers: done."
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.973773238+08:00" level=info msg="Docker daemon" commit=b0f5bc3 graphdrive...=20.10.7
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.973916900+08:00" level=info msg="Daemon has completed initialization"
11月 11 15:13:43 localhost.localdomain dockerd[47559]: time="2021-11-11T15:13:43.999505683+08:00" level=info msg="API listen on /var/run/docker.sock"
11月 11 15:13:43 localhost.localdomain systemd[1]: Started Docker Application Container Engine.
11月 11 15:14:12 localhost.localdomain systemd[1]: Current command vanished from the unit file, execution of the command list won't be resumed.
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost ~]# netstat -ano | grep 2375
tcp6       0      0 :::2375                 :::*                    LISTEN      off (0.00/0/0)

二、修改防火墙

其他centos7防火墙配置 我这里是虚拟机,防火墙服务关闭了,所以无需配置下面的信息,生产环境自行配置

[root@localhost ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)

修改防火墙策略,允许访问2375端口:

#开放2375/tcp端口
firewall-cmd --zone=public --add-port=2375/tcp --permanent
#更新防火墙的设置,使上面的修改生效
firewall-cmd --reload 

查看防火墙开放状态:

#查看所有打开的端口
firewall-cmd --zone=public --list-ports

三、使用插件

3.1 docker-maven-plugin插件

官方Github文档

(1) 不使用Dockerfile

            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.2</version>
                <configuration>
                    <imageName>${project.artifactId}:${project.version}</imageName>
                    <!-- <baseImage>jdk1.8</baseImage> -->
                    <baseImage>xuux/small-jre8:1.0</baseImage>
                    <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                    <dockerHost>http://192.168.122.22:2375</dockerHost>
                </configuration>
            </plugin>

执行 build 操作 mvn clean package docker:build

执行 build 完成后 push 镜像: mvn clean package docker:build -DpushImage

执行 build 并 push 指定 tag 的镜像 mvn clean package docker:build -DpushImageTag

注意:这里必须指定至少一个 imageTag,它可以配置到 POM 中,也可以在命令行指定。

指定方式有两种:

  1. 命令行指定如下:mvn clean package docker:build -DpushImageTags -DdockerImageTags=imageTag_1 -DdockerImageTags=imageTag_2

  2. POM 文件中指定:

<build>
  <plugins>
        <plugin>
        <groupId>com.spotify</groupId>
        <artifactId>docker-maven-plugin</artifactId>
        <version>1.2.2</version>
        <configuration>
            <imageName>${project.artifactId}:${project.version}</imageName>
            <baseImage>xuux/small-jre8:1.0</baseImage>
            <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
            <resources>
                <resource>
                    <targetPath>/</targetPath>
                    <directory>${project.build.directory}</directory>
                    <include>${project.build.finalName}.jar</include>
                </resource>
            </resources>
            <dockerHost>http://192.168.122.22:2375</dockerHost>
            <!--指定tag-->
            <imageTags>
                <imageTag>imageTag_1</imageTag>
                <imageTag>imageTag_2</imageTag>
            </imageTags>
        </configuration>
    </plugin>
  </plugins>
</build>

(2) 使用Dockerfile

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>1.2.2</version>
    <configuration>
        <imageName>${project.artifactId}:${project.version}</imageName>
        <!-- 指定 Dockerfile 路径-->
        <dockerDirectory>${basedir}/docker</dockerDirectory>
        <!-- 这里是复制 jar 包到 docker 容器指定目录配置,也可以写到 Docokerfile 中 -->
        <resources>
            <resource>
                <targetPath>/</targetPath>
                <directory>${project.build.directory}</directory>
                <include>${project.build.finalName}.jar</include>
            </resource>
        </resources>
        <dockerHost>http://192.168.122.22:2375</dockerHost>
        <!--指定tag-->
        <imageTags>
            <imageTag>1.0.1</imageTag>
        </imageTags>
    </configuration>
</plugin>

Dockerfile文件:

FROM xuux/small-jre8:1.0
MAINTAINER xu_ux test@email.com
WORKDIR /opt
CMD ["java", "-version"]
ENTRYPOINT ["java", "-jar", "${project.build.finalName}.jar"]

执行命令: mvn clean package docker:build -DpushImageTag


[INFO] Building image demo:0.0.1-SNAPSHOT
Step 1/5 : FROM xuux/small-jre8:1.0
 ---> 4fa1f55350fb
Step 2/5 : MAINTAINER xu_ux test@email.com
 ---> Running in c8b2e5b012c4
Removing intermediate container c8b2e5b012c4
 ---> 14353903927c
Step 3/5 : WORKDIR /opt
 ---> Running in d8dfcf2f63a6
Removing intermediate container d8dfcf2f63a6
 ---> 6e980ad6882a
Step 4/5 : CMD ["java", "-version"]
 ---> Running in 9bae114258a6
Removing intermediate container 9bae114258a6
 ---> 212ff76fe2a2
Step 5/5 : ENTRYPOINT ["java", "-jar", "${project.build.finalName}.jar"]
 ---> Running in 2f59b4c7ac0a
Removing intermediate container 2f59b4c7ac0a
 ---> 07c262894893
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built 07c262894893
Successfully tagged demo:0.0.1-SNAPSHOT

[root@localhost jre1.8.0_311]# docker images
REPOSITORY                     TAG              IMAGE ID       CREATED              SIZE
demo                           0.0.1-SNAPSHOT   07c262894893   About a minute ago   224MB
demo                           1.0.1            07c262894893   About a minute ago   224MB

(3) 绑定 Docker 命令到 Maven各个阶段

官方Github上已经很详细了,大家可以上去看看官方文档

<build>
    <plugins>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>1.2.2</version>
            <configuration>
               ......
            </configuration>
            <executions>
                <execution>
                    <id>build-image</id>
                    <phase>package</phase>
                    <goals>
                        <goal>build</goal>
                    </goals>
                </execution>
                <execution>
                    <id>tag-image</id>
                    <phase>package</phase>
                    <goals>
                        <goal>tag</goal>
                    </goals>
                    <configuration>
                        <image>${project.artifactId}:latest</image>
                        <newName>${project.artifactId}:${project.version}</newName>
                    </configuration>
                </execution>
                <execution>
                    <id>push-image</id>
                    <phase>deploy</phase>
                    <goals>
                        <goal>push</goal>
                    </goals>
                    <configuration>
                        <imageName>${project.artifactId}:${project.version}</imageName>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行mvn package时,执行 build、tag 操作 执行mvn deploy时,执行build、tag、push 操作 如果我们想跳过 docker 某个过程时,只需要:

-DskipDockerBuild 跳过 build 镜像
-DskipDockerTag 跳过 tag 镜像
-DskipDockerPush 跳过 push 镜像
-DskipDocker 跳过整个阶段

例如:我们想执行 package 时,跳过 tag 过程,那么就需要mvn package -DskipDockerTag

3.2 dockerfile-maven-plugin插件

官方推荐使用dockerfile-maven-plugin

docker-maven-plugin:We recommend you use dockerfile-maven instead.

注意:需要结合Dockerfile文件,设置环境变量

1.设置环境变量(必须)

环境变量名称:DOCKER_HOST 变量值:tcp://192.168.122.22:2375(根据实际IP地址来)

export DOCKER_HOST=tcp://localhost:2375

2. xml配置

    <plugin>
        <groupId>com.spotify</groupId>
        <artifactId>dockerfile-maven-plugin</artifactId>
        <version>1.4.13</version>
        <configuration>
            <repository>${project.artifactId}</repository>
            <tag>${project.version}</tag>
            <buildArgs>
                <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
            </buildArgs>
        </configuration>
    </plugin>

或者

<plugin>
  <groupId>com.spotify</groupId>
  <artifactId>dockerfile-maven-plugin</artifactId>
  <version>1.4.13</version>
  <executions>
    <execution>
      <id>default</id>
      <goals>
        <goal>build</goal>
        <goal>push</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
     <repository>${project.artifactId}</repository>
    <tag>${project.version}</tag>
    <buildArgs>
      <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
    </buildArgs>
  </configuration>
</plugin>

该插件的配置比docker-maven-plugin更简单

  • repository:指定docker镜像的repo名字
  • tag:指定docker镜像的tag
  • buildArgs:可以指定一个或多个变量,传递给Dockerfile,在Dockerfile中通过ARG指令进行引用

在execution中同时指定build和push目标: 当运行mvn package时,会自动执行build目标,构建Docker镜像。当运行mvn deploy命令时,会自动执行push目标,将Docker镜像push到Docker仓库。

3. 创建Dockerfile文件

Dockerfile文件必须在根目录下,与pom.xml文件同级

FROM xuux/small-jre8:1.0
MAINTAINER xu_ux test@email.com
WORKDIR /opt
CMD ["java", "-version"]
ENTRYPOINT ["java", "-jar", "${project.build.finalName}.jar"]

4. 其他使用方法:

github.com/spotify/doc…

四、问题

<baseImage>jdk1.8</baseImage>
pull access denied for jdk1.8, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

原因: 报这个错是因为docker上没有jdk1.8镜像文件。

解决方法: 换成xuux/small-jre8

# 修改xml
<baseImage>xuux/small-jre8</baseImage>

# 宿主机获取镜像
docker pull xuux/small-jre8:1.0

参考:

Maven 插件之 docker-maven-plugin 的使用