Grails 作为一个 Docker 容器
学习如何将你的 Grails 应用程序作为 Docker 容器进行分发。
作者:Iván López
Grails 版本 4.0.1
1 培训
Grails 培训 - 由创建和积极维护 Grails 框架的人员开发和提供的!.
2 入门
Docker 已成为一种很好的运行应用程序的方式,而无需安装任何运行它的依赖项的麻烦。
在本指南中,你将编写一个 Grails 应用程序,该应用程序将打包为 Docker 映像,并在 Docker 容器内运行。
2.1 如何完成指南
要入门,请执行以下操作
-
下载并解压缩源代码
或者
-
克隆Git 存储库
git clone https://github.com/grails-guides/grails-as-docker-container.git
Grails 指南存储库包含两个文件夹
-
initial
初始项目。通常是一个简单的 Grails 应用,附带一些额外的代码,让你可以抢先一步。 -
complete
一个完整的示例。这是完成指南中介绍的步骤并在initial
文件夹中应用这些更改的结果。
要完成指南,请转到initial
文件夹
-
cd
进入grails-guides/grails-as-docker-container/initial
并遵循下一节中的说明。
如果你cd 进入grails-guides/grails-as-docker-container/complete ,则可以进入完整示例 |
3 编写指南
3.1 安装和配置 Docker
如果你还没有安装 Docker,则需要安装它。
根据您的环境,您可能需要将 Docker 可用内存增加到 4GB 或更高。
提示:获取 Kitematic
Kitematic 是一款用于管理 Docker 容器的出色的桌面应用程序。第一次单击打开 Kitematic 时,它会提示您下载并安装它。然后,您可以使用 Kitematic 查看容器输出、管理容器设置等。
3.2 Gradle Docker 插件
在本指南中,我们使用 Gradle Docker 插件;一种用于管理 Docker 镜像和容器的 Gradle 插件。
要安装 Gradle 插件,请修改 build.gradle
buildscript {
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
classpath "org.grails:grails-gradle-plugin:$grailsVersion"
classpath "gradle.plugin.com.github.erdi.webdriver-binaries:webdriver-binaries-gradle-plugin:2.1"
classpath "org.grails.plugins:hibernate5:7.0.0"
classpath "com.bertramlabs.plugins:asset-pipeline-gradle:3.0.11"
classpath 'com.bmuschko:gradle-docker-plugin:6.0.0' (1)
}
}
apply plugin:"eclipse"
apply plugin:"idea"
//apply plugin:"war" (2)
apply plugin:"org.grails.grails-web"
apply plugin:"com.github.erdi.webdriver-binaries"
apply plugin:"com.bertramlabs.asset-pipeline"
apply plugin:"org.grails.grails-gsp"
apply plugin:"com.bmuschko.docker-remote-api" (1)
1 | Gradle Docker 插件 |
2 | 删除 war 插件,因为我们将生成一个可运行的 jar |
3.3 应用入口脚本
创建一个脚本,用作容器的入口点。
#!/bin/sh
java -Djava.security.egd=file:/dev/./urandom -jar /app/application.jar
3.4 Gradle Docker 任务
配置多个 Gradle 任务,它们允许我们构建可运行的 jar、将其连同所需资源一起复制到临时目录、生成 Dockerfile
文件以及最终构建 docker 镜像。
import com.bmuschko.gradle.docker.tasks.image.Dockerfile
import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
...
..
.
ext {
dockerTag = "grails-sample/${project.name}:${project.version}".toLowerCase() (1)
dockerBuildDir = mkdir("${buildDir}/docker") (2)
}
task prepareDocker(type: Copy, dependsOn: assemble) { (3)
description = 'Copy files from src/main/docker and application jar to Docker temporal build directory'
group = 'Docker'
from 'src/main/docker'
from project.jar
into dockerBuildDir
}
task createDockerfile(type: Dockerfile, dependsOn: prepareDocker) { (4)
description = 'Create a Dockerfile file'
group = 'Docker'
destFile = project.file("${dockerBuildDir}/Dockerfile")
from 'openjdk:8u151-jdk-alpine'
exposePort 8080
workingDir '/app'
copyFile jar.archiveName, 'application.jar'
copyFile 'app-entrypoint.sh', 'app-entrypoint.sh' (5)
runCommand 'chmod +x app-entrypoint.sh'
entryPoint '/app/app-entrypoint.sh' (5)
}
task buildImage(type: DockerBuildImage, dependsOn: createDockerfile) { (6)
description = 'Create Docker image to run the Grails application'
group = 'Docker'
inputDir = file(dockerBuildDir)
images.add(dockerTag)
}
1 | 定义 docker 镜像名称。它类似于 grails-sample/myProject:0.1 |
2 | 用于构建 Docker 镜像的临时目录 |
3 | 将可运行 jar 文件和 src/main/docker 中的其他文件复制到临时目录 |
4 | 创建 Dockerfile 文件 |
5 | 复制 app-entrypoint.sh 脚本并将它定义为容器入口点 |
6 | 构建 Docker 镜像 |
app-entrypoint.sh
的内容
#!/bin/sh
java -Djava.security.egd=file:/dev/./urandom -jar /app/application.jar
4 构建应用
在创建新 Gradle 任务之后,现在我们可以执行
./gradlew buildImage
...
...
:complete:jar
:complete:bootRepackage
:complete:assemble (1)
:complete:prepareDocker
:complete:createDockerfile
:complete:buildImage (2)
Building image using context '/home/ivan/workspaces/oci/guides/grails-as-docker-container/complete/build/docker'.
Using tag 'grails-sample/complete:0.1' for image.
Step 1/8 : FROM openjdk:8u151-jdk-alpine
---> 3642e636096d
Step 2/8 : MAINTAINER John Doe "[email protected]"
---> Using cache
---> 3e1c67b067e8
Step 3/8 : EXPOSE 8080
---> Using cache
---> 144aadd0580e
Step 4/8 : WORKDIR /app
---> Using cache
---> c9af01e696f8
Step 5/8 : COPY complete-0.1.jar application.jar
---> e4f41e8f0840
Removing intermediate container 6dccf4039811
Step 6/8 : COPY app-entrypoint.sh app-entrypoint.sh
---> 0be562313720
Removing intermediate container 595d0cb7b9d2
Step 7/8 : RUN chmod +x app-entrypoint.sh
---> Running in 3b41eb944045
---> 5f6fa6b0ab9a
Removing intermediate container 3b41eb944045
Step 8/8 : ENTRYPOINT /app/app-entrypoint.sh
---> Running in 3221a85ae904
---> 68f5588d1134
Removing intermediate container 3221a85ae904
Successfully built 68f5588d1134
Successfully tagged grails-sample/complete:0.1 (3)
Created image with ID '68f5588d1134'.
BUILD SUCCESSFUL
Total time: 11.453 secs
1 | assemble 任务之后执行新的 docker 任务 |
2 | 使用前一个任务中生成的 Dockerfile 构建镜像。显示 docker 命令输出 |
3 | 已经创建了镜像 grails-sample/complete:0.1 |
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
grails-sample/complete 0.1 68f5588d1134 3 minutes ago 143MB
运行应用程序
经过 docker 化 的 Grails 应用程序的运行方法非常简单
$ docker run -p 8080:8080 grails-sample/complete:0.1
几秒钟后,我们会看到消息 Grails application running at http://localhost:8080 in environment: production
5 仅使用 Docker
或者,您可以手动创建一个 Docker 文件。
-
删除 Gradle 任务
createDockerfile
和buildImage
。 -
删除对 Gradle Docker 插件的依赖关系
-
删除
src/main/docker/app-entrypoint.sh
。我们直接在 Dockerfile 中定义 CMD。 -
创建文件
src/main/docker/Dockerfile
FROM openjdk:8u151-jdk-alpine
MAINTAINER John Doe "[email protected]"
EXPOSE 8080
WORKDIR /app
COPY *.jar application.jar
CMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/application.jar"]
由于我们在 src/main/docker
下创建了 Dockerfile
,Gradle 任务 prepareDocker
将它与我们的应用程序可运行 jar 一起复制。
创建镜像
$ ./gradlew prepareDocker
$ docker build --tag="grails-sample/complete:0.1" build/docker/
手动创建 Dockerfile 将您的 Docker 镜像生成与 Docker Gradle 插件分离。