写点什么

Docker 镜像加速教程

发布于: 2021 年 02 月 25 日

原文链接:https://fuckcloudnative.io/posts/docker-registry-proxy/


在使用 Docker 和 Kubernetes 时,我们经常需要访问 gcr.ioquay.io 镜像仓库,由于众所周知的原因,这些镜像仓库在中国都无法访问,唯一能访问的是 Docker Hub,但速度也是奇慢无比。gcr.azk8s.cngcr.io 镜像仓库的代理站点,原来可以通过 gcr.azk8s.cn 访问 gcr.io 仓库里的镜像,但是目前 *.azk8s.cn 已经仅限于 Azure 中国的 IP 使用,不再对外提供服务了。国内其他的镜像加速方案大多都是采用定时同步的方式来缓存,这种方法是有一定延迟的,不能保证及时更新,ustc 和七牛云等镜像加速器我都试过了,非常不靠谱,很多镜像都没有。


为了能够顺利访问 gcr.io 等镜像仓库,我们需要在墙外自己搭建一个类似于 gcr.azk8s.cn 的镜像仓库代理站点。利用 Docker 的开源项目 registry 就可以实现这个需求,registry 不仅可以作为本地私有镜像仓库,还可以作为上游镜像仓库的缓存,也就是 pull through cache


先来感受下速度:






1. 前提条件


  • 一台能够施展魔法的服务器(你懂得,可以直接访问 gcr.io)

  • 一个域名和域名相关的 SSL 证书(docker pull 镜像时需要验证域名证书),一般用 Let's Encrypt 就够了。


2. 核心思路


registry 可以通过设置参数 remoteurl 将其作为远端仓库的缓存仓库,这样当你通过这个私有仓库的地址拉取镜像时,regiistry 会先将镜像缓存到本地存储,然后再提供给拉取的客户端(有可能这两个步骤是同时的,我也不太清楚)。我们可以先部署一个私有 registry,然后将 remoteurl 设为需要加速的镜像仓库地址,基本上就可以了。


3. 定制 registry


为了能够支持缓存 docker.iogcr.iok8s.gcr.ioquay.ioghcr.io 等常见的公共镜像仓库,我们需要对 registry 的配置文件进行定制,Dockerfile 如下:


FROM registry:2.6LABEL maintainer="registry-proxy Docker Maintainers https://fuckcloudnative.io"ENV PROXY_REMOTE_URL="" \    DELETE_ENABLED=""COPY entrypoint.sh /entrypoint.sh
复制代码


其中 entrypoint.sh 用来将环境变量传入配置文件:


#!/bin/sh
set -e
CONFIG_YML=/etc/docker/registry/config.yml
if [ -n "$PROXY_REMOTE_URL" -a `grep -c "$PROXY_REMOTE_URL" $CONFIG_YML` -eq 0 ]; then echo "proxy:" >> $CONFIG_YML echo " remoteurl: $PROXY_REMOTE_URL" >> $CONFIG_YML echo " username: $PROXY_USERNAME" >> $CONFIG_YML echo " password: $PROXY_PASSWORD" >> $CONFIG_YML echo "------ Enabled proxy to remote: $PROXY_REMOTE_URL ------"elif [ $DELETE_ENABLED = true -a `grep -c "delete:" $CONFIG_YML` -eq 0 ]; then sed -i '/rootdirectory/a\ delete:' $CONFIG_YML sed -i '/delete/a\ enabled: true' $CONFIG_YML echo "------ Enabled local storage delete -----"fi
sed -i "/headers/a\ Access-Control-Allow-Origin: ['*']" $CONFIG_YMLsed -i "/headers/a\ Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']" $CONFIG_YMLsed -i "/headers/a\ Access-Control-Expose-Headers: ['Docker-Content-Digest']" $CONFIG_YML
case "$1" in *.yaml|*.yml) set -- registry serve "$@" ;; serve|garbage-collect|help|-*) set -- registry "$@" ;;esac
exec "$@"
复制代码


