使用 Dockerfile 开发容器

1. 概览

Docker 是一个用于开发、交付和运行应用的开放式平台。利用 Docker,您可以将应用与基础设施分开管理,并将基础设施作为托管式应用来处理。Docker 可帮助您加快代码的交付、测试和部署速度,并缩短从代码编写到运行的整个周期。

为了做到这一点,Docker 将内核容器化功能与用于管理和部署应用的工作流及工具相结合。

Docker 容器可以直接在 Kubernetes 中使用,方便您在 Kubernetes Engine 中运行它们。在学完有关 Docker 的基础知识后,您将能够开始开发 Kubernetes 应用和容器化应用。

学习内容

在本实验中,您将学习如何完成以下操作:

  • 为示例应用创建 Dockerfile
  • 构建映像
  • 在本地将映像作为容器运行
  • 更改容器行为
  • 将映像推送到 Artifact Registry

前提条件

这是一个入门级实验。我们假定您几乎没有 Docker 和容器方面的相关经验。建议您先熟悉一下 Cloud Shell 和命令行,但不作强制要求。

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串,您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中必须是唯一的,并且不可变(一经设置便无法更改)。Cloud Console 会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为 PROJECT_ID),因此如果您不喜欢某个 ID,请再生成一个随机 ID,还可以尝试自己创建一个,并确认是否可用。然后,项目创建后,ID 会处于“冻结”状态。
  • 第三个值是一些 API 使用的项目编号。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud Console 中启用结算功能,才能使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。要关闭资源以避免产生超出本教程范围的费用,请按照此 Codelab 末尾提供的任何“清理”说明操作。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。

2. 示例应用

为促进此实验,我们提供了一个示例应用。在本部分,您将检索源代码,并以原生形式构建应用,然后再继续进行容器化流程。

源代码

本实验的源代码位于 GoogleCloudPlatform/container-developer-workshop 仓库中,并提供相应的示例应用文档

配置 Git

git config --global user.name ${USER}
git config --global user.email ${USER}@qwiklabs.net

克隆示例应用 Cloud Source Repositories 代码库

gcloud source repos clone sample-app ${HOME}/sample-app &&
cd ${HOME}/sample-app &&
git checkout main

输出

Cloning into '/home/student_03_49720296e995/sample-app'...
remote: Finding sources: 100% (16/16)
remote: Total 16 (delta 0), reused 16 (delta 0)
Receiving objects: 100% (16/16), 47.23 KiB | 681.00 KiB/s, done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.

Project [qwiklabs-gcp-02-4327c4e03d82] repository [sample-app] was cloned to [/home/student_03_49720296e995/sample-app].
Branch 'main' set up to track remote branch 'main' from 'origin'.
Switched to a new branch 'main'

构建示例应用

cd ${HOME}/sample-app
./mvnw compile

输出

[INFO] Scanning for projects...
...
[INFO] Compiling 1 source file to /home/student_03_49720296e995/sample-app/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.080 s
[INFO] Finished at: 2022-02-23T17:14:30Z
[INFO] ------------------------------------------------------------------------

运行示例应用

cd ${HOME}/sample-app
./mvnw exec:java

输出

[INFO] Scanning for projects...
...
Listening at http://localhost:8080

预览正在运行的应用

  • 点击“Cloud Shell 网页预览”按钮
  • 点击端口 8080 上的“预览”

完成后

  • 在 Cloud Shell 中按 CTRL + c 停止正在运行的应用

3. Dockerfile

使用 Dockerfile 将应用容器化

使用 Dockerfile 将应用打包到容器中的一种方法是使用 Dockerfile。Dockerfile 类似于一个脚本,用于指示守护程序如何组建容器映像。如需了解详情,请参阅 Dockerfile 参考文档

在示例应用代码库中创建空的 Dockerfile。

touch ${HOME}/sample-app/Dockerfile

在您选择的编辑器中打开 Dockerfile。

vi ${HOME}/sample-app/Dockerfile

选择初始图片

