實戰Spring Boot 2.0系列(一) – 使用Gradle構建Docker映象

零壹技術棧發表於2019-03-03

前言

通常我們使用 Dockerfile 來構建專案的 Docker 映象。但是也有使用 gradle 在編譯專案的時候一起把映象給 構建上傳 的需求。本文將會講解如何使用 gradle 編寫並配置 Dockerfile 並生成 映象

實戰Spring Boot 2.0系列(一) – 使用Gradle構建Docker映象

本系列文章

  1. 實戰Spring Boot 2.0系列(一) – 使用Gradle構建Docker映象
  2. 實戰Spring Boot 2.0系列(二) – 全域性異常處理和測試
  3. 實戰Spring Boot 2.0系列(三) – 使用@Async進行非同步呼叫詳解
  4. 實戰Spring Boot 2.0系列(四) – 使用WebAsyncTask處理非同步任務
  5. 實戰Spring Boot 2.0系列(五) – Listener, Servlet, Filter和Interceptor
  6. 實戰Spring Boot 2.0系列(六) – 單機定時任務的幾種實現

正文

1. 建立專案

利用 Spring Initializer 建立一個 gradle 專案 spring-boot-gradle-for-docker,建立時新增一個 web 依賴。得到的初始 build.gradle 如下:

buildscript {
    ext {
        springBootVersion = `2.0.2.RELEASE`
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: `java`
apply plugin: `org.springframework.boot`
apply plugin: `io.spring.dependency-management`


group = `io.ostenant.springboot.sample`
version = `1.0`
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile(`org.springframework.boot:spring-boot-starter-web`)
    testCompile(`org.springframework.boot:spring-boot-starter-test`)
}
複製程式碼

2. 配置入口類

為了方便容器部署的測試,在 Spring Boot 啟動類上配置一個控制器,響應當前的系統時間。

@RestController
@SpringBootApplication
public class Application {

    private ThreadLocal<SimpleDateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"));

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @GetMapping("/")
    public String retrieveTime() {
        return threadLocal.get().format(new Date());
    }
}
複製程式碼

3. 新增外掛

這裡使用 gradle-docker 外掛 來實現 docker 映象構建。這樣,我們就可以直接在 Gradle 的指令碼里配置 Dockerfile 達到 構建映象 功能的目的。

gradle-docker 外掛已經被上傳到 jCenterMavenCentral 上。所以只需要在 dependencies 新增依賴 se.transmode.gradle:gradle-docker:1.2 就能使用 docker 外掛。

buildscript {
    ext {
        springBootVersion = `2.0.2.RELEASE`
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("se.transmode.gradle:gradle-docker:1.2")
    }
}
複製程式碼

4. 應用外掛

新增以下程式碼到 build.gradle

apply plugin: `application`
apply plugin: `docker`
複製程式碼

如果新增了 application 外掛的話,預設 gradle-docker 外掛會新增一個 distDockergradle task,用來構建一個 包含所有程式檔案docker 映象。

5. 配置映象構建資訊

5.1. 配置group

group = `io.ostenant.springboot.sample`
複製程式碼

5.2. 配置映象名稱和版本號

jar {
    baseName = "spring-boot-gradle-for-docker"
    version = 1.0
}
複製程式碼

其中映象的 tag 預設的構成為:專案組/應用名稱:版本號

tag = "${project.group}/${applicationName}:${tagVersion}"
複製程式碼
  • project.group:標準的 gradle 屬性,如果不進行定義,外掛預設會 省略 ${project.group} 這個屬性。

  • applicationName:應用被容器化時的 名稱

  • tagVersion:可選屬性,會作為映象的 標籤。預設值為 project.version,如果未指定 project.version,則使用 latest 作為標記。

5.3. 配置docker構建基礎資訊

distDocker {
    baseImage = "openjdk"
    maintainer = "harrison"
}
複製程式碼

其中,baseImage 相當於 Dockerfile 中宣告的 FROM。宣告瞭在 構建映象 是基於的 Imagemaintainer 相當於 MAINTAINER ,宣告瞭 映象作者。如果宣告瞭 registry 地址,外掛在 映象射生成後 可以自動 push 到該地址。其他的配置還包括 docker hub地址使用者名稱密碼

更詳細的配置案例如下:

docker {
    baseImage `openjdk`
    maintainer `harrison`
    useApi true
    hostUrl `http://myserver:4243`
    apiUsername `user`
    apiPassword `password`
    apiEmail `me@mycompany.com`
}
複製程式碼

6. 新增task任務

完成了基本的配置,我們還需要新增一個 task 用來在 gradle 編譯的時候 執行映象構建

外掛提供了一些 轉換方法,用來指代 Dockerfile 中的 關鍵詞語法,如下表,可以按照需求對照著來:

Dockerfile關鍵詞 gradle task方法
ADD addFile(Closure copySpec)
addFile(String source, String dest)
addFile(File source, String dest)
CMD defaultCommand(List cmd)
ENTRYPOINT entryPoint(List entryPoint)
ENV setEnvironment(String key, String val)
EXPOSE exposePort(Integer port)
exposePort(String port)
RUN runCommand(String cmd)
USER switchUser(String userNameOrUid)
VOLUME volume(String… paths)
WORKDIR workingDir(String dir)

下面是本專案的 taskBuilder 的任務配置

task dockerBuilder(type: Docker) {
    applicationName = jar.baseName
    tagVersion = jar.version
    volume(`/tmp`)
    addFile("${jar.baseName}-${jar.version}.jar", "app.jar")
    entryPoint(["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", `app.jar`])
    exposePort(8080)
    doFirst {
        copy {
            from jar
            into stageDir
        }
    }
}
複製程式碼

構建完成y以後,專案根目錄的 build/docker 資料夾下面會出現 Dockerfilespring-boot-gradle-for-docker-1.0.jar 檔案。其中,以上的 task 等同於以下的 Dockerfile

FROM aglover/java8-pier
VOLUME ["/tmp"]
ADD spring-boot-gradle-for-docker-1.0.jar app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
EXPOSE 8080
複製程式碼

如果覺的在 task 中編寫 Dockerfile 替換指令碼 非常彆扭,也可以直接在 task 中指定 Dockfile檔案路徑,直接使用已有的檔案來生成映象:

task buildDocker(type: Docker) {
    applicationName = jar.baseName
    tagVersion = jar.version
    dockerfile = file(`Dockerfile`)
    doFirst {
        copy {
            from jar
            into stageDir
        }
    }
}
複製程式碼

通過 file() 指定 task 使用位於 專案根目錄Dockerfile 來生產映象。

7. 編譯並構建Docker映象

進入專案根目錄,執行 gradle 命令進行打包構建。

$ ./gradlew clean build dockerBuilder --info
複製程式碼

gradle 首先會執行 本地測試,然後進行 專案打包,進一步根據 docker-gradle 外掛進行 映象構建

實戰Spring Boot 2.0系列(一) – 使用Gradle構建Docker映象

等待出現 BUILD SUCCESSFUL 就表明任務執行成功。可以觀察到映象的名稱為

io.ostenant.springboot.sample/spring-boot-gradle-for-docker:1.0
複製程式碼

執行 docker images 檢視本地映象,進一步驗證映象構建成功。

實戰Spring Boot 2.0系列(一) – 使用Gradle構建Docker映象

下面給出 build.gradle 完整的 配置檔案

buildscript {
    ext {
        springBootVersion = `2.0.2.RELEASE`
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("se.transmode.gradle:gradle-docker:1.2")
    }
}

apply plugin: `java`
apply plugin: `org.springframework.boot`
apply plugin: `io.spring.dependency-management`
apply plugin: `application`
apply plugin: `docker`


group = `io.ostenant.springboot.sample`
version = `1.0`
sourceCompatibility = 1.8
targetCompatibility = 1.8
mainClassName = "io.ostenant.springboot.sample.Application"

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile(`org.springframework.boot:spring-boot-starter-web`)
    testCompile(`org.springframework.boot:spring-boot-starter-test`)
}