4. 启动缓存服务


构建好 Docker 镜像之后,就可以启动服务了。如果你不想自己构建,可以直接用我的镜像:yangchuansheng/registry-proxy


一般来说,即使你要同时缓存 docker.iogcr.iok8s.gcr.ioquay.ioghcr.io,一台 1C 2G 的云主机也足够了(前提是你不在上面跑其他的服务)。我的博客、评论服务和其他一堆乱七八糟的服务都要跑在云主机上,所以一台是不满足我的需求的,我直接买了两台腾讯云香港轻量级服务器。



既然买了两台,肯定得组个 k3s 集群啦,看主机名就知道我是用来干啥的。其中 2C 4G 作为 master 节点,1C 2G 作为 node 节点。


docker.io 为例,创建资源清单:


apiVersion: apps/v1kind: Deploymentmetadata:  name: dockerhub  labels:    app: dockerhubspec:  replicas: 1  selector:    matchLabels:      app: dockerhub  template:    metadata:      labels:        app: dockerhub    spec:      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchExpressions:                - key: app                  operator: In                  values:                  - dockerhub              topologyKey: kubernetes.io/hostname            weight: 1      dnsPolicy: None      dnsConfig:        nameservers:          - 8.8.8.8          - 8.8.4.4      containers:      - name: dockerhub        image: yangchuansheng/registry-proxy:latest        env:        - name: PROXY_REMOTE_URL          value: https://registry-1.docker.io        - name: PROXY_USERNAME          value: yangchuansheng        - name: PROXY_PASSWORD          value: ********        ports:        - containerPort: 5000          protocol: TCP        volumeMounts:        - mountPath: /etc/localtime          name: localtime        - mountPath: /var/lib/registry          name: registry      volumes:      - name: localtime        hostPath:          path: /etc/localtime      - name: registry        hostPath:          path: /var/lib/registry---apiVersion: v1kind: Servicemetadata:  name: dockerhub  labels:    app: dockerhubspec:  selector:    app: dockerhub  ports:    - protocol: TCP      name: http      port: 5000      targetPort: 5000
复制代码


使用资源清单创建对应的服务:


🐳  → kubectl apply -f dockerhub.yaml
复制代码


如果你只有一台主机,可以使用 docker-compose 来编排容器,配置文件可以自己参考 k8s 的配置修改,本文就不赘述了。


5. 代理选择


如果只缓存 docker.io,可以直接将 registry-proxy 的端口改成 443,并添加 SSL 证书配置。如果要缓存多个公共镜像仓库,就不太推荐这么做了,因为 443 端口只有一个,多个 registry-proxy 服务不能共用一个端口,合理的做法是使用边缘代理服务根据域名来转发请求到不同的 registry-proxy 服务。


