如何在DigitalOceanSpaces之上设置私有Docker注册表并将其与DigitalOceanKubernetes一起使用

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。

介绍

Docker 注册表 是用于命名 Docker 映像的存储和内容交付系统,它是容器化应用程序的行业标准。 与公共 Docker 注册表相比,私有 Docker 注册表允许您在团队或组织内安全地共享映像,具有更大的灵活性和控制力。 通过将私有 Docker 注册表直接托管在 Kubernetes 集群中,您可以获得更高的速度、更低的延迟和更好的可用性,同时还能控制注册表。

底层注册表存储委托给外部驱动程序。 默认存储系统是本地文件系统,但您可以将其换成基于云的存储驱动程序。 DigitalOcean Spaces 是一种兼容 S3 的对象存储,专为需要可扩展、简单且经济实惠的方式来存储和服务大量数据的开发人员团队和企业而设计,非常适合存储 Docker 映像。 它内置CDN网络,在频繁访问图片时可以大大降低延迟。

在本教程中,您将使用 Helm 将私有 Docker 注册表部署到 DigitalOcean Kubernetes 集群,并由 DigitalOcean Spaces 备份以存储数据。 您将为您指定的空间创建 API 密钥,使用自定义配置将 Docker 注册表安装到您的集群,配置 Kubernetes 以对其进行正确身份验证,并通过在集群上运行示例部署对其进行测试。 在本教程结束时,您将在 DigitalOcean Kubernetes 集群上安装一个安全的私有 Docker 注册表。

先决条件

在开始本教程之前,您需要:

  • Docker 安装在您将从中访问集群的机器上。 对于 Ubuntu 18.04,请访问 如何在 Ubuntu 18.04 上安装和使用 Docker。 您只需完成Step 1Step 2。 否则,请访问 Docker 的 网站 了解其他发行版。

  • Docker Hub 上的一个帐户,用于存储您将在本教程中创建的 Docker 映像。

  • Git 安装在您将用于访问集群的计算机上。 对于 Ubuntu 18.04,请遵循 如何在 Ubuntu 18.04 上安装 Git 教程的 Step 1。 其他平台请访问【X31X】官网【X51X】。

  • 一个 DigitalOcean Kubernetes 集群,您的连接配置配置为 kubectl 默认值。 如何配置 kubectl 的说明显示在创建集群时显示的 连接到集群 步骤下。 要了解如何在 DigitalOcean 上创建 Kubernetes 集群,请参阅 Kubernetes 快速入门

  • 带有 API 密钥(访问和秘密)的 DigitalOcean 空间。 要了解如何创建 DigitalOcean Space 和 API 密钥,请参阅 如何创建 DigitalOcean Space 和 API 密钥

  • 安装在本地计算机上的 Helm 包管理器。 为此,请完成 如何使用 Helm 3 包管理器 教程在 Kubernetes 集群上安装软件的 步骤 1

  • 安装在集群上的 Nginx Ingress Controller 和 Cert-Manager。 有关如何执行此操作的指南,请参阅 如何使用 Helm 在 DigitalOcean Kubernetes 上设置 Nginx 入口。

  • 具有两个 DNS A 记录的域名指向 Ingress 使用的 DigitalOcean 负载均衡器。 如果您使用 DigitalOcean 管理您域的 DNS 记录,请参考 如何管理 DNS 记录 创建 A 记录。 在本教程中,我们将 A 记录称为 registry.your_domaink8s-test.your_domain

    注意:本教程中使用的域名必须与如何在DigitalOcean Kubernetes先决条件教程中设置Nginx Ingress中使用的域名不同。

第 1 步 — 配置和安装 Docker 注册表

在此步骤中,您将为注册表部署创建一个配置文件,并使用 Helm 包管理器使用给定的配置将注册表安装到您的集群中。

