使用maven外掛構建docker映象

fairjm發表於2017-12-22

本文來自 fairjm@圖靈社群 轉截請註明出處


為什麼要用外掛

主要還是自動化的考慮,如果額外使用Dockerfile進行映象生成,可能會需要自己手動指定jar/war位置,並且打包和生成映象間不同步,帶來很多瑣碎的工作。

外掛選擇

使用比較多的是spotify的外掛:https://github.com/spotify/docker-maven-plugin
https://github.com/spotify/dockerfile-maven
但這裡我選擇另一款外掛:https://github.com/fabric8io/docker-maven-plugin。 因為他文件比較詳細,在使用上也比較方便。
文件地址:enter link description here

示例

這裡使用一個spring boot專案,只有一個最簡單的HelloController,如下:

@RestController
public class HelloController {
    @GetMapping("/")
    public String hello() {
        return "hello";
    }
}

pom.xml改動如下:

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.23.0</version>
    <configuration>
        <dockerHost>tcp://192.168.99.100:2376</dockerHost>
        <certPath>C:\Users\fairjm\.docker\machine\machines\default</certPath>
        <images>
            <image>
                <name>${project.name}:${project.version}</name>
                <build>
                    <from>openjdk:8-jre</from>
                    <args>
                        <JAR_FILE>${project.name}-${project.version}.jar</JAR_FILE>
                    </args>
                    <assembly>
                        <descriptorRef>artifact</descriptorRef>
                    </assembly>
                    <entryPoint>["java"]</entryPoint>
                    <cmd>["-jar","maven/${project.name}-${project.version}.jar"]</cmd>
                </build>
                <run>
                    <ports>
                        <port>8888:8080</port>
                    </ports>
                </run>
            </image>
        </images>
    </configuration>
</plugin>

這裡使用了在xml裡寫操作而不是使用Dockerfile的方式,個人感覺這種方式更加簡單一點,不需要額外再維護一份檔案,和Dockerfile相比使用的語法(注意entrypoint和cmd)也類似。

接下來介紹一下configuration配置。
dockerHostcertPath是連線docker使用,畢竟外掛本身不包含docker和對應功能只是呼叫docker提供的API。
這兩個值在docker toolbox上可以通過docker-machine env獲得。

$ docker-machine env
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="C:\Users\fairjm\.docker\machine\machines\default"
export DOCKER_MACHINE_NAME="default"
export COMPOSE_CONVERT_WINDOWS_PATHS="true"
# Run this command to configure your shell:
# eval $("D:\Docker Toolbox\docker-machine.exe" env)

image的build指定了構建相關的設定:
- name指定image名,這裡使用了專案名,tag使用專案版本;
- from指定基於的image,和Dockerfile的FROM一致;
- args和ARG一致(在這個例子中沒有實際意義);
- assembly用來定義哪些檔案進入映象中,使用了外掛已經定義好的行為,spring-boot生成的是fat jar不需要拷貝依賴所以選擇了artifact。這個的配置比較豐富,可以檢視文件獲取更多的資訊。
- entryPoint和cmd也對應同樣的Dockerfile命令。

接著通過mvn clean package docker:build執行打包和build

[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ docker-test ---
[INFO] Building jar: D:\sts_workspace\docker-test\target\docker-test-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:1.5.9.RELEASE:repackage (default) @ docker-test ---
[INFO]
[INFO] --- docker-maven-plugin:0.23.0:build (default-cli) @ docker-test ---
[INFO] Copying files to D:\sts_workspace\docker-test\target\docker\docker-test\0.0.1-SNAPSHOT\build\maven
[INFO] Building tar: D:\sts_workspace\docker-test\target\docker\docker-test\0.0.1-SNAPSHOT\tmp\docker-build.tar
[INFO] DOCKER> [docker-test:0.0.1-SNAPSHOT]: Created docker-build.tar in 1 second
[INFO] DOCKER> [docker-test:0.0.1-SNAPSHOT]: Built image sha256:303c3
[INFO] DOCKER> [docker-test:0.0.1-SNAPSHOT]: Removed old image sha256:ea8a7
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

完成打包,在對應連線的docker上也會出現這個映象:

$ docker image ls
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
docker-test                       0.0.1-SNAPSHOT      303c39c7d253        13 seconds ago      552MB

run指定了執行引數 這裡將host的8888和容器的8080繫結,可以使用mvn docker:start啟動,訪問8888埠即可連線到伺服器。
與其配對的是mvn docker:stop,可以停止並移除啟動的容器。

示例2

上述使用xml的配置方式,這裡再簡單描述一下使用Dockerfile的配置方式。
在進行一些操作的時候,可以發現使用xml會有些問題,比如指令的執行順序。
該外掛xml的執行順序和命令的定義順序不一定一致,可能會帶來一些問題,比如將<user>放於<runCmds>前但還是<runCmds>先觸發,一些需要root許可權的命令就會失敗。
比如這個issus(但不確定是feature還是bug,感覺是feature):https://github.com/fabric8io/docker-maven-plugin/issues/913

這時候就需要直接使用Dockerfile來進行配置。
這裡取一個實際的打成war的工程。
外掛配置如下:

<images>
    <image>
        <name>${project.name}:${project.version}</name>
        <build>
            <assembly>
                <descriptorRef>rootWar</descriptorRef>
            </assembly>
            <dockerFile>Dockerfile</dockerFile>
        </build>
        <run>
            <ports>
                <port>8888:8080</port>
            </ports>
        </run>
    </image>
</images>  

這裡更改了descriptorRef,換成rootWar,這會將target下的專案war拷貝到maven\下並且取名為ROOT.war
Dockerfile預設放置的位置是src/main/docker,我們在這裡建對應的檔案:

FROM jetty
USER root
ENV JAVA_OPTIONS=-Xmx1g
RUN mkdir -p /root/xxx && touch /root/xxx/yyy && echo zz > /root/xxx/yyy
COPY maven/ /var/lib/jetty/webapps

基本和上面的配置類似,base image改為了jetty,檢視jetty的Dockerfile可以發現他使用了一個新使用者jetty,使用這個使用者無法在root下建立目錄,並且由於專案本身之前使用sudo執行的,所以為了能正常執行選擇使用root使用者。
最後一步將ROOT.war拷貝到jetty的webapps目錄下。

關於maven/這個目錄,在打包後,會在target下生成target\docker\專案名\0.0.1-SNAPSHOT\build,對應的Dockerfilemaven\就在這個目錄下,實際執行的不是src/main/docker/Dockerfile,而是拷貝到上述目錄下的Dockerfile,此外使用xml的方式也是在這個位置生成了一份Dockerfile(USER 總是被放置於最後...)。

更多

本文簡要說明了使用fabric8的docker maven外掛進行構建執行相關的操作,該外掛還有其他的功能可以通過上面的文件獲取幫助。

原始碼下載

https://github.com/fairjm/spring-boot-docker

相關文章