对于 Kubernetes 集群来说,Ingress Controller 即边缘代理,常见的 Ingress Controller 基本上都是由 Nginx 或者 Envoy 来实现。[Envoy](https://fuckcloudnative.io/envoy-handbook/) 虽为代理界新秀,但生而逢时,它的很多特性都是原生为云准备的,是真正意义上的 Cloud Native L7 代理和通信总线。比如它的服务发现和动态配置功能,与 Nginx 等代理的热加载不同,[Envoy](https://fuckcloudnative.io/envoy-handbook/) 可以通过 API 来实现其控制平面,控制平面可以集中服务发现,并通过 API 接口动态更新数据平面的配置,不需要重启数据平面的代理。不仅如此,控制平面还可以通过 API 将配置进行分层,然后逐层更新。


目前使用 Envoy 实现的 Ingress Controller 有 [Contour](https://fuckcloudnative.io/posts/use-envoy-as-a-kubernetes-ingress/)、[Ambassador](https://github.com/datawire/ambassador) 和 [Gloo](https://github.com/solo-io/gloo) 等,如果你对 [Envoy](https://fuckcloudnative.io/envoy-handbook/) 比较感兴趣,并且想使用 Ingress Controller 作为边缘代理,可以试试 [Contour](https://fuckcloudnative.io/posts/use-envoy-as-a-kubernetes-ingress/)。Ingress Controller 对底层做了抽象,屏蔽了很多细节,无法顾及到所有细节的配置,必然不会支持底层代理所有的配置项,所以我选择使用原生的 [Envoy](https://fuckcloudnative.io/envoy-handbook/) 来作为边缘代理。如果你是单机跑的 registry-proxy 服务,也可以试试 [Envoy](https://fuckcloudnative.io/envoy-handbook/)


6. 代理配置


首先创建 Envoy 的资源清单:


apiVersion: apps/v1kind: Deploymentmetadata:  name: envoy  namespace: kube-system  labels:    app: envoyspec:  replicas: 2  selector:    matchLabels:      app: envoy  strategy:    rollingUpdate:      maxSurge: 0      maxUnavailable: 1    type: RollingUpdate  template:    metadata:      labels:        app: envoy    spec:      hostNetwork: true      dnsPolicy: ClusterFirstWithHostNet      containers:      - name: envoy        image: envoyproxy/envoy:v1.17-latest        imagePullPolicy: IfNotPresent        command:        - envoy        - /etc/envoy/envoy.yaml        ports:        - containerPort: 443          name: https        - containerPort: 80          name: http        - containerPort: 15001          name: http-metrics        volumeMounts:        - mountPath: /etc/localtime          name: localtime        - mountPath: /etc/envoy          name: envoy        - mountPath: /root/.acme.sh/fuckcloudnative.io          name: ssl      volumes:      - name: localtime        hostPath:          path: /etc/localtime      - name: ssl        hostPath:          path: /root/.acme.sh/fuckcloudnative.io      - name: envoy        hostPath:          path: /etc/envoy
复制代码


使用资源清单创建对应的服务:


🐳  → kubectl apply -f envoy.yaml
复制代码


这里选择使用 hostPath 将 envoy 的配置挂载到容器中,然后通过文件来动态更新配置。来看下 [Envoy](https://fuckcloudnative.io/envoy-handbook/) 的配置,先进入 /etc/envoy 目录。


bootstrap 配置:


node:  id: node0  cluster: cluster0dynamic_resources:  lds_config:    path: /etc/envoy/lds.yaml  cds_config:    path: /etc/envoy/cds.yamladmin:  access_log_path: "/dev/stdout"  address:    socket_address:      address: "0.0.0.0"      port_value: 15001
复制代码


LDS 的配置:


version_info: "0"resources:- "@type": type.googleapis.com/envoy.config.listener.v3.Listener  name: listener_http  address:    socket_address:      address: 0.0.0.0      port_value: 80  filter_chains:  - filters:    - name: envoy.filters.network.http_connection_manager      typed_config:        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager        stat_prefix: ingress_http        codec_type: AUTO        access_log:          name: envoy.access_loggers.file          typed_config:            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog            path: /dev/stdout        route_config:          name: http_route          virtual_hosts:          - name: default            domains:            - "*"            routes:            - match:                prefix: "/"              redirect:                https_redirect: true                port_redirect: 443                response_code: "FOUND"        http_filters:        - name: envoy.filters.http.router- "@type": type.googleapis.com/envoy.config.listener.v3.Listener  name: listener_https  address:    socket_address:      address: 0.0.0.0      port_value: 443  listener_filters:  - name: "envoy.filters.listener.tls_inspector"    typed_config: {}  filter_chains:  - transport_socket:      name: envoy.transport_sockets.tls      typed_config:        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext        common_tls_context:          alpn_protocols: h2,http/1.1          tls_certificates:          - certificate_chain:              filename: "/root/.acme.sh/fuckcloudnative.io/fullchain.cer"            private_key:              filename: "/root/.acme.sh/fuckcloudnative.io/fuckcloudnative.io.key"    filters:    - name: envoy.filters.network.http_connection_manager      typed_config:        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager        stat_prefix: ingress_https        codec_type: AUTO        use_remote_address: true        access_log:          name: envoy.access_loggers.file          typed_config:            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog            path: /dev/stdout        route_config:          name: https_route          response_headers_to_add:          - header:              key: Strict-Transport-Security              value: "max-age=15552000; includeSubdomains; preload"          virtual_hosts:          - name: docker            domains:            - docker.fuckcloudnative.io            routes:            - match:                prefix: "/"              route:                cluster: dockerhub                timeout: 600s        http_filters:        - name: envoy.filters.http.router          typed_config:            "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router 
复制代码


CDS 的配置:


version_info: "0"resources:- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster  name: dockerhub  connect_timeout: 15s  type: strict_dns  dns_lookup_family: V4_ONLY  lb_policy: ROUND_ROBIN  load_assignment:    cluster_name: dockerhub    endpoints:    - lb_endpoints:      - endpoint:          address:            socket_address:              address: dockerhub.default              port_value: 5000
复制代码


这里的 address 使用的是 Kubernetes 集群内部域名,其他部署方式请自己斟酌。


配置好了 Envoy 之后,就可以通过代理服务器拉取 docker.io 的镜像了。


7. 验证加速效果


现在你就可以通过代理服务器来拉取公共镜像了。比如你想拉取 nginx:alpine 镜像,可以使用下面的命令:


🐳  → docker pull docker.fuckcloudnative.io/library/nginx:alpine
alpine: Pulling from library/nginx801bfaa63ef2: Pull completeb1242e25d284: Pull complete7453d3e6b909: Pull complete07ce7418c4f8: Pull completee295e0624aa3: Pull completeDigest: sha256:c2ce58e024275728b00a554ac25628af25c54782865b3487b11c21cafb7fabdaStatus: Downloaded newer image for docker.fuckcloudnative.io/library/nginx:alpinedocker.fuckcloudnative.io/library/nginx:alpine
复制代码


8. 缓存所有镜像仓库


前面的示例只是缓存了 docker.io,如果要缓存所有的公共镜像仓库,可以参考 4-6 节的内容。以 k8s.gcr.io 为例,先准备一个资源清单:


apiVersion: apps/v1kind: Deploymentmetadata:  name: gcr-k8s  labels:    app: gcr-k8sspec:  replicas: 1  selector:    matchLabels:      app: gcr-k8s  template:    metadata:      labels:        app: gcr-k8s    spec:      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchExpressions:                - key: app                  operator: In                  values:                  - gcr-k8s              topologyKey: kubernetes.io/hostname            weight: 1      dnsPolicy: None      dnsConfig:        nameservers:          - 8.8.8.8          - 8.8.4.4      containers:      - name: gcr-k8s        image: yangchuansheng/registry-proxy:latest        env:        - name: PROXY_REMOTE_URL          value: https://k8s.gcr.io        ports:        - containerPort: 5000          protocol: TCP        volumeMounts:        - mountPath: /etc/localtime          name: localtime        - mountPath: /var/lib/registry          name: registry      volumes:      - name: localtime        hostPath:          path: /etc/localtime      - name: registry        hostPath:          path: /var/lib/registry---apiVersion: v1kind: Servicemetadata:  name: gcr-k8s  labels:    app: gcr-k8sspec:  selector:    app: gcr-k8s  ports:    - protocol: TCP      name: http      port: 5000      targetPort: 5000
复制代码


将其部署到 Kubernetes 集群中:


🐳  → kubectl apply -f gcr-k8s.yaml
复制代码


lds.yaml 中添加相关配置:


          virtual_hosts:          - name: docker            ...            ...          - name: k8s            domains:            - k8s.fuckcloudnative.io            routes:            - match:                prefix: "/"              route:                cluster: gcr-k8s                timeout: 600s
复制代码


cds.yaml 中添加相关配置:


- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster  name: gcr-k8s  connect_timeout: 1s  type: strict_dns  dns_lookup_family: V4_ONLY  lb_policy: ROUND_ROBIN  load_assignment:    cluster_name: gcr-k8s    endpoints:    - lb_endpoints:      - endpoint:          address:            socket_address:              address: gcr-k8s.default              port_value: 5000
复制代码


其他镜像仓库可照搬上述步骤,以下是我自己跑的所有缓存服务容器:


🐳  → kubectl get pod -o wide
gcr-8647ffb586-67c6g 1/1 Running 0 21h 10.42.1.52 blog-k3s02ghcr-7765f6788b-hxxvc 1/1 Running 0 21h 10.42.1.55 blog-k3s01dockerhub-94bbb7497-x4zwg 1/1 Running 0 21h 10.42.1.54 blog-k3s02gcr-k8s-644db84879-7xssb 1/1 Running 0 21h 10.42.1.53 blog-k3s01quay-559b65848b-ljclb 1/1 Running 0 21h 10.42.0.154 blog-k3s01
复制代码


9. 容器运行时配置


配置好所有的缓存服务后,就可以通过代理来拉取公共镜像了,只需按照下面的列表替换镜像地址中的字段就行了:



当然,最好的方式还是直接配置 registry mirror,Docker 只支持配置 docker.io 的 registry mirror,ContainerdPodman 支持配置所有镜像仓库的 registry mirror。


Docker


Docker 可以修改配置文件 /etc/docker/daemon.json,添加下面的内容:


{    "registry-mirrors": [        "https://docker.fuckcloudnative.io"    ]}
复制代码


然后重启 Docker 服务,就可以直接拉取 docker.io 的镜像了,不需要显示指定代理服务器的地址,Docker 服务本身会自动通过代理服务器去拉取镜像。比如:


🐳 → docker pull nginx:alpine🐳 → docker pull docker.io/library/nginx:alpine
复制代码


Containerd


Containerd 就比较简单了,它支持任意 registry 的 mirror,只需要修改配置文件 /etc/containerd/config.toml,添加如下的配置:


    [plugins."io.containerd.grpc.v1.cri".registry]      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]          endpoint = ["https://docker.fuckcloudnative.io"]        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]          endpoint = ["https://k8s.fuckcloudnative.io"]        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]          endpoint = ["https://gcr.fuckcloudnative.io"]        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]          endpoint = ["https://ghcr.fuckcloudnative.io"]        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]          endpoint = ["https://quay.fuckcloudnative.io"]