在本教程的过程中,您将使用一个名为 chart_values.yaml 的配置文件来覆盖 Docker 注册表 Helm chart 的一些默认设置。 Helm 将其包称为图表; 这些文件集概述了 Kubernetes 资源的相关选择。 您将编辑设置以将 DigitalOcean Spaces 指定为底层存储系统,并通过连接 Let's Encrypt TLS 证书来启用 HTTPS 访问。

作为 Nginx 入口控制器先决条件的一部分,您创建了示例服务和入口。 在本教程中您将不需要它们,因此您可以通过运行以下命令来删除它们:

kubectl delete -f hello-kubernetes-first.yaml
kubectl delete -f hello-kubernetes-second.yaml
kubectl delete -f hello-kubernetes-ingress.yaml

kubectl delete 命令在传递 -f 参数时接受要删除的文件。

我们将使用 GitLab 的 Container Registry 分支,而不是使用与 S3 存储提供程序存在问题的官方 Docker 注册表,您需要下载和构建它。

创建一个文件夹作为您的工作区:

mkdir ~/k8s-registry

通过运行导航到它:

cd ~/k8s-registry

通过运行以下命令,使用 git 下载 Container Registry 存储库:

git clone https://gitlab.com/gitlab-org/container-registry.git

输出将与此类似:

OutputCloning into 'container-registry'...
remote: Enumerating objects: 1706, done.
...
Resolving deltas: 100% (13955/13955), done.

存储库现在位于 container-registry 目录中。 导航到它:

cd container-registry

您现在拥有容器注册表的源代码。 要在集群中使用它,您需要从中构建 Docker 映像并将其推送到公共注册表,例如 Docker Hub。

运行以下命令切换到最新稳定版本的分支:

git checkout v2.13.1-gitlab

运行以下命令来构建注册表的 Docker 映像,将 your_dockerhub_username 替换为您的 Docker Hub 用户名:

docker build -t your_dockerhub_username/registry:dev .

此命令可能需要一些时间才能完成。 输出会很长,应该类似于:

Output...
Successfully built 27322ec15cf7
Successfully tagged your_dockerhub_username/registry:dev

现在镜像已经构建好了,要推送到你的账户,你首先需要登录:

docker login

出现提示时输入您的 Docker Hub 用户名和密码。 输出的结尾应如下所示:

Output...
Login Succeeded

您现在可以推送图像:

docker push your_dockerhub_username/registry:dev

最终输出将如下所示:

OutputThe push refers to repository [docker.io/your_dockerhub_username/registry]
c3baf7582a54: Pushed
bc49969a328b: Pushed
0694fbf8288a: Pushed
3e207b409db3: Mounted from library/alpine
dev: digest: sha256:02399157107a1d72312fb4f383f4c8c53a08f3e206d787a9c9380f446b008184 size: 1156

现在您已经构建并推送了注册表,导航回您的工作区:

cd ~/k8s-registry

使用您喜欢的文本编辑器创建您的 chart_values.yaml 文件:

nano chart_values.yaml

添加以下行,确保将突出显示的行替换为您的详细信息:

图表值.yaml

ingress:
  enabled: true
  hosts:
    - registry.your_domain
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/proxy-body-size: "30720m"
  tls:
    - secretName: docker-registry-prod
      hosts:
        - registry.your_domain

storage: s3

secrets:
  htpasswd: ""
  s3:
    accessKey: "your_space_access_key"
    secretKey: "your_space_secret_key"

s3:
  region: your_space_region
  regionEndpoint: your_space_region.digitaloceanspaces.com
  secure: true
  bucket: your_space_name

image:
  repository: your_dockerhub_username/registry
  tag: dev