要使用 Dockerfile 方法构建容器,需要直接了解应用以便组建容器。创建 Dockerfile 的第一步是选择一个将用作映像基础的映像。此映像应该是由可信来源(通常是您的公司)维护和发布的父级映像或基础映像。

FROM 指令会初始化新的构建阶段,并为后续的依序命令设置基础映像。因此,FROM 指令通常是 Dockerfile 中的第一条指令,并且只能后跟支持变量的可选 ARG 指令

语法:FROM <image>[:<tag> | @<digest>] [AS <name>]

图片的格式为 <image>:<tag><image>@<digest>。如果未指定标记或摘要,则默认为 :latest 标记。<image> 的格式因用于存储映像的注册表而异。对于 Artifact Registry,<image> 格式为 <region>-docker.pkg.dev/<project ID>/<repository name>/<image name>:<image tag>

在本实验中,我们使用公共 openjdk:11.0-jdk 映像,将以下代码行添加到您的 Dockerfile 中

FROM openjdk:11.0-jdk

设置工作目录

WORKDIR 指令用于为 Dockerfile 中遵循的任何顺序指令设置工作目录。如需了解详情,请参阅 Dockerfile 参考文档的“WORKDIR”部分

语法:WORKDIR <path>

在本实验中,我们使用 /app 目录作为 WORKDIR,将以下代码行添加到 Dockerfile 文件底部

WORKDIR /app

复制应用文件

COPY 指令会将目录或文件从 <source> 位置复制到图片文件系统的 <destination> 路径。您可以指定多个 <source> 资源,并且这些资源都相对于构建上下文。构建上下文将在“构建”部分进一步讨论。如需了解详情,请参阅 Dockerfile 参考文档的“COPY”部分

语法:COPY <source>... <destination>

在本实验中,我们会将代码库中的所有文件复制到映像文件系统中,并将以下代码行添加到 Dockerfile 文件底部

COPY . /app

编译应用

RUN 指令在当前图片之上的新图片层中执行命令并提交结果。生成的提交的映像将用于 Dockerfile 中的连续步骤。如需了解详情,请参阅 Dockerfile 参考文档的“运行”部分

语法:RUN <command>

在本实验中,我们将使用 Maven 将应用编译为 JAR 文件,并将以下代码行添加到 Dockerfile 文件底部

RUN ./mvnw compile assembly:single

启动应用

