在本文中, 我们将看看 Jib, 它是 Google 提供的一个工具, 可以轻松快速地创建 Docker 镜像. 无需创建 Dockerfile 文件, 也无需安装 Docker 守护进程, Jib 可直接使用.
简介
到目前为止, 我们一直使用来自 Spotify 的 dockerfile-maven-plugin 来构建和推送 Docker 镜像. 这要求我们根据 最佳实践 来编写 Dockerfile, 安装 Docker 守护进程并将插件添加到构建过程中. Jib 将为我们提供一种更简便的方式来创建 Docker 镜像. 我们只需要添加并配置 Maven 插件即可. 当然, 只有当我们自己亲自尝试了, 我们才会相信它更轻便, 这正是接下来要做的.
我们将创建一个简单的 Spring Boot 应用程序, 使用 Jib Maven 插件 将其容器化并将其推送到 DockerHub. 接着我们将拉取镜像并运行容器. 这些资源可在 GitHub https://github.com/mydeveloperplanet/myjibplanet 获取.
我们正在使用:
- Ubuntu 18.04
- Spring Boot 2.2.1
- Java 11
Jib Maven 插件 1.8.0
Docker Hub 账号
有关 Jib 的更多信息请访问 Google Cloud Platform Blog 和 GitHub https://github.com/GoogleContainerTools/jib
创建应用程序
第一步, 我们将创建一个简单的 Spring Boot 应用程序. 我们将 Spring Actuator 和 Spring web MVC 依赖项添加到 pom 文件中. Spring Actuator 将为我们提供添加运行状况检查的方法.
- <dependency>
- <groupId>
- org.springframework.boot
- </groupId>
- <artifactId>
- spring-boot-starter-actuator
- </artifactId>
- </dependency>
- <dependency>
- <groupId>
- org.springframework.boot
- </groupId>
- <artifactId>
- spring-boot-starter-Web
- </artifactId>
- </dependency>
我们的应用程序由一个 REST 控制器组成, 该控制器返回问候消息和机器地址.
- @RestController
- public class HelloController {
- @RequestMapping("/hello")
- public String hello() {
- StringBuilder message = new StringBuilder("Hello Jib Maven Plugin!");
- try {
- InetAddress ip = InetAddress.getLocalHost();
- message.append("From host:" + ip);
- } catch (UnknownHostException e) {
- e.printStackTrace();
- }
- return message.toString();
- }
- }
在本地运行:
$ mvn spring-boot:run
成功启动之后, 我们调用 URL http//localhost8080/hello, 它将返回以下消息:
Hello Jib Maven Plugin! From host: gunter-Latitude-5590/127.0.1.1
设置 Jib 和 Docker Hub
在本节中, 我们将添加 Jib Maven 插件, 并确保成功连接到 Docker Hub 注册中心. 要使其正常工作是相当困难的, 主要是由于缺乏文档. Jib 官方文档对安全身份验证方法相当模糊. 大多数示例都包括向 pom 或 Maven 配置文件中添加纯文本凭证. 但这不是我们想要的. 我们想要一种通过 Docker Credential Helper 连接到 Docker Hub 的安全方法.
为了测试连接, 我们将 Jib Maven 插件添加到 pom 中并对其进行配置, 以便检索基础镜像和将该镜像推送到 Docker Hub.
- <plugin>
- <groupId>com.google.cloud.tools</groupId>
- <artifactId>jib-maven-plugin</artifactId>
- <version>1.8.0</version>
- <configuration>
- <!-- openjdk:11.0.5-jre -->
- <from>
- <image>openjdk:11.0.5-jre</image>
- </from>
- <to>
- <image>docker.io/${docker.image.prefix}/${project.artifactId}</image>
- <credHelper>pass</credHelper>
- </to>
- </configuration>
- </plugin>
from 标签包含我们的基础镜像, 就像 Dockerfile 中的 FROM 语句. to 标签包含我们想要推送的镜像. ${docker.image.prefix} 设置为 mydeveloperplanet (我们的 Docker Hub 账号), 你需要对应修改为你自己的账号. ${project.artifactId} 包含 1.0-SNAPSHOT 版本. 为了使用 Credential Helper, 我们将标签 credHelper 设置为 pass .
在开始之前, 如果你尚未设置 GPG 密钥, 则需要设置它, 请参阅 Ubuntu 帮助页面
$ gpg --gen-key
为方便使用, 你可以将生成的密钥作为环境变量添加到配置文件中. 将以下行添加到你的 .profile 文件中, 注意替换 Your_GPG_Key 内容.
export GPGKEY=Your_GPG_Key
执行 source 以使环境变量生效.
$ source .profile
你也可以选择将你的密钥发送到 Ubuntu 密钥服务器, 但不是必要的.
$ gpg --send-keys --keyserver keyserver.Ubuntu.com $GPGKEY
安装 https://www.passwordstore.org/ 并使用你的 GPG 密钥初始化密码存储.
- $ sudo apt install pass
- $ pass init Your_GPG_Key
- mkdir: created directory '/home/gunter/.password-store/'
- Password store initialized for My Password Storage Key
接下来要做的是下载并解压缩 Docker Credential Helper, 并赋予可执行权限.
- $ wget https://github.com/docker/docker-credential-helpers/releases/download/v0.6.3/docker-credential-pass-v0.6.3-amd64.tar.gz
- $ tar xvzf docker-credential-pass-v0.6.3-amd64.tar.gz
- $ mv docker-credential-pass /usr/bin
- $ chmod +x docker-credential-pass
Docker Credential Helper 需要正确配置, 而这部分文档是缺失的.
创建包含以下内容的 config.JSON 文件. 在文档中说明要添加内容 { "credStore": "pass" } , 但是使用此配置, Jib 将无法连接到 Docker Hub 注册表. 我们发现该 Issue 中提及到 credStore 已不再支持 Google Cloud Registry.
- "credHelpers": {
- "https://index.docker.io/v1": "pass"
- }
初始化 Docker Credential Helper. 当 pass 初始化并要求输入密码时输入密码.
- $ pass insert docker-credential-helpers/docker-pass-initialized-check
- mkdir: created directory '/home/gunter/.password-store/docker-credential-helpers'
- Enter password for docker-credential-helpers/docker-pass-initialized-check:
- Retype password for docker-credential-helpers/docker-pass-initialized-check:
检查密码设置是否正确:
- $ pass show docker-credential-helpers/docker-pass-initialized-check
- pass is initialized
使用你的 Docker 凭证登陆. 这里会出现警告提示你的密码以非加密方式保存在 config.JSON 文件中. 不清楚为何会出现该提示, 因为凭证已经是以加密形式保存在 config.JSON 中.
- $ docker login
- Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
- Username: your_user_name
- Password:
- WARNING! Your password will be stored unencrypted in /home/gunter/.docker/config.JSON.
- Configure a credential helper to remove this warning. See
- https://docs.docker.com/engine/reference/commandline/login/#credentials-store
- Login Succeeded
从现在开始, docker login 无需输入凭证即可执行.
- $ docker login
- Authenticating with existing credentials...
- WARNING! Your password will be stored unencrypted in /home/gunter/.docker/config.JSON.
- Configure a credential helper to remove this warning. See
- https://docs.docker.com/engine/reference/commandline/login/#credentials-store
- Login Succeeded
你可以使用 docker logout 再次注销
- $ docker logout
- Removing login credentials for https://index.docker.io/v1/
确保你已再次登陆, 然后运行 Maven Jib 构建命令:
$ mvn compile jib:build
镜像会成功被构建并推送到 Docker Hub. 构建过程中将引发两个警告:
Base image 'openjdk:11.0.5-jre' does not use a specific image digest - build may not be reproducible
这可以通过替换基础镜像 openjdk:11.0.5-jre 为 openjdk@sha256:b3e19d27caa8249aad6f90c6e987943d03e915bbf3a66bc1b7f994a4fed668f6 (sha256 格式) 值来轻松解决.
The credential helper (docker-credential-pass) has nothing for server URL: https://index.docker.io/v1
这是一个奇怪的警告, 因为此 URL 的凭据已解析并用于推送镜像.
为我们的应用程序配置 Jib
现在我们已经以安全的方式配置了身份认证, 我们可以继续为应用程序配置 Jib Maven 插件. 我们在镜像中添加标签并指定主类.
- <to>
- <image>
- docker.io/${docker.image.prefix}/${project.artifactId}
- </image>
- <credHelper>
- pass
- </credHelper>
- <tags>
- <tag>
- ${project.version}
- </tag>
- </tags>
- </to>
- <container>
- <mainClass>
- com.mydeveloperplanet.myjibplanet.MyJibPlanetApplication
- </mainClass>
- </container>
不要将标签 format 和 OCI 值添加到容器配置中. Docker Hub 尚未完全支持 OCI, 将会显示 An error occurred while loading the tags. Try reloading the page 错误信息.
再次构建镜像并拉取 Docker 镜像:
- $ docker pull mydeveloperplanet/myjibplanet
- Using default tag: latest
- latest: Pulling from mydeveloperplanet/myjibplanet
- 844c33c7e6ea: Pull complete
- ada5d61ae65d: Pull complete
- f8427fdf4292: Pull complete
- a5217f27a28f: Pull complete
- 176e83ebae4f: Pull complete
- 800204250483: Pull complete
- 492e142ab90b: Pull complete
- 7c8e6198cd4b: Pull complete
- c49bb7f02774: Pull complete
- Digest: sha256:b7144bfdf6ee47d6b38914a84789ef9f7e2117320080b28ce39c385ee399a0c8
- Status: Downloaded newer image for mydeveloperplanet/myjibplanet:latest
- docker.io/mydeveloperplanet/myjibplanet:latest
运行该镜像并映射 8080 端口:
- $ docker run -p 127.0.0.1:8080:8080/tcp mydeveloperplanet/myjibplanet
- ...
- 2019-12-25 09:57:13.196 INFO 1 --- [nio-8080-exec-1] o.s.Web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
- 2019-12-25 09:57:13.205 INFO 1 --- [nio-8080-exec-1] o.s.Web.servlet.DispatcherServlet : Completed initialization in 9 ms
查看 Docker 容器列表:
- $ docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- c05e431b0bd1 mydeveloperplanet/myjibplanet "java -cp /app/resou..." 13 seconds ago Up 12 seconds 127.0.0.1:8080->8080/tcp recursing_meninsky
我们只需要检索 Docker 容器的 IP 地址.
- $ docker inspect c05e431b0bd1
- ...
- "NetworkSettings": {
- ...
- "IPAddress": "172.17.0.2",
- ...
- }
- ...
现在可以使用 http://172.17.0.2:8080/hello 调用我们应用程序的 URL .
这将向我们返回欢迎信息:
Hello Jib Maven Plugin! From host: c05e431b0bd1/172.17.0.2
我们还有一个问题要解决: 我们的应用程序在 Docker 容器中以 root 用户运行. 由于安全性原因, 这不是我们想要的. 首先, 我们将检查 Docker 容器中有哪些用户可用:
- $ docker exec -it -u root c05e431b0bd1 cat /etc/passwd
- ...
- nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
- ...
可发现该 Docker 容器包含了一个 nobody 用户, 我们可以用它来运行应用程序. 添加 user 标签到 pom 文件中:
- <container>
- <mainClass>
- com.mydeveloperplanet.myjibplanet.MyJibPlanetApplication
- </mainClass>
- <user>
- nobody
- </user>
- </container>
再次构建镜像, 拉取并运行它. 使用 docker inspect 检验是否是使用 nobody 作为用户.
- ...
- "Config": {
- "Hostname": "76b3afaca3af",
- "Domainname": "",
- "User": "nobody",
- ...
- }
- ...
在 pom 中, 我们还添加了 Spring Actuator. 没有方法通过 Jib 添加 Docker 运行状态检查, 必须通过在 Kubernetes 配置中的存活探针和就绪探针来解决, 另请参阅此
结论
我们尝试了使用 Jib Maven 插件来创建我们的 Docker 镜像. 为 Docker Hub 注册表配置凭据非常困难, 但是一旦设置好了, 这个插件就非常容易使用了. 除此之外, 不需要 Docker 守护进程, 也不需要编写单独的 Dockerfile. 最后不能不提的是, 它确实非常快. 我们肯定会在不久的将来使用这个插件.
相关链接:
- Docker 镜像和容器
- 使用 Docker 和 Jib 容器化 Spring Boot 应用程序
[原文链接] : Create Fast and Easy Docker Images With Jib 翻译: 冯旭松
来源: http://www.tuicool.com/articles/jQ3Yzun