第一个块 ingress 配置将作为 Helm 图表部署的一部分创建的 Kubernetes 入口。 Ingress 对象使外部 HTTP/HTTPS 路由指向集群中的内部服务,从而允许来自外部的通信。 被覆盖的值为:

  • enabled:设置为 true 以启用 Ingress。
  • hosts:Ingress 将接受来自其的流量的主机列表。
  • annotations:元数据列表,为 Kubernetes 的其他部分提供有关如何处理 Ingress 的进一步指导。 您将 Ingress Controller 设置为 nginx,将 Let's Encrypt 集群颁发者设置为生产变体 (letsencrypt-prod),并告诉 nginx 控制器接受最大大小为 30 的文件GB,即使是最大的 Docker 镜像,这也是一个合理的限制。
  • tls:此子类别配置 Let's Encrypt HTTPS。 您使用我们的示例域名填充 hosts 列表,该列表定义此 Ingress 将接受来自哪些安全主机的 HTTPS 流量。 secretName(此处设置为 docker-registry-prod)指定将存储证书的密钥的名称,通常对于您创建或部署的每个 Ingress 都必须不同。

然后,将文件系统存储设置为 s3 — 另一个可用选项是 filesystem。 这里的 s3 表示使用与 DigitalOcean Spaces 满足的行业标准 Amazon S3 API 兼容的远程存储系统。

在下一个块 secrets 中,您配置用于访问 s3 子类别下的 DO 空间的密钥。 最后,在 s3 块中,配置指定空间的参数。

在文件末尾,您将刚刚推送的注册表映像指定为将要部署的映像,而不是官方的 Docker 注册表。

保存并关闭文件。

现在,如果您还没有这样做,请将您的 A 记录设置为指向您在先决条件教程中作为 Nginx Ingress Controller 安装的一部分创建的负载均衡器。 要了解如何在 DigitalOcean 上设置 DNS,请参阅 如何管理 DNS 记录

部署 Docker 注册表的图表位于 twuni 存储库中。 通过运行将其添加到 Helm:

helm repo add twuni https://helm.twun.io

在从它安装任何东西之前,您需要刷新它的缓存。 这将更新有关图表存储库的最新信息。 为此,请运行以下命令:

helm repo update

现在,您将通过运行以下命令通过 Helm 使用此自定义配置部署 Docker 注册表图表:

helm install docker-registry twuni/docker-registry -f chart_values.yaml

您将看到以下输出:

OutputNAME: docker-registry
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
  https://registry.your_domain/

现在可以从您之前指定的域名访问注册表。

您已在 Kubernetes 集群上配置并部署了 Docker 注册表。 接下来,您将测试新部署的 Docker 注册表的可用性。

第 2 步 — 测试推拉

在此步骤中,您将通过在其中推送和拉取镜像来测试新部署的 Docker 注册表。 目前,注册表是空的。 要推送一些内容,您需要在您正在使用的机器上提供可用的图像。 让我们为此目的使用 mysql Docker 映像。

从 Docker Hub 中拉出 mysql 开始:

docker pull mysql

您的输出将如下所示:

OutputUsing default tag: latest
latest: Pulling from library/mysql
27833a3ba0a5: Pull complete
...
e906385f419d: Pull complete
Digest: sha256:9643e9fbd6330d10686f8922292dcb20995e7b792c17d4e94ddf95255f1d5449
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest

您现在可以在本地使用该图像。 要通知 Docker 将其推送到何处,您需要使用主机名对其进行标记,如下所示:

docker tag mysql registry.your_domain/mysql

然后,将镜像推送到新的注册表:

docker push registry.your_domain/mysql

此命令将成功运行并表明您的新注册表已正确配置并接受流量——包括推送新图像。 如果您看到错误,请根据步骤 1 和 2 仔细检查您的步骤。

要测试从注册表中是否干净地拉取,首先使用以下命令删除本地 mysql 图像:

docker rmi registry.your_domain/mysql && docker rmi mysql

然后,从注册表中拉取它:

docker pull registry.your_domain/mysql

此命令将需要几秒钟才能完成。 如果它成功运行,这意味着您的注册表工作正常。 如果显示错误,请根据之前的命令仔细检查您输入的内容。

您可以通过运行以下命令列出本地可用的 Docker 映像:

docker images

您将看到列出本地计算机上可用图像的输出,以及它们的 ID 和创建日期。