复制代码


重启 Containerd 服务后,就可以直接拉取所有镜像了,不需要修改任何前缀,Containerd 会根据配置自动选择相应的代理 URL 拉取镜像。


Podman


Podman 也支持任意 registry 的 mirror,只需要修改配置文件 /etc/containers/registries.conf,添加如下的配置:


unqualified-search-registries = ['docker.io', 'k8s.gcr.io', 'gcr.io', 'ghcr.io', 'quay.io']
[[registry]]prefix = "docker.io"insecure = truelocation = "registry-1.docker.io"
[[registry.mirror]]location = "docker.fuckcloudnative.io"
[[registry]]prefix = "k8s.gcr.io"insecure = truelocation = "k8s.gcr.io"
[[registry.mirror]]location = "k8s.fuckcloudnative.io"
[[registry]]prefix = "gcr.io"insecure = truelocation = "gcr.io"
[[registry.mirror]]location = "gcr.fuckcloudnative.io"
[[registry]]prefix = "ghcr.io"insecure = truelocation = "ghcr.io"
[[registry.mirror]]location = "ghcr.fuckcloudnative.io"
[[registry]]prefix = "quay.io"insecure = truelocation = "quay.io"
[[registry.mirror]]location = "quay.fuckcloudnative.io"
复制代码


