1. 程式人生 > >持續整合測試(1) -- docker-maven-plugin初探

持續整合測試(1) -- docker-maven-plugin初探

背景

最近想搞持續整合測試,初步構想是使用git、jekins、maven、docker作為持續整合的基礎元件,當然也是最常用的基礎元件。
初步是想將java的測試用例塞到docker容器中進行測試,測試環境部署只一次就好,映象推送到倉庫,隨測隨拉,直接使用docker命令執行,好處是環境一致,不需要重新部署測試程式碼所依附的環境;壞處是docker,docker,docker,也就是想執行測試用例必備的基礎環境docker。

junit的命令列執行

我們最常見的執行測試用例多數是通過eclipse的run as,或者是mvn test執行測試用例。如果將測試用例塞到容器內,要麼將mvn裝到容器內,要麼在物理機構建,並將構建後的環境也就是jar包塞到容器內使用java執行。
衡量了下,還是決定在物理機進行構建,將構建結果塞到容器內.
1. 重複構建mvn環境浪費時間;
2. 將mvn塞到容器內浪費資源;
3. blablabla,反正就是不爽

鑑於本人學藝不精,這裡轉載一篇對於junitcore使用的文章:

命令列執行使用java -cp *.jar org.junit.runner.JUnitCore classname可參考該篇文章瞭解及執行。

執行示例

使用junit簡單的輸出語句,沒有功能,只是作為示例演示:

public class startTest {

    @Before
    public void setup(){
        System.out.println("this is setup...");
    }

    @After
    public void teardown
(){ System.out.println("this is teardown..."); } @Test public void test1(){ System.out.println("this is test1..."); } }

命令列之行junit:

java -cp $CLASS_PATH:target/test-classes org.junit.runner.JUnitCore $CLASS_NAME 

遇到的問題及解決辦法

由於對java執行junit測試用例實在不是很熟,mvn打完包後,執行

java -cp
$CLASS_PATH org.junit.runner.JUnitCore $CLASS_NAME

總是找不到測試類(本人技術不熟,噴子勿噴^o^),原因是由於jar包內預設查詢的是src/main下的檔案,而測試用例大都在src/test下

mv src/test src/main
mvn clean package -DskipTests=true
java -cp $CLASS_PATH org.junit.runner.JUnitCore $CLASS_NAME
bingo

或者指定classpath,指定去target/test-classes目錄下查詢測試類

java -cp $CLASS_PATH:target/test-classes org.junit.runner.JUnitCore $CLASS_NAME

進入主題

該外掛有兩種使用方式:
1. 不使用dockerfile
2. 使用dockerfile

不使用dockerfile

顧名思義就是不依賴於dockerfile構建映象,即通過標籤來定義映象構建過程。

<plugin>
  <groupId>com.spotify</groupId>
  <artifactId>docker-maven-plugin</artifactId>
  <version>0.4.13</version>
  <configuration>
    <imageName>registry.test.com/example</imageName>
    <baseImage>registry.test.com/base_image</baseImage>
    <entryPoint>["sh", "start.sh"]</entryPoint>
    <resources>
      <resource>
        <targetPath>/</targetPath>
        <directory>${project.build.directory}</directory>
        <include>**/*</include>
      </resource>
    </resources>
  </configuration>
</plugin>

其中:

imageName:即將構建的映象名
baseImage: 構建映象時需要的基礎映象,類似於Dockerfile的From
entryPoint: 容器啟動時執行的命令
resources:拷貝一些額外的檔案到指定路徑下,比如${project.build.finalName}.jar檔案

一些maven的內建變數

${basedir} 專案根目錄
${project.build.directory} 構建目錄,預設為target
${project.build.outputDirectory} 構建過程輸出目錄,預設為target/classes,target/test-classes
${project.build.finalName} 打包後生成的結果名稱,預設為${project.artifactId}-${project.version}
\${project.packaging} 打包型別,預設為jar

maven一些標籤

targetPath:指定build資源到哪個目的目錄,預設是base directory
directory:指定屬性檔案的目錄,build的過程需要找到它,並且將其放到targetPath下。
includes:指定包含檔案的patterns,符合樣式並且在directory目錄下的檔案將會是包含進project的資原始檔
excludes:指定不包含在內的patterns,如果includes與excludes有衝突,那麼excludes勝利,那些符合衝突樣式的檔案還是不會包含進來的

使用dockerfile

依賴於Dockerfile構建映象,需指定dockerDirectory 來查詢Dockerfile所在檔案目錄,指定dockerDirectory 後,baseImage, maintainer, cmdentryPoint等標籤均失效。dockerDirectory目錄下的所有內容預設會被複制到${project.build.directory}/docker目錄下。

<plugin>
  <groupId>com.spotify</groupId>
  <artifactId>docker-maven-plugin</artifactId>
  <version>0.4.13</version>
  <configuration>
    <imageName>registry.test.com/example</imageName>
    <dockerDirectory>${project.basedir}/</dockerDirectory>
    <resources>
      <resource>
        <targetPath>/</targetPath>
        <directory>${project.build.directory}</directory>
        <include>${project.build.finalName}.jar</include>
      </resource>
    </resources>
  </configuration>
</plugin>

我的根目錄結構為:

-rw-r--r-- 1 ** **  437 Sep 21 10:38 Dockerfile
drwxr-xr-x 2 ** ** 4096 Sep 20 13:59 lib
drwxr-xr-x 3 ** ** 4096 Sep 20 11:18 logs
-rwxrwxrwx 1 ** ** 3015 Sep 20 18:40 pom.xml
-rwxr-xr-x 1 ** ** 3102 Sep 20 18:54 pom.xml.undocker
drwxrwxrwx 3 ** ** 4096 Sep 20 11:18 src
-rw-r--r-- 1 ** ** 1028 Sep 20 10:27 start.sh

我的Dockerfile指定在根目錄下,當執行 mvn clean package docker:build後會生成一target檔案,檢視target目錄後預設生成docker資料夾,繼續檢視docker資料夾時可見,根目錄的所有內容都被copy到該資料夾下,在進行docker build的過程中也是在target/docker目錄下根據Dockerfile執行。

Dockerfile檔案內容如下,安裝了jdk,新增測試程式碼所需的一些庫:

From registry.test.com/base_image:centos6.6

ADD target/test-classes /data1/target/test-classes
ADD target/dockermaven/lib /data1/target/dockermaven/lib
ADD start.sh /data1/
ADD lib/jdk-1.8.0_77-2.el6.x86_64.rpm /jdk-1.8.0_77-2.el6.x86_64.rpm
RUN rpm -ivh /jdk-1.8.0_77-2.el6.x86_64.rpm
ENV JAVA_HOME /usr/local/jdk1.8.0_77
ENV PATH $PATH:$JAVA_HOME/bin
RUN chmod +x /data1/start.sh
WORKDIR /data1
CMD sh start.sh

構建命令

# maven打包並構建映象
mvn clean package -DskipTests=true docker:build
# maven打包構建映象並push到倉庫
mvn clean package docker:build -DpushImage
# maven打包構建映象,將指定tag的映象push到倉庫,該命令需使用
# <imageTags><imageTag>...</imageTag></imageTags>標籤
mvn clean package docker:build -DpushImageTag

<plugin>
  <configuration>
    ...
    <imageTags>
       <imageTag>${project.version}</imageTag>
       <imageTag>latest</imageTag>
    </imageTags>
  </configuration>
</plugin>

# 關於tags配置也可在命令列直接設定
mvn ... docker:build -DpushImageTags -DdockerImageTag=latest -DdockerImageTag=another-tag