您的 Docker 注册表已配置。 您已将图像推送到它并验证您可以将其拉下。 现在让我们添加身份验证,以便只有某些人可以访问图像。

第 3 步 - 添加帐户身份验证和配置 Kubernetes 访问权限

在此步骤中,您将使用 htpasswd 实用程序为注册表设置用户名和密码验证。

htpasswd 实用程序来自 Apache 网络服务器,您可以使用它来创建存储用户名和密码的文件,以便对 HTTP 用户进行基本身份验证。 htpasswd 文件的格式是 username:hashed_password(每行一个),它的可移植性足以让其他程序也可以使用它。

为简单起见,您将使用 htpasswd 的 Dockerized 变体。 运行以下命令将登录组合附加到 htpasswd_file,将 usernamepassword 替换为所需的凭据:

docker run --rm -ti xmartlabs/htpasswd username password >> htpasswd_file

Docker 要求使用 bcrypt 算法对密码进行哈希处理,此处隐式使用该算法。 bcrypt 算法是基于 Blowfish 分组密码的密码散列函数,具有 工作因子 参数,指定散列函数的成本。

您可以为希望添加的用户重复此命令。

完成后,通过运行以下命令显示 htpasswd_file 的内容:

cat htpasswd_file

选择并复制显示的内容。

要将身份验证添加到 Docker 注册表,您需要编辑 chart_values.yaml 并将 htpasswd_file 的内容添加到 htpasswd 变量中。

打开chart_values.yaml进行编辑:

nano chart_values.yaml

找到如下所示的行:

图表值.yaml

  htpasswd: ""

编辑它以匹配以下内容,将 htpasswd\_file\_contents 替换为您从 htpasswd_file 复制的内容:

图表值.yaml

  htpasswd: |-
    htpasswd_file_contents

注意缩进,文件内容的每一行前面必须有四个空格。 您可以删除空行(如果有)。

添加内容后,保存并关闭文件。

要将更改传播到您的集群,请运行以下命令:

helm upgrade docker-registry twuni/docker-registry -f chart_values.yaml

输出将类似于您第一次部署 Docker 注册表时显示的输出:

OutputRelease "docker-registry" has been upgraded. Happy Helming!
NAME: docker-registry
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
  https://registry.your_domain/

此命令调用 Helm 并指示它在应用 chart_values.yaml 文件后升级现有版本,在您的情况下为 docker-registry,其图表在图表存储库的 stable/docker-registry 中定义。

现在,您将尝试再次从注册表中提取图像:

docker pull registry.your_domain/mysql

输出将如下所示:

OutputUsing default tag: latest
Error response from daemon: Get https://registry.your_domain/v2/mysql/manifests/latest: no basic auth credentials

它正确地失败了,因为您没有提供凭据。 这意味着您的 Docker 注册表正确授权请求。

要登录注册表,请运行以下命令:

docker login registry.your_domain

请记住将 registry.your_domain 替换为您的域地址。 它会提示您输入用户名和密码。 如果显示错误,请仔细检查 htpasswd_file 包含的内容。 您必须从您在此步骤前面创建的 htpasswd_file 中指定用户名和密码组合。

要测试登录,您可以通过运行以下命令再次尝试拉取:

docker pull registry.your_domain/mysql

输出将类似于以下内容:

OutputUsing default tag: latest
latest: Pulling from mysql
Digest: sha256:f2dc118ca6fa4c88cde5889808c486dfe94bccecd01ca626b002a010bb66bcbe
Status: Image is up to date for registry.your_domain/mysql:latest

您现在已经配置了 Docker 并且可以安全地登录。 要配置 Kubernetes 以登录到您的注册表,请运行以下命令:

sudo kubectl create secret docker-registry regcred --docker-server=registry.your_domain --docker-username=your_username --docker-password=your_password

此命令在您的集群中创建一个名为 regcred 的机密,其中将包含您的注册表的登录信息,并将其解析为 dockerconfigjson,它在 Kubernetes 中定义了一个注册表凭据。

