如何在 DigitalOcean Spaces 之上设置私有 Docker Registry 并将其与 DigitalOcean Kubernetes 一起使用

作为Write for DOnations计划的一部分,作者选择了免费和开源基金来接受捐赠

介绍

一个码头工人的注册表是名为泊坞图像,这是集装箱应用的行业标准的存储和内容传送系统。与公共镜像相比,私有 Docker 注册表允许您在团队或组织内安全地共享您的镜像,具有更大的灵活性和控制力。通过将私有 Docker 注册表直接托管在 Kubernetes 集群中,您可以获得更高的速度、更低的延迟和更好的可用性,同时控制注册表。

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

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

先决条件

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

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

第 1 步 – 配置和安装 Docker Registry

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

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

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

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

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

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

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

  • mkdir ~/k8s-registry

通过运行导航到它:

  • cd ~/k8s-registry

git通过运行以下命令下载 Container Registry 存储库

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

输出将类似于:

Output
Cloning 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

最终输出将如下所示:

Output
The 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

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

chart_values.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。Ingress 对象使外部 HTTP/HTTPS 路由指向集群中的内部服务,从而允许来自外部的通信。覆盖的值是:

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

然后,您将文件系统存储设置为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

您将看到以下输出:

Output
NAME: 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 注册表推送和拉取镜像来测试新部署的 Docker 注册表。目前,注册表是空的。要推送某些内容,您需要在您工作的机器上有一个可用的图像。mysql为此,让我们使用Docker 映像。

首先mysql从 Docker Hub取:

  • docker pull mysql

您的输出将如下所示:

Output
Using 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

选择并复制显示的内容。

要添加验证您多克尔注册表,你需要编辑chart_values.yaml和添加内容htpasswd_filehtpasswd变量。

打开chart_values.yaml编辑:

  • nano chart_values.yaml

找到如下所示的行:

chart_values.yaml
  htpasswd: ""

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

chart_values.yaml
  htpasswd: |-
    htpasswd_file_contents

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

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

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

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

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

Output
Release "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 并指示它在应用文件升级现有版本,在您的情况下docker-registry,其图表stable/docker-registry在图表存储库中定义chart_values.yaml

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

  • docker pull registry.your_domain/mysql

输出将如下所示:

Output
Using 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

输出将类似于以下内容:

Output
Using 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

您将看到以下输出:

Output
secret/regcred created

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

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

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

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

您可以通过指定imagePullSecrets. 当 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,以使集群外部可以访问该应用程序。添加以下行,用您的域替换突出显示的行:

你好-world.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 部署定义入口,您将通过 Nginx 入口控制器拥有的负载均衡器路由该入口。然后,您定义一个可以访问部署中创建的 pod 的服务。在实际部署规范中,您将 指定image为位于您的注册表中的那个,并设置imagePullSecretsregcred您在上一步中创建的 。

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

  • kubectl apply -f hello-world.yaml

您将看到以下输出:

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

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

你好世界页面

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

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

  • kubectl delete -f hello-world.yaml

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

结论

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

觉得文章有用?

点个广告表达一下你的爱意吧 !😁