GCP 计算实例虚拟机用于 Docker 化应用的入门指南 [教程第八部分]





5.00/5 (1投票)
如何创建虚拟机、使用容器注册表和秘密管理器
这篇文章最初发表于 https://www.pascallandau.com/,原文链接为 GCP 计算实例虚拟机用于 Docker 化应用的入门指南 [教程第八部分]
在本文中,我们将重点介绍 Google Cloud Platform (GCP),并创建一个计算实例虚拟机来运行 Docker 化应用程序。这包括
- 创建虚拟机
- 使用容器注册表
- 使用秘密管理器
所有代码示例都公开可用,可在我的 Github 上的 Docker PHP 教程代码库中找到。
您可以在 part-8-gcp-compute-instance-vm-docker 分支中找到本教程的最终结果。
Docker PHP 教程的所有已发布部分都收集在 Docker PHP 教程 的专用页面下。上一部分是 为 Docker 化 PHP 应用创建 CI 管道,下一部分是 通过 Docker Compose 将 Docker 化 PHP 应用部署到 GCP 生产环境。
如果您想继续学习,请订阅 RSS feed 或 通过电子邮件,以便在下一部分发布时收到自动通知。:)
目录
引言
在下一个教程中,我们将通过 Docker Compose 将 Docker 化 PHP 应用部署到“生产环境”,并将在GCP (Google Cloud Platform) 上创建此“生产环境”。本教程作为 GCP 的入门指南,旨在建立一些基础知识,因为我们将使用该平台提供运行 Docker 化 PHP 应用程序所需的所有基础设施。
在此过程中,我们将了解 GCP 项目作为我们在 GCP 中的“空间”,以及服务帐号作为以编程方式进行通信的一种方式。我们将首先通过 UI 手动完成所有操作,但也会解释如何通过 gcloud
cli 以编程方式完成,并最终得到一个完全自动化的脚本。
下面的视频展示了整体流程
我使用的 API 密钥(参见服务帐号密钥文件)不在代码库中,因为任何使用都会向我收费,即您必须创建自己的项目和密钥才能继续学习。
注意
但您仍应事先了解这一点,并确保在您自己尝试时关闭/删除所有内容。“最安全”的方法是关闭(删除)整个项目。
设置 GCP 项目
在 GCP 中,资源组织在所谓的项目下。我们可以通过创建项目 UI 来创建一个项目。
项目 ID 必须是一个全局唯一的 字符串
,我为本教程选择了 pl-dofroscra-p
(pl
=> Pascal Landau;dofroscra
=> Docker From Scratch;p
=> production)。
创建服务帐号
下一步,我们需要一个服务帐号,我们可以用它来发出 API 请求,因为我们不想使用我们的“个人 GCP 帐号”。服务帐号是通过 IAM 和管理员 > 服务帐号 UI 创建的。
创建服务帐号密钥文件
为了以编程方式使用该帐号,我们还需要创建一个密钥文件,方法是选择相应服务帐号的“管理密钥”选项。
这将打开一个 UI,地址为
https://console.cloud.google.com/iam-admin/serviceaccounts/details/$serviceAccountId/keys
其中 $serviceAccountId
是服务帐号的数字 ID,例如 109548647107864470967
。要创建密钥
- 点击
“添加密钥”
并从下拉菜单中选择“创建新密钥”
。- 这将弹出一个模态窗口,用于选择密钥类型。
- 选择推荐的 JSON 类型,然后点击
“创建”
。- GCP 将生成新的密钥对,存储公钥,并将私钥文件提供下载。
- 下载文件,并确保像对待任何其他私钥(ssh、gpg 等)一样对待它,即切勿公开共享!
我们将将此文件存储在代码库的根目录下,文件名为 gcp-service-account-key.json,并将其添加到 .gitignore
文件中。
每个服务帐号还有一个唯一的电子邮件地址,由其(非数字)ID
和项目 ID
组成。您也可以直接在密钥文件中找到它
$ grep "email" ./gcp-service-account-key.json
"client_email":
"docker-php-tutorial-deployment@pl-dofroscra-p.iam.gserviceaccount.com",
此电子邮件地址通常用于引用服务帐号,例如在分配 IAM 权限时。
配置 IAM 权限
IAM 是 Identity and Access Management (IAM) 的缩写,用于管理 GCP 上的权限。“权限”和“角色”是两个核心概念。
- 权限是针对特定操作的精细控制,例如
storage.buckets.create
以“创建 Cloud Storage 存储桶”。 - 角色结合了一系列权限,例如
Cloud Storage Admin
角色具有以下权限:storage.buckets.create
storage.buckets.get
- 等等。
- 角色被分配给用户(或服务帐号)。
您可以在权限参考中找到所有权限的完整概述,在了解角色 > 预定义角色下找到所有角色。
在本教程中,我们将向服务帐号“user
” docker-php-tutorial-deployment@pl-dofroscra-p.iam.gserviceaccount.com
分配以下角色:
- Storage Admin
- Secret Manager Admin
- 用于从秘密管理器中检索秘密。
- Compute Admin, Service Account User 和 IAP-secured Tunnel User
- 对于通过 IAP 登录虚拟机是必需的。
可以通过 Cloud Console IAM UI,通过编辑相应的用户来分配角色。
注意:IAM 权限的更改可能需要一些时间(通常是几秒钟)才能生效。
设置 gcloud CLI 工具
GCP 的 CLI 工具称为 gcloud,并且适用于所有操作系统。
在本教程中,我们使用版本 380.0.0,原生安装在 Windows 上,通过 GoogleCloudSDKInstaller.exe 进行安装,并使用了“捆绑 Python”选项。
供参考:如卸载 Google Cloud CLI中所述,您可以通过以下方式找到安装和配置目录:
# installation directory
$ gcloud info --format='value(installation.sdk_root)'
C:\Users\Pascal\AppData\Local\Google\Cloud SDK\google-cloud-sdk
# config directory
$ gcloud info --format='value(config.paths.global_config_dir)'
C:\Users\Pascal\AppData\Roaming\gcloud
我将不使用我的个人 Google 帐号来运行 gcloud
命令,因此我不使用“通常”的初始化过程运行 gcloud init
。相反,我将使用我们之前创建的服务帐号,并按照gcloud auth activate-service-account 的描述激活它,命令如下:
gcloud auth activate-service-account
docker-php-tutorial-deployment@pl-dofroscra-p.iam.gserviceaccount.com
--key-file=./gcp-service-account-key.json --project=pl-dofroscra-p
输出
$ gcloud auth activate-service-account docker-php-tutorial-deployment@
pl-dofroscra-p.iam.gserviceaccount.com --key-file=./gcp-service-account-key.json
--project=pl-dofroscra-p
Activated service account credentials for:
[docker-php-tutorial-deployment@pl-dofroscra-p.iam.gserviceaccount.com]
供参考:因为我们使用的是包含服务帐号 ID 的 json
密钥文件,所以我们也可以在命令中省略 ID,即:
$ gcloud auth activate-service-account --key-file=./gcp-service-account-key.json
--project=pl-dofroscra-p
Activated service account credentials for:
[docker-php-tutorial-deployment@pl-dofroscra-p.iam.gserviceaccount.com]
设置容器注册表
我们将在下一个教程部分中使用 Docker Compose 来运行我们的 PHP 应用程序,并且需要使我们的 Docker 镜像可用在一个容器注册表中。幸运的是,GCP 提供了 Container Registry 产品,它为我们提供了作为 GCP 项目一部分的即用型私有注册表。在使用它之前,必须启用相应的 Google Container Registry API。
您可以在 Cloud Console UI 中的容器注册表下找到容器注册表。
身份验证 Docker
由于容器注册表是私有的,我们在推送 Docker 镜像之前需要进行身份验证。可用的身份验证方法在 GCP 文档“容器注册表身份验证方法”中有描述。要从本地主机系统推送镜像,我们将使用我们之前创建的服务帐号密钥文件,并运行文档中“JSON 密钥文件”部分所示的命令。
key=./gcp-service-account-key.json
cat "$key" | docker login -u _json_key --password-stdin https://gcr.io
成功的身份验证如下所示:
$ cat "$key" | docker login -u _json_key --password-stdin https://gcr.io
Login Succeeded
Logging in with your password grants your terminal complete access to your account.
For better security, log in with a limited-privilege personal access token.
Learn more at https://docs.dockerd.com.cn/go/access-tokens/
那么,运行此命令时到底“发生”了什么?根据docker login 文档:
当您登录时,该命令会将凭据存储在 Linux 上的 $HOME/.docker/config.json 或 Windows 上的 %USERPROFILE%/.docker/config.json 中 [...]
Docker Engine 可以将用户凭据保存在外部凭据存储中,例如操作系统的原生密钥链。 [...]
您需要在 $HOME/.docker/config.json 中指定凭据存储,以告知 Docker Engine 使用它。 [...]
默认情况下,Docker 在每个平台上查找原生二进制文件,即 macOS 上的“
osxkeychain
”,Windows 上的“wincred
”,以及 Linux 上的“pass
”。
换句话说:我无法在任何地方“明文”看到服务帐号密钥文件的内容,但 Docker 将利用操作系统特定的工具安全地存储它们。在我运行 Windows 上的 docker login
命令后,我在 ~/.docker/config.json 中发现了以下内容:
$ cat ~/.docker/config.json
{
"auths": {
"gcr.io": {}
},
"credsStore": "desktop"
}
供参考:“desktop”
似乎是 Wincred 可执行文件的包装器。
将镜像推送到注册表
在本教程中,我们将创建一个非常简单的 nginx
alpine 镜像,它通过以下方式提供一个“Hello world”hello.html 文件:
docker build -t my-nginx -f - . <<EOF
FROM nginx:1.21.5-alpine
RUN echo "Hello world" >> /usr/share/nginx/html/hello.html
EOF
镜像的名称是 my-nginx
。
$ docker image ls | grep my-nginx
my-nginx latest 42dd1608d126 50 seconds ago 23.5MB
为了将镜像推送到注册表,镜像名称必须带有相应的注册表前缀。这对我来说相当令人困惑,因为我本以为可以运行类似这样的命令:
$ docker push my-nginx --registry=gcr.io
unknown flag: --registry
See 'docker push --help'.
但事实并非如此,没有这样的 --registry
选项。更糟糕的是:省略它将导致推送到 docker.io
,这是“默认”注册表。
$ docker push my-nginx
Using default tag: latest
The push refers to repository [docker.io/my-nginx]
根据关于推送和拉取镜像的 GCP 文档,将镜像推送到 GCP 注册表需要以下步骤:
- 标记镜像,包含其在 Container Registry 中的目标路径,以及 gcr.io 注册表主机和项目 ID my-project。
- 推送镜像到注册表。
在我们的例子中,到 Container Registry 的目标路径是:
gcr.io/pl-dofroscra-p
因为 pl-dofroscra-p
是我们之前创建的 GCP 项目的 ID。
完整的镜像名称变成:
gcr.io/pl-dofroscra-p/my-nginx
要推送 my-nginx
镜像,我们必须首先通过docker tag
为它“添加另一个名称”:
$ docker tag my-nginx gcr.io/pl-dofroscra-p/my-nginx
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx latest ba7a2c5faf0d 15 minutes ago 23.5MB
gcr.io/pl-dofroscra-p/my-nginx latest ba7a2c5faf0d 15 minutes ago 23.5MB
然后在之后推送该名称:
$ docker push gcr.io/pl-dofroscra-p/my-nginx
Using default tag: latest
The push refers to repository [gcr.io/pl-dofroscra-p/my-nginx]
134174afa9ad: Preparing
cb7b4430c52d: Preparing
419df8b60032: Preparing
0e835d02c1b5: Preparing
5ee3266a70bd: Preparing
3f87f0a06073: Preparing
1c9c1e42aafa: Preparing
8d3ac3489996: Preparing
8d3ac3489996: Waiting
3f87f0a06073: Waiting
1c9c1e42aafa: Waiting
cb7b4430c52d: Pushed
134174afa9ad: Pushed
419df8b60032: Pushed
5ee3266a70bd: Pushed
0e835d02c1b5: Pushed
8d3ac3489996: Layer already exists
3f87f0a06073: Pushed
1c9c1e42aafa: Pushed
latest: digest: sha256:0740591fb686227d8cdf4e42b784f634cbaf9f5caa6ee478e3bcc24aeef75d7f
size: 1982
然后您可以在Container Registry UI中找到该镜像。
不用担心:我们不必每次推送前都进行标记,因为我们将在下一个部分中设置 make
以自动使用正确的名称来构建镜像。
镜像存储在 Google Cloud Storage 存储桶中
我们先前已将 Storage Admin
角色分配给服务帐号,其中包含 storage.buckets.create
权限。如果我们没有这样做,就会出现以下错误:
denied: Token exchange failed for project 'pl-dofroscra-p'.
Caller does not have permission 'storage.buckets.create'.
To configure permissions, follow instructions at:
https://cloud.google.com/container-registry/docs/access-control
Container Registry 尝试将 Docker 镜像存储在 Google Cloud Storage 存储桶中,该存储桶在推送第一个镜像时即时创建,请参阅关于“添加注册表”的 GCP 文档。
推送到某个主机名的第一个镜像会触发在该项目中创建注册表以及相应的 Cloud Storage 存储桶。首次推送需要项目范围的权限来创建存储桶。
您可以在Cloud Storage UI中找到存储桶,在我的情况下,该存储桶名为 artifacts.pl-dofroscra-p.appspot.com
。
注意:请确保在完成教程后删除此存储桶 - 否则将会产生存储费用。
由于技术限制,本文篇幅限制为 30000 个字符。请访问 GCP 计算实例虚拟机用于 Docker 化应用的入门指南 [教程第八部分] 阅读全部内容。