请记住将 registry.your_domain 替换为您的注册域,并使用您之前创建的登录凭据之一代替 your_usernameyour_password

您将看到以下输出:

Outputsecret/regcred created

您已经使用 htpasswd 创建了登录配置文件,配置了注册表以验证请求,并创建了包含登录凭据的 Kubernetes 机密。 接下来,您将测试 Kubernetes 集群和注册表之间的集成。

第 4 步 — 通过运行示例部署测试 Kubernetes 集成

在此步骤中,您将使用存储在集群内注册表中的映像运行示例部署,以测试 Kubernetes 集群和注册表之间的连接。

在最后一步中,您创建了一个名为 regcred 的密钥,其中包含您的私有注册表的登录凭据。 它可能包含多个注册表的登录凭据,在这种情况下,您必须相应地更新 Secret。

您可以通过指定 imagePullSecrets 来指定在 pod 定义中拉取容器时 Kubernetes 应该使用哪个 secret。 当 Docker 注册表需要身份验证时,此步骤是必需的。

您现在将从您的私有 Docker 注册表部署示例 Hello World 映像 到您的集群。 首先,为了推送它,您将通过运行以下命令将其拉到您的机器上:

docker pull paulbouwer/hello-kubernetes:1.8

然后,通过运行标记它:

docker tag paulbouwer/hello-kubernetes:1.8 registry.your_domain/paulbouwer/hello-kubernetes:1.8

最后,将其推送到您的注册表:

docker push registry.your_domain/paulbouwer/hello-kubernetes:1.8

从您的机器中删除它,因为您在本地不再需要它:

docker rmi registry.your_domain/paulbouwer/hello-kubernetes:1.8

现在,您将部署示例 Hello World 应用程序。 首先,使用文本编辑器创建一个新文件 hello-world.yaml

nano hello-world.yaml

接下来,您将定义一个 Service 和一个 Ingress,以使应用程序可以在集群外部访问。 添加以下行,将突出显示的行替换为您的域:

你好世界.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: k8s-test.your_domain
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes
            port:
              number: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes
  template:
    metadata:
      labels:
        app: hello-kubernetes
    spec:
      containers:
      - name: hello-kubernetes
        image: registry.your_domain/paulbouwer/hello-kubernetes:1.8
        ports:
        - containerPort: 8080
      imagePullSecrets:
      - name: regcred

首先,您为 Hello World 部署定义 Ingress,您将通过 Nginx Ingress Controller 拥有的负载均衡器对其进行路由。 然后,您定义一个可以访问部署中创建的 pod 的服务。 在实际部署规范中,您将 image 指定为位于注册表中的那个,并将 imagePullSecrets 设置为您在上一步中创建的 regcred

保存并关闭文件。 要将其部署到您的集群,请运行以下命令:

kubectl apply -f hello-world.yaml

您将看到以下输出:

Outputingress.extensions/hello-kubernetes-ingress created
service/hello-kubernetes created
deployment.apps/hello-kubernetes created

您现在可以导航到您的测试域 — 本教程中的第二条 A 记录 k8s-test.your_domain。 您将看到 Kubernetes Hello world! 页面。

Hello World 页面列出了一些环境信息,例如 Linux 内核版本和提供请求的 pod 的内部 ID。 您还可以通过 Web 界面访问您的空间,以查看您在本教程中使用过的图像。

如果要在测试后删除此 Hello World 部署,请运行以下命令:

kubectl delete -f hello-world.yaml

在此步骤中,您创建了一个示例 Hello World 部署,以测试 Kubernetes 是否正确地从您的私有注册表中提取图像。

结论

您现在已经成功地在您的 DigitalOcean Kubernetes 集群上部署了您自己的私有 Docker 注册表,使用 DigitalOcean Spaces 作为下面的存储层。 您可以存储的图像数量没有限制,空间可以无限扩展,同时提供相同的安全性和稳健性。 但是,在生产环境中,您应该尽可能地优化 Docker 映像,请查看 如何优化生产环境的 Docker 映像 教程。