使用Gradle 构建SpringBoot应用的Docker镜像
应用发布流程
通过结合docker容器,目前我们应用的发布流程大致如下:
Gradle脚本构建镜像
我们的工程是:
- 基于SpringBoot 2.0.3.RELEASE
- 采用JDK8编译
- gradle 构建
根据我们发布流程的要求,构建出最终的镜像需要满足几个目标:
- 尽可能构建体积小的镜像
- 通过执行简单的gradle命令,构建镜像并push到阿里云的dockerHub仓库
- 构建的镜像版本,有唯一标识,方便发布。比如版本中含有日期和 最后一次git commit的hash值
我们最终选用了 https://github.com/bmuschko/gradle-docker-plugin 的gradle-docker-plugin来实现构建docker镜像。该插件支持java-application
和 spring-boot-application
两种方式,很明显我们选取spring-boot-applicaiton插件。
在原工程的build.gradle 最后加上:
apply from: 'docker.gradle'
在build.gradle的同一级目录下新建文件docker.gradle。
添加:
buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath 'com.bmuschko:gradle-docker-plugin:4.0.1'
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: DockerRemoteApiPlugin
apply plugin: com.bmuschko.gradle.docker.DockerSpringBootApplicationPlugin
都是一些基础配置。
def projectname = "${project.getName()}"
def dockerVer = getGitVersion()
def port = 8990
这里定义一些全局变量使用。port可以根据实际情况定义。其中getGitVersion()
的定义:
import java.text.SimpleDateFormat
def getGitVersion() {
def logTime = 'git log'.execute() | 'grep Date:'.execute() | 'head -n 1'.execute()
logTime.waitFor()
Date date = new Date(logTime.text.replace("Date:", "").trim())
String pushTime = new SimpleDateFormat("yyyyMMddHHmmss").format(date)
return pushTime + "." + ('git rev-parse --short HEAD'.execute().text.trim())
}
可以看到拼接了git仓库的最后一个commit 的提交时间和hash值。
gradle-docker-plugin 预定义了一些task,我们只需要简单配置:
docker {
url = getDefaultDockerUrl()
registryCredentials {
url = "registry.cn-hangzhou.aliyuncs.com"
username = 'yourRepoUsername'
password = 'yourRepopswd'
}
springBootApplication {
baseImage = 'openjdk:8-alpine'
ports = [port, port]
}
}
getDefaultDockerUrl
是本地docker 的url,plugin对windows、linux、mac都已经有了相应实现。
registryCredentials
是docker Hub的认证信息配置。 阿里云的dockerHub配置如上。
springBootApplication
只需要配置baseImage
和端口映射。可以看到我们基于openjdk:8-alpine
,alpine linux 镜像只有4.4M,不过 openjdk:8-alpine
镜像体积赫然有103MB那么大了。
配置这些就可以构建镜像,但是有些小问题需要解决。
- ``openjdk:8-alpine` 默认是标准时区,而不是+8时区,需要修改。
- 该插件对私有docker仓库的tag支持存在bug,需要特殊处理。
接下来我们需要重写其中的 createDockerFile,buildImage,PushImage Task 来解决这两个问题。
其中 createDockerFile:
task createDockerfile(type: Dockerfile) {
dependsOn dockerSyncArchive
from(docker.springBootApplication.baseImage.get())
copyFile(bootWar.archiveName, "/app/${bootWar.archiveName}".toString())
//https://wiki.alpinelinux.org/wiki/Setting_the_timezone
//https://github.com/gliderlabs/docker-alpine/issues/428
runCommand(' echo \'http://mirrors.ustc.edu.cn/alpine/v3.8/main\' > /etc/apk/repositories ' +
' && echo \'http://mirrors.ustc.edu.cn/alpine/v3.8/community\' >>/etc/apk/repositories ' +
' && apk update && apk add tzdata ' +
' && ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ' +
' && echo "Asia/Shanghai" > /etc/timezone ' +
' && date '+
' && rm -rf /var/cache/apk/* ' +
' && rm -rf /usr/local/share/.cache')
entryPoint("java")
defaultCommand("-jar", "/app/${bootWar.archiveName}".toString())
exposePort(docker.springBootApplication.ports)
}
上面主要是创建Dockerfile,编写指令来配置合适的timezone
。使用中科大的apk安装源(mirrors.ustc.edu.cn)更快。。。
task buildImage(type: DockerBuildImage) {
dependsOn createDockerfile
inputDir = createDockerfile.destFile.get().asFile.parentFile
tag = "zongwu233/${projectname}:${dockerVer}".toLowerCase()
}
//https://github.com/bmuschko/gradle-docker-plugin/issues/209
task dockerTag(type: com.bmuschko.gradle.docker.tasks.image.DockerTagImage) {
dependsOn buildImage
imageId = "zongwu233/${projectname}:${dockerVer}".toLowerCase()
tag = "${dockerVer}".toLowerCase()
repository = "registry.cn-hangzhou.aliyuncs.com/zongwu233/${projectname}".toLowerCase()
}
解决私有DockerHub 的tag问题。更详细的讨论见https://github.com/bmuschko/gradle-docker-plugin/issues/209
其中zongwu233
是在阿里云DockerHub中的命名空间,${projectname}
是仓库名称。
最后是push task:
task pushImage(type: DockerPushImage) {
dependsOn dockerTag
imageName = "registry.cn-hangzhou.aliyuncs.com/zongwu233/${projectname}".toLowerCase()
}
另外要在createDockerFile,buildImage 等task之前 加上import 声明:
import com.bmuschko.gradle.docker.DockerRemoteApiPlugin
import com.bmuschko.gradle.docker.tasks.image.*
import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import com.bmuschko.gradle.docker.tasks.image.DockerPushImage
这样,在控制台输入命令:
gradle pushImage
即可完成应用的docker镜像构建并且push到阿里云仓库。