然后就可以直接拉取所有镜像了,不需要修改任何前缀,Podman 会根据配置自动选择相应的代理 URL 拉取镜像。而且 Podman 还有 fallback 机制,上面的配置表示先尝试通过 registry.mirrorlocation 字段的 URL 来拉取镜像,如果失败就会尝试通过 registry 中 location 字段的 URL 来拉取。


10. 清理缓存


缓存服务会将拉取的镜像缓存到本地,所以需要消耗磁盘容量。一般云主机的磁盘容量都不是很大,OSS 和 s3 存储都比较贵,不太划算。


为了解决这个问题,我推荐定期删除缓存到本地磁盘的部分镜像,或者删除所有镜像。方法也比较简单,单独再部署一个 registry,共用其他 registry 的存储,并启用 delete 功能,然后再通过 API 或者 Dashboard 进行删除。


先准备一个资源清单:


apiVersion: apps/v1kind: Deploymentmetadata:  name: reg-local  labels:    app: reg-localspec:  replicas: 1  selector:    matchLabels:      app: reg-local  template:    metadata:      labels:        app: reg-local    spec:      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchExpressions:                - key: app                  operator: In                  values:                  - reg-local              topologyKey: kubernetes.io/hostname            weight: 1      containers:      - name: reg-local        image: yangchuansheng/registry-proxy:latest        env:        - name: DELETE_ENABLED          value: "true"        ports:        - containerPort: 5000          protocol: TCP        volumeMounts:        - mountPath: /etc/localtime          name: localtime        - mountPath: /var/lib/registry          name: registry      volumes:      - name: localtime        hostPath:          path: /etc/localtime      - name: registry        hostPath:          path: /var/lib/registry---apiVersion: v1kind: Servicemetadata:  name: reg-local  labels:    app: reg-localspec:  selector:    app: reg-local  ports:    - protocol: TCP      name: http      port: 5000      targetPort: 5000
复制代码