CMD 指令为正在运行的容器提供默认命令。Dockerfile 中只能有一条 CMD 指令,如果指定了多个 CMD,则只有最后一个 CMD 会生效。使用 CMD 和 ENTRYPOINT 说明时,还可以使用更多高级功能,但本实验不介绍这些功能。如需了解详情,请参阅 Dockerfile 参考文档的 CMD` 部分

语法:CMD ["executable","param1","param2"]

在本实验中,我们运行编译的 JAR 文件,将以下代码行添加到 Dockerfile 文件底部

CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

最终的 Dockerfile

最终的 Dockerfile

FROM openjdk:11.0-jdk
WORKDIR /app
COPY . /app
RUN ./mvnw compile assembly:single
CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

在本地提交 Dockerfile

cd ${HOME}/sample-app
git add Dockerfile
git commit -m "Added Dockerfile"

4. 构建

现在,我们将使用 docker build 命令从 Dockerfile 中构建映像。此命令指示 Docker 守护程序按照 Dockerfile 中的说明构建映像。如需了解详情,请参阅 docker build 参考文档

构建映像

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker build --tag sample-app:${IMAGE_TAG} .

输出

Sending build context to Docker daemon  221.2kB
Step 1/4 : FROM openjdk:11.0-jdk
11.0-jdk: Pulling from library/openjdk
0c6b8ff8c37e: Pull complete
412caad352a3: Pull complete
e6d3e61f7a50: Pull complete
461bb1d8c517: Pull complete
e442ee9d8dd9: Pull complete
542c9fe4a7ba: Pull complete
41de18d1833d: Pull complete
Digest: sha256:d72b1b9e94e07278649d91c635e34737ae8f181c191b771bde6816f9bb4bd08a
Status: Downloaded newer image for openjdk:11.0-jdk
---> 2924126f1829
Step 2/4 : WORKDIR /app
---> Running in ea037abb273d
Removing intermediate container ea037abb273d
---> bd9b6d078082
Step 3/4 : COPY . /app
---> b9aec2b5de51
Step 4/4 : RUN ./mvnw compile jar:jar
---> Running in 3f5ff737b7fd
[INFO] Scanning for projects...
...
[INFO] Building jar: /app/target/sample-app-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  22.952 s
[INFO] Finished at: 2022-02-23T18:09:08Z
[INFO] ------------------------------------------------------------------------
Removing intermediate container 331443caebd3
---> 152f65cc441e
Step 5/5 : CMD ["java", "-jar", "/app/target/sample-app-1.0.0.jar"]
---> Running in 3d595a72231c
Removing intermediate container 3d595a72231c
---> 0e40d7548cab
Successfully built 0e40d7548cab
Successfully tagged sample-app:aaa8895

5. 运行

成功构建容器映像之后,我们现在可以运行应用并确保它能使用 docker run 命令按预期运行。此命令将在命令提示符的前台启动我们的容器,以进行测试或调试。如需了解详情,请参阅 docker run 参考文档

使用映像运行容器

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG}

输出

Listening at http://localhost:8080

预览在容器中运行的应用

  • 点击“Cloud Shell 网页预览”按钮
  • 点击端口 8080 上的“预览”
  • 在 Cloud Shell 中按 CTRL + c 停止容器

更改容器行为

执行 Docker Run 会使用 Dockerfile 中的默认配置。可以添加其他说明和参数来修改此行为。

启用 TRACE 日志记录

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG} \
  java -Dorg.slf4j.simpleLogger.defaultLogLevel=trace -jar /app/target/sample-app-1.0.0-jar-with-dependencies.jar

预览在容器中运行的应用

  • 点击“Cloud Shell 网页预览”按钮
  • 点击端口 8080 上的“预览”
  • 切换到 Cloud Shell 标签页
  • 在 Cloud Shell 中按 CTRL + c 以停止容器

更改端口

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
--rm \
-e PORT=8081 \
-p 8081:8081 \
sample-app:${IMAGE_TAG}

预览在容器中运行的应用

  • 点击“Cloud Shell 网页预览”按钮
  • 点击“更改端口”
  • 输入 8081
  • 点击“更改并预览”
  • 在 Cloud Shell 中按 CTRL + c 以停止容器

6. 推入式

一旦确信容器映像运行正常,并且我们希望在其他环境中和/或其他用户能够运行此容器,我们就需要将映像推送到共享存储库。此操作应该作为自动化构建流水线的一部分进行,但在测试环境中,我们已经配置了代码库,并且可以手动推送映像。

将 Dockerfile 提交推送到 Sample-app 代码库

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
git push

为 Artifact Registry 标记映像

docker tag sample-app:${IMAGE_TAG} \
    us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

配置 Artifact Registry 的凭据

gcloud auth configure-docker us-central1-docker.pkg.dev

当系统提示时,输入 Do you want to continue (Y/n)? 的答案 y 并按 Enter

将映像推送到 Artifact Registry

docker push us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

输出

 The push refers to repository [us-central1-docker.pkg.dev/qwiklabs-gcp-04-b47ced695a3c/apps/sample-app]
  453b97f86449: Pushed
  e86791aa0382: Pushed
  d404c7ee0850: Pushed
  fe4f44af763d: Pushed
  7c072cee6a29: Pushed
  1e5fdc3d671c: Pushed
  613ab28cf833: Pushed
  bed676ceab7a: Pushed
  6398d5cccd2c: Pushed
  0b0f2f2f5279: Pushed
  aaa8895: digest: sha256:459de00f86f159cc63f98687f7c9563fd65a2eb9bcc71c23dda3351baf13607a size: 2424

7. 恭喜!

恭喜,您已完成此 Codelab!

所学内容

  • 为示例应用创建了 Dockerfile
  • 已构建映像
  • 在本地将映像作为容器运行
  • 更改了容器行为
  • 将映像推送到 Artifact Registry