jar {
    baseName `spring-boot-gradle-for-docker`
    version `1.0`
}

distDocker {
    baseImage `openjdk`
    maintainer `harrison`
}

task dockerBuilder(type: Docker) {
    applicationName = jar.baseName
    tagVersion = jar.version
    volume(`/tmp`)
    addFile("${jar.baseName}-${jar.version}.jar", "app.jar")
    entryPoint(["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", `app.jar`])
    exposePort(8080)
    doFirst {
        copy {
            from jar
            into stageDir
        }
    }
}
複製程式碼

8. 使用映象啟動容器

執行如下命令,根據映象啟動容器,對外暴露 8080 訪問埠。

$ docker run -d --name gradle-boot -p 8080:8080 io.ostenant.springboot.sample/spring-boot-gradle-for-docker:1.0
複製程式碼

訪問 http://127.0.0.1:8080/ ,頁面會輸出當前系統時間,如圖所示:

實戰Spring Boot 2.0系列(一) – 使用Gradle構建Docker映象

小結

gradle-docker 外掛還提供了配置 映象倉庫地址、配置使用 Docker Remote ApiDocker Hub 等用法,可以參考該專案的 GitHub 地址來進行配置使用:
github.com/Transmode/g…


歡迎關注技術公眾號: 零壹技術棧

零壹技術棧

本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。

相關文章