将其部署到 Kubernetes 集群中:


🐳  → kubectl apply -f reg-local.yaml
复制代码


再准备一个 Docker Registry UI 的资源清单:


apiVersion: apps/v1kind: Deploymentmetadata:  name: registry-ui  labels:    app: registry-uispec:  replicas: 1  selector:    matchLabels:      app: registry-ui  template:    metadata:      labels:        app: registry-ui    spec:      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchExpressions:                - key: app                  operator: In                  values:                  - registry-ui              topologyKey: kubernetes.io/hostname            weight: 1      tolerations:      - key: node-role.kubernetes.io/ingress        operator: Exists        effect: NoSchedule      containers:      - name: registry-ui        image: joxit/docker-registry-ui:static        env:        - name: REGISTRY_TITLE          value: My Private Docker Registry        - name: REGISTRY_URL          value: "http://reg-local:5000"        - name: DELETE_IMAGES          value: "true"        ports:        - containerPort: 80          protocol: TCP        volumeMounts:        - mountPath: /etc/localtime          name: localtime      volumes:      - name: localtime        hostPath:          path: /etc/localtime---apiVersion: v1kind: Servicemetadata:  name: registry-ui  labels:    app: registry-uispec:  selector:    app: registry-ui  ports:    - protocol: TCP      name: http      port: 80      targetPort: 80
复制代码


将其部署到 Kubernetes 集群中:


🐳  → kubectl apply -f registry-ui.yaml
复制代码


这样就可以通过 Dashboard 来清理镜像释放空间了。



或者直接简单粗暴,定时删除整个存储目录的内容。例如,执行命令 crontab -e,添加如下内容:


