作者选择了自由和开源基金作为Write for DOnations计划的一部分进行捐赠。
介绍
Docker注册表是用于命名Docker镜像的存储和内容交付系统,它是容器化应用程序的行业标准。 与公共数据库相比,私有Docker注册表允许您在团队或组织内安全地共享您的图像,具有更大的灵活性和控制力。 通过直接在Kubernetes集群中托管您的私有Docker注册表,您可以实现更高的速度,更低的延迟和更好的可用性,同时控制注册表。
底层注册表存储委托给外部驱动程序。 默认存储系统是本地文件系统,但您可以将其交换为基于云的存储驱动程序。 DigitalOcean Spaces是一个S3兼容的对象存储,专为需要可扩展,简单且经济实惠的方式存储和提供大量数据的开发人员团队和企业而设计,非常适合存储Docker镜像。 它有一个内置的CDN网络,可以在频繁访问图像时大大减少延迟。
在本教程中,您将使用Helm将您的私有Docker注册表部署到DigitalOcean Kubernetes集群,由DigitalOcean Spaces备份以存储数据。 您将为指定的Space创建API密钥,使用自定义配置将Docker注册表安装到您的群集,配置Kubernetes以对其进行适当的身份验证,并通过在群集上运行示例部署来对其进行测试。 在本教程结束时,您将在DigitalOcean Kubernetes集群上安装一个安全的私有Docker注册表。
先决条件
在开始本教程之前,您需要:
Docker安装在您将从中访问群集的计算机上。 对于Ubuntu 18.04,请访问如何在Ubuntu 18.04上安装和使用Docker 。 您只需完成第一步。 否则,请访问Docker的网站以获取其他发行版。
DigitalOcean Kubernetes集群,其连接配置配置为
kubectl
默认值。 有关如何配置kubectl
的说明显示在创建群集时显示的“ 连接到群集”步骤下。 要了解如何在DigitalOcean上创建Kubernetes集群,请参阅Kubernetes快速入门 。带有API密钥的DigitalOcean Space(访问和秘密)。 要了解如何创建DigitalOcean Space和API密钥,请参阅如何创建DigitalOcean Space和API密钥 。
Helm软件包管理器安装在本地计算机上,并且Tiller安装在您的集群上。 使用Helm Package Manager完成如何在Kubernetes群集上安装软件的第1步和2。 您只需要完成前两个步骤。
Nginx Ingress Controller和Cert-Manager安装在群集上。 有关如何执行此操作的指南,请参阅如何在DigitalOcean Kubernetes上使用Cert-Manager设置Nginx Ingress 。
具有两个DNS A记录的域名,指向Ingress使用的DigitalOcean负载均衡器。 如果您使用DigitalOcean管理域的DNS记录,请参阅如何管理DNS记录以创建A记录。 在本教程中,我们将A记录称为
registry.example.com
和k8s-test.example.com
。
第1步 – 配置和安装Docker Registry
在此步骤中,您将为注册表部署创建配置文件,并使用Helm软件包管理器将Docker注册表安装到具有给定配置的集群。
在本教程中,您将使用名为chart_values.yaml
的配置文件来覆盖Docker注册表Helm 图表的某些默认设置。 赫尔姆称其包裹,图表; 这些是概述相关Kubernetes资源选择的文件集。 您将编辑设置以将DigitalOcean Spaces指定为基础存储系统,并通过连接Let的加密TLS证书来启用HTTPS访问。
作为先决条件的一部分,您将创建echo1
和echo2
服务以及echo_ingress
入口以进行测试; 在本教程中您不需要这些,因此您现在可以删除它们。
首先通过运行以下命令删除入口:
kubectl delete -f echo_ingress.yaml
然后,删除两个测试服务:
kubectl delete -f echo1.yaml && kubectl delete -f echo2.yaml
kubectl delete
命令在传递-f
参数时接受要删除的文件。
创建一个将用作工作区的文件夹:
mkdir ~/k8s-registry
通过运行导航到它:
cd ~/k8s-registry
现在,使用文本编辑器创建chart_values.yaml
文件:
nano chart_values.yaml
添加以下行,确保使用您的详细信息替换突出显示的行:
ingress: enabled: true hosts: - registry.example.com annotations: kubernetes.io/ingress.class: nginx certmanager.k8s.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/proxy-body-size: "30720m" tls: - secretName: letsencrypt-prod hosts: - registry.example.comstorage: s3secrets: 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
第一个块, ingress
,配置将作为Helm图表部署的一部分创建的Kubernetes Ingress。 Ingress对象使外部HTTP / HTTPS路由指向群集中的内部服务,从而允许来自外部的通信。 被覆盖的值为:
-
enabled
:设置为true
以启用Ingress。 -
hosts
:Ingress将接受流量的主机列表。 -
annotations
:元数据列表,为Kubernetes的其他部分提供有关如何对待Ingress的进一步指导。 您将Ingress Controller设置为nginx
,将Let的加密集群发行者设置为生产变体(letsencrypt-prod
),并告诉nginx
控制器接受最大大小为30 GB的文件,这对即使是最大的Docker镜像也是一个合理的限制。 -
tls
:此子类别配置Let的加密HTTPS。 您填充hosts
列表,该列表定义此Ingress将使用我们的示例域名接受HTTPS流量的安全主机。
然后,将文件系统存储设置为s3
– 另一个可用选项是filesystem
。 这里s3
表示使用与DigitalOcean Spaces满足的行业标准Amazon S3 API兼容的远程存储系统。
在下一个块中,您可以配置密钥以访问s3
子类别下的DO空间。 最后,在s3
块中,配置指定Space的参数。
保存并关闭您的文件。
现在,如果您还没有这样做,请将A记录设置为指向您在先决条件教程中作为Nginx Ingress Controller安装的一部分创建的Load Balancer。 要了解如何在DigitalOcean上设置DNS,请参阅如何管理DNS记录 。
接下来,确保您的Space不为空。 如果您的Space中没有任何文件,Docker注册表将根本不运行。 要解决此问题,请上传文件。 导航到Spaces选项卡,找到您的Space,单击Upload File按钮,然后上传您想要的任何文件。 您可以上传刚刚创建的配置文件。
在通过Helm安装任何内容之前,您需要刷新其缓存。 这将更新有关您的图表存储库的最新信息。 为此,请运行以下命令:
helm repo update
现在,您将通过运行Helm,使用此自定义配置部署Docker注册表图表:
helm install stable/docker-registry -f chart_values.yaml --name docker-registry
您将看到以下输出:
NAME: docker-registry...NAMESPACE: defaultSTATUS: DEPLOYEDRESOURCES:==> v1/ConfigMapNAME DATA AGEdocker-registry-config 1 1s==> v1/Pod(related)NAME READY STATUS RESTARTS AGEdocker-registry-54df68fd64-l26fb 0/1 ContainerCreating 0 1s==> v1/SecretNAME TYPE DATA AGEdocker-registry-secret Opaque 3 1s==> v1/ServiceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEdocker-registry ClusterIP 10.245.131.143 <none> 5000/TCP 1s==> v1beta1/DeploymentNAME READY UP-TO-DATE AVAILABLE AGEdocker-registry 0/1 1 0 1s==> v1beta1/IngressNAME HOSTS ADDRESS PORTS AGEdocker-registry registry.example.com 80, 443 1sNOTES:1. Get the application URL by running these commands: https://registry.example.com/
Helm列出了由于Docker注册表图表部署而创建的所有资源。 现在可以从您之前指定的域名访问注册表。
您已在Kubernetes群集上配置并部署了Docker注册表。 接下来,您将测试新部署的Docker注册表的可用性。
第2步 – 测试推动和拉动
在此步骤中,您将通过推送和从中拉出图像来测试新部署的Docker注册表。 目前,注册表是空的。 要想要推动某些东西,您需要在您正在使用的机器上提供图像。 我们来使用mysql
Docker镜像。
首先从Docker Hub中提取mysql
:
sudo docker pull mysql
您的输出将如下所示:
Using default tag: latestlatest: Pulling from library/mysql27833a3ba0a5: Pull complete...e906385f419d: Pull completeDigest: sha256:a7cf659a764732a27963429a87eccc8457e6d4af0ee9d5140a3b56e74986eed7Status: Downloaded newer image for mysql:latest
您现在可以在本地使用该图像。 要通知Docker在哪里推送它,您需要使用主机名标记它,如下所示:
sudo docker tag mysql registry.example.com/mysql
然后,将图像推送到新的注册表:
sudo docker push registry.example.com/mysql
此命令将成功运行并指示您的新注册表已正确配置并接受流量 – 包括推送新映像。 如果您看到错误,请仔细检查第1步和2的步骤。
要干净地测试从注册表中提取,请首先使用以下命令删除本地mysql
映像:
sudo docker rmi registry.example.com/mysql && sudo docker rmi mysql
然后,从注册表中提取它:
sudo docker pull registry.example.com/mysql
此命令将需要几秒钟才能完成。 如果它成功运行,则表示您的注册表正常运行。 如果显示错误,请仔细检查您对先前命令输入的内容。
您可以通过运行以下命令列出本地可用的Docker映像:
sudo docker images
您将看到输出列出本地计算机上可用的图像,以及它们的ID和创建日期。
您的Docker注册表已配置。 您已将图像推送到该图像并验证您可以将其拉下来。 现在让我们添加身份验证,这样只有特定的人才能访问代码。
第3步 – 添加帐户身份验证和配置Kubernetes访问
在此步骤中,您将使用htpasswd
实用程序为注册表设置用户名和密码身份验证。
htpasswd
实用程序来自Apache Web服务器,您可以使用它来创建存储用户名和密码的文件,以便对HTTP用户进行基本身份验证。 htpasswd
文件的格式是username:hashed_password
(每行一个),它足够便携,允许其他程序也使用它。
要使htpasswd
在系统上可用,您需要通过运行以下命令来安装它:
sudo apt install apache2-utils -y
注意: 如果您是从Mac运行本教程,则需要使用以下命令在您的计算机上使用htpasswd
:
docker run --rm -v ${PWD}:/app -it httpd htpasswd -b -c /app/htpasswd_file sammy password
通过执行以下命令创建它:
touch htpasswd_file
将用户名和密码组合添加到htpasswd_file
:
htpasswd -B htpasswd_file username
Docker需要使用bcrypt算法对密码进行哈希处理,这就是我们传递-B
参数的原因。 bcrypt算法是基于Blowfish分组密码的密码散列函数,具有工作因子参数,该参数指定散列函数的成本。
请记住用您想要的用户名替换username
名。 运行时, htpasswd
会询问您是否附带密码并将组合添加到htpasswd_file
。 您可以为要添加的用户重复此命令。
现在,通过运行以下命令显示htpasswd_file
的内容:
cat htpasswd_file
选择并复制显示的内容。
要向Docker注册表添加身份验证,您需要编辑chart_values.yaml
并在htpasswd
变量中添加htpasswd_file
的内容。
打开chart_values.yaml
进行编辑:
nano chart_values.yaml
找到如下所示的行:
htpasswd: ""
编辑它以匹配以下内容,将htpasswd\_file\_contents
替换为您从htpasswd_file
复制的内容:
htpasswd: |- htpasswd_file_contents
小心缩进,文件内容的每一行必须在它之前有四个空格。
添加完内容后,保存并关闭文件。
要将更改传播到群集,请运行以下命令:
helm upgrade docker-registry stable/docker-registry -f chart_values.yaml
输出将类似于第一次部署Docker注册表时显示的输出:
Release "docker-registry" has been upgraded. Happy Helming!LAST DEPLOYED: ...NAMESPACE: defaultSTATUS: DEPLOYEDRESOURCES:==> v1/ConfigMapNAME DATA AGEdocker-registry-config 1 3m8s==> v1/Pod(related)NAME READY STATUS RESTARTS AGEdocker-registry-6c5bb7ffbf-ltnjv 1/1 Running 0 3m7s==> v1/SecretNAME TYPE DATA AGEdocker-registry-secret Opaque 4 3m8s==> v1/ServiceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEdocker-registry ClusterIP 10.245.128.245 <none> 5000/TCP 3m8s==> v1beta1/DeploymentNAME READY UP-TO-DATE AVAILABLE AGEdocker-registry 1/1 1 1 3m8s==> v1beta1/IngressNAME HOSTS ADDRESS PORTS AGEdocker-registry registry.example.com 159.89.215.50 80, 443 3m8sNOTES:1. Get the application URL by running these commands: https://registry.example.com/
此命令调用Helm并指示它在应用chart_values.yaml
文件后,使用其在图表存储库中的stable/docker-registry
中定义的图表升级现有版本(在您的情况下为chart_values.yaml
stable/docker-registry
。
现在,您将尝试再次从注册表中提取图像:
sudo docker pull registry.example.com/mysql
输出将如下所示:
Using default tag: latestError response from daemon: Get https://registry.example.com/v2/mysql/manifests/latest: no basic auth credentials
它正确失败,因为您没有提供凭据。 这意味着您的Docker注册表正确授权请求。
要登录注册表,请运行以下命令:
sudo docker login registry.example.com
请记住将registry.example.com
替换为您的域名地址。 它会提示您输入用户名和密码。 如果显示错误,请仔细检查htpasswd_file
包含的内容。 您必须在此步骤中先前创建的htpasswd_file
定义用户名和密码组合。
要测试登录,可以尝试通过运行以下命令再次执行:
sudo docker pull registry.example.com/mysql
输出类似于以下内容:
Using default tag: latestlatest: Pulling from mysqlDigest: sha256:f2dc118ca6fa4c88cde5889808c486dfe94bccecd01ca626b002a010bb66bcbeStatus: Image is up to date for registry.example.com/mysql:latest
您现在已经配置了Docker并且可以安全登录。 要配置Kubernetes以登录到注册表,请运行以下命令:
sudo kubectl create secret generic regcred --from-file=.dockerconfigjson=/home/sammy/.docker/config.json --type=kubernetes.io/dockerconfigjson
您将看到以下输出:
secret/regcred created
此命令在集群中创建一个名为regcred
的秘密,获取Docker存储凭据的JSON文件的内容,并将其解析为dockerconfigjson
,它定义了Kubernetes中的注册表凭据。
您已使用htpasswd
创建登录配置文件,配置注册表以验证请求,并创建包含登录凭据的Kubernetes机密。 接下来,您将测试Kubernetes集群和注册表之间的集成。
第4步 – 通过运行示例部署来测试Kubernetes集成
在此步骤中,您将运行一个示例部署,其中包含存储在群集内注册表中的映像,以测试Kubernetes群集和注册表之间的连接。
在最后一步中,您创建了一个名为regcred
的机密,其中包含私有注册表的登录凭据。 它可能包含多个注册表的登录凭据,在这种情况下,您必须相应地更新Secret。
您可以通过指定imagePullSecrets
指定在pod定义中拉取容器时Kubernetes应使用的秘密。 当Docker注册表需要身份验证时,此步骤是必需的。
您现在将从私有Docker注册表部署示例Hello World映像到您的群集。 首先,为了推送它,您可以通过运行以下命令将其拉到您的机器:
sudo docker pull paulbouwer/hello-kubernetes:1.5
然后,通过运行标记它:
sudo docker tag paulbouwer/hello-kubernetes:1.5 registry.example.com/paulbouwer/hello-kubernetes:1.5
最后,将其推送到您的注册表:
sudo docker push registry.example.com/paulbouwer/hello-kubernetes:1.5
在您的机器上删除它,因为您不再需要它在本地:
sudo docker rmi registry.example.com/paulbouwer/hello-kubernetes:1.5
现在,您将部署示例Hello World应用程序。 首先,使用文本编辑器创建一个新文件hello-world.yaml
:
nano hello-world.yaml
接下来,您将定义服务和Ingress,以使应用程序可以在群集外部访问。 添加以下行,用您的域替换突出显示的行:
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: hello-kubernetes-ingress annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: /spec: rules: - host: k8s-test.example.com http: paths: - path: / backend: serviceName: hello-kubernetes servicePort: 80---apiVersion: v1kind: Servicemetadata: name: hello-kubernetesspec: type: NodePort ports: - port: 80 targetPort: 8080 selector: app: hello-kubernetes---apiVersion: apps/v1kind: Deploymentmetadata: name: hello-kubernetesspec: replicas: 3 selector: matchLabels: app: hello-kubernetes template: metadata: labels: app: hello-kubernetes spec: containers: - name: hello-kubernetes image: registry.example.com/paulbouwer/hello-kubernetes:1.5 ports: - containerPort: 8080 imagePullSecrets: - name: regcred
首先,为Hello World部署定义Ingress,您将通过Nginx Ingress Controller拥有的Load Balancer进行路由。 然后,您定义可以访问在部署中创建的pod的服务。 在实际部署规范中,您将image
指定为位于注册表中的image
,并将imagePullSecrets
设置为regcred
,这是您在上一步中创建的。
保存并关闭文件。 要将其部署到群集,请运行以下命令:
kubectl apply -f hello-world.yaml
您将看到以下输出:
ingress.extensions/hello-kubernetes-ingress createdservice/hello-kubernetes createddeployment.apps/hello-kubernetes created
您现在可以导航到您的测试域 – 本教程中的第二个A记录k8s-test.example.com
。 你会看到Kubernetes Hello世界! 页。
Hello World页面列出了一些环境信息,例如Linux内核版本和请求服务的pod的内部ID。 您还可以通过Web界面访问您的Space,以查看您在本教程中使用过的图像。
如果要在测试后删除此Hello World部署,请运行以下命令:
kubectl delete -f hello-world.yaml
您已经创建了一个示例Hello World部署,以测试Kubernetes是否正确地从您的私有注册表中提取图像。
结论
您现在已经在DigitalOcean Kubernetes集群上成功部署了自己的私有Docker注册表,使用DigitalOcean Spaces作为下面的存储层。 您可以存储的图像数量没有限制,Spaces可以无限延伸,同时提供相同的安全性和稳健性。 但是,在生产中,您应该始终尽可能地优化Docker镜像,请参阅如何优化Docker镜像以进行生产教程。