* * */2 * * /usr/bin/rm -rf /var/lib/registry/* &>/dev/null
复制代码


表示每过两天清理一次 /var/lib/registry/ 目录。


11. 防白嫖认证


最后还有一个问题,我把缓存服务的域名全部公开了,如果大家都来白嫖,我的云主机肯定承受不住。为了防止白嫖,我得给 registry-proxy 加个认证,最简单的方法就是使用 basic auth,用 htpasswd 来存储密码。


  1. 为用户 admin 创建一个密码文件,密码为 admin


 🐳 → docker run \ --entrypoint htpasswd \ registry:2.6 -Bbn admin admin > htpasswd
复制代码


  1. 创建 Secret:


🐳 → kubectl create secret generic registry-auth --from-file=htpasswd
复制代码


  1. 修改资源清单的配置,以 docker.io 为例:


apiVersion: apps/v1kind: Deploymentmetadata:  name: dockerhub  labels:    app: dockerhubspec:  replicas: 1  selector:    matchLabels:      app: dockerhub  template:    metadata:      labels:        app: dockerhub    spec:      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchExpressions:                - key: app                  operator: In                  values:                  - dockerhub              topologyKey: kubernetes.io/hostname            weight: 1      dnsPolicy: None      dnsConfig:        nameservers:          - 8.8.8.8          - 8.8.4.4      containers:      - name: dockerhub        image: yangchuansheng/registry-proxy:latest        env:        - name: PROXY_REMOTE_URL          value: https://registry-1.docker.io        - name: PROXY_USERNAME          value: yangchuansheng        - name: PROXY_PASSWORD          value: ********+       - name: REGISTRY_AUTH_HTPASSWD_REALM+         value: Registry Realm+       - name: REGISTRY_AUTH_HTPASSWD_PATH+         value: /auth/htpasswd         ports:        - containerPort: 5000          protocol: TCP        volumeMounts:        - mountPath: /etc/localtime          name: localtime        - mountPath: /var/lib/registry          name: registry+       - mountPath: /auth+         name: auth      volumes:      - name: localtime        hostPath:          path: /etc/localtime      - name: registry        hostPath:          path: /var/lib/registry+     - name: auth+       secret:+         secretName: registry-auth
复制代码


  1. 尝试拉取镜像:


🐳 → docker pull docker.fuckcloudnative.io/library/nginx:latest  Error response from daemon: Get https://docker.fuckcloudnative.io/v2/library/nginx/manifests/latest: no basic auth credentials
复制代码


  1. 登录镜像仓库:


🐳 → docker login docker.fuckcloudnative.ioUsername: adminPassword:WARNING! Your password will be stored unencrypted in /root/.docker/config.json.Configure a credential helper to remove this warning. Seehttps://docs.docker.com/engine/reference/commandline/login/#credentials-store   Login Succeeded
复制代码


现在就可以正常拉取镜像了。


如果你想更细粒度地控制权限,可以使用 Token 的方式来进行认证,具体可以参考 docker_auth 这个项目。


12. 费用评估


好了,现在我们来评估一下这一切的费用。首先你得有一个会魔法的服务器,国内的肯定不用考虑了,必须选择国外的,而且到国内的速度还过得去的,最低最低不会低于 30 人民币/月 吧。除此之外,你还得拥有一个个人域名,这个价格不好说,总而言之,加起来肯定不会低于 30 吧,多数人肯定是下不去这个手的。没关系,我有一个更便宜的方案,我已经部署好了一切,你可以直接用我的服务,当然我也是自己买的服务器,每个月也是要花钱的,如果你真的想用,只需要每月支付 3 元,以此来保障我每个月的服务器费用。当然肯定不止你一个人,目前大概有十几个用户,后面如果人数特别多,再考虑加服务器。这个需要你自己考虑清楚,有意者请点击文章开头的原文链接向我咨询。


发布于: 2021 年 02 月 25 日阅读数: 10
用户头像

云原生宝藏男孩 2018.03.30 加入

我是一名在上海工作的 Cloud Native 工程师,目前就职于 IBM,是一名云原生技术爱好者,专注于云原生领域,我的个人网站:https://fuckcloudnative.io,同时还运营了一个云原生技术公众号『云原生实验室』。

评论

发布
暂无评论
Docker 镜像加速教程