当前位置:   article > 正文

彻底解决 gcr、quay、DockerHub 镜像下载难题

quay.io

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

为了能够顺利访问 gcr.io 等镜像仓库,我们需要在墙外自己搭建一个类似于 gcr.azk8s.cn 的镜像仓库代理站点。直接反代可以保证获取到的镜像是最新最全的,比缓存靠谱多了。

1. 前提条件

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

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

2. 代理方案

quay.ioDocker Hub 很好代理,可以直接使用 Envoy 的 host_rewrite_literal 参数(这是新版本的参数,如果你使用旧版本的 Envoy,参数应该是 host_rewrite),当 Envoy 将请求转发给上游集群时,会直接将头文件中的 host 改为指定的值。比如,如果上游集群是 quay.io,就将头文件改为 quay.io。我之前写过的 使用 Envoy 反向代理谷歌搜索 用的就是此方案。什么?你是 Envoy 小白?莫慌,我已经为你们准备了一本 Envoy 从入门到放弃 的电子书,快快扫描下方的二维码学习去吧(记得给我一个 star 哦)~~

你也可以直接打开链接:https://github.com/yangchuansheng/envoy-handbook

gcr.io 稍微有点难办,因为它在连接的时候需要二次认证,即使你通过反代服务器 pull 镜像,它还是会再次访问 gcr.io 进行验证,然后才可以通过反代服务器 pull 镜像。这就有点尴尬了,我特么要是能访问 gcr.io,还要什么反代啊。。。话说 Docker 官方不是有一个 registry 镜像吗,可以通过设置参数 remoteurl 将其作为远端仓库的缓存仓库,这样当你通过这个私有仓库的地址拉取镜像时,regiistry 会先将镜像缓存到本地存储,然后再提供给拉取的客户端(有可能这两个步骤是同时的,我也不太清楚)。我们可以先部署一个私有 registry,然后将 remoteurl 设为 https://gcr.io,最后再通过 Envoy 反代,基本上就可以了。

3. 代理配置

方案确定了之后,就可以动手配置了。还是使用我之前反复提到的方法:通过文件动态更新配置。如果你不是很清楚我在说什么,请参考 Envoy 基础教程:基于文件系统动态更新配置。这里我就直接贴配置了。

bootstrap 配置:

  1. # envoy.yaml
  2. node:
  3.   id: node0
  4.   cluster: cluster0
  5. dynamic_resources:
  6.   lds_config:
  7.     path: /etc/envoy/lds.yaml
  8.   cds_config:
  9.     path: /etc/envoy/cds.yaml
  10. admin:
  11.   access_log_path: "/dev/stdout"
  12.   address:
  13.     socket_address:
  14.       address: "0.0.0.0"
  15.       port_value: 15001

LDS 的配置:

  1. # lds.yaml
  2. version_info: "0"
  3. resources:
  4. "@type"type.googleapis.com/envoy.config.listener.v3.Listener
  5.   name: listener_http
  6.   address:
  7.     socket_address:
  8.       address: 0.0.0.0
  9.       port_value: 80
  10.   filter_chains:
  11.   - filters:
  12.     - name: envoy.filters.network.http_connection_manager
  13.       typed_config:
  14.         "@type"type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
  15.         stat_prefix: ingress_http
  16.         codec_type: AUTO
  17.         access_log:
  18.           name: envoy.access_loggers.file
  19.           typed_config:
  20.             "@type"type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
  21.             path: /dev/stdout
  22.         route_config:
  23.           name: http_route
  24.           virtual_hosts:
  25.           - name: default
  26.             domains:
  27.             - "*"
  28.             routes:
  29.             - match:
  30.                 prefix: "/"
  31.               redirect:
  32.                 https_redirect: true
  33.                 port_redirect: 443
  34.                 response_code: "FOUND"
  35.         http_filters:
  36.         - name: envoy.filters.http.router
  37. "@type"type.googleapis.com/envoy.config.listener.v3.Listener
  38.   name: listener_https
  39.   address:
  40.     socket_address:
  41.       address: 0.0.0.0
  42.       port_value: 443
  43.   listener_filters:
  44.   - name: "envoy.filters.listener.tls_inspector"
  45.     typed_config: {}
  46.   filter_chains:
  47.   - transport_socket:
  48.       name: envoy.transport_sockets.tls
  49.       typed_config:
  50.         "@type"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
  51.         common_tls_context:
  52.           alpn_protocols: h2,http/1.1
  53.           tls_certificates:
  54.           - certificate_chain:
  55.               filename: "/root/.acme.sh/xxx.com/fullchain.cer"
  56.             private_key:
  57.               filename: "/root/.acme.sh/xxx.com/xxx.com.key"
  58.     filters:
  59.     - name: envoy.filters.network.http_connection_manager
  60.       typed_config:
  61.         "@type"type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
  62.         stat_prefix: ingress_https
  63.         codec_type: AUTO
  64.         use_remote_address: true
  65.         access_log:
  66.           name: envoy.access_loggers.file
  67.           typed_config:
  68.             "@type"type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
  69.             path: /dev/stdout
  70.         route_config:
  71.           name: https_route
  72.           response_headers_to_add:
  73.           - header:
  74.               key: Strict-Transport-Security
  75.               value: "max-age=15552000; includeSubdomains; preload"
  76.           virtual_hosts:
  77.           - name: gcr
  78.             domains:
  79.             - gcr.xxx.com
  80.             routes:
  81.             - match:
  82.                 prefix: "/"
  83.               route:
  84.                 cluster: gcr
  85.                 timeout: 600s
  86.           - name: quay
  87.             domains:
  88.             - quay.xxx.com
  89.             routes:
  90.             - match:
  91.                 prefix: "/"
  92.               route:
  93.                 cluster: quay
  94.                 host_rewrite_literal: quay.io
  95.           - name: docker
  96.             domains:
  97.             - docker.xxx.com
  98.             routes:
  99.             - match:
  100.                 prefix: "/"
  101.               route:
  102.                 cluster: dockerhub
  103.                 host_rewrite_literal: registry-1.docker.io
  104.         http_filters:
  105.         - name: envoy.filters.http.router
  106.           typed_config:
  107.             "@type"type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

友情提醒:我这里使用的是 v3 版本的 API,v2 版本的 API 即将被废弃,请奔走相告。

CDS 的配置:

  1. # cds.yaml
  2. version_info: "0"
  3. resources:
  4. "@type"type.googleapis.com/envoy.config.cluster.v3.Cluster
  5.   name: gcr
  6.   connect_timeout: 1s
  7.   type: strict_dns
  8.   dns_lookup_family: V4_ONLY
  9.   lb_policy: ROUND_ROBIN
  10.   load_assignment:
  11.     cluster_name: gcr
  12.     endpoints:
  13.     - lb_endpoints:
  14.       - endpoint:
  15.           address:
  16.             socket_address:
  17.               address: gcr.default
  18.               port_value: 5000
  19. "@type"type.googleapis.com/envoy.config.cluster.v3.Cluster
  20.   name: dockerhub
  21.   connect_timeout: 15s
  22.   type: logical_dns
  23.   dns_lookup_family: V4_ONLY
  24.   dns_resolvers:
  25.     socket_address:
  26.       address: 8.8.8.8
  27.       port_value: 53
  28.   lb_policy: ROUND_ROBIN
  29.   load_assignment:
  30.     cluster_name: dockerhub
  31.     endpoints:
  32.     - lb_endpoints:
  33.       - endpoint:
  34.           address:
  35.             socket_address:
  36.               address: registry-1.docker.io
  37.               port_value: 443
  38.   transport_socket:
  39.     name: envoy.transport_sockets.tls
  40.     typed_config:
  41.       "@type"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
  42.       sni: registry-1.docker.io
  43. "@type"type.googleapis.com/envoy.config.cluster.v3.Cluster
  44.   name: quay
  45.   connect_timeout: 15s
  46.   type: logical_dns
  47.   dns_lookup_family: V4_ONLY
  48.   dns_resolvers:
  49.     socket_address:
  50.       address: 8.8.8.8
  51.       port_value: 53
  52.   lb_policy: ROUND_ROBIN
  53.   load_assignment:
  54.     cluster_name: quay
  55.     endpoints:
  56.     - lb_endpoints:
  57.       - endpoint:
  58.           address:
  59.             socket_address:
  60.               address: quay.io
  61.               port_value: 443
  62.   transport_socket:
  63.     name: envoy.transport_sockets.tls
  64.     typed_config:
  65.       "@type"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
  66.       sni: quay.io

各个字段的含义我实在是懒得解释,可以直接去看上面提到的电子书。

配置好了 Envoy 之后,就可以通过代理服务器拉取 Docker Hubquay.io 的镜像了。最后来解决 gcr.io 镜像的难题。

4. registry 配置

首先需要部署一个私有的 registry,如果你只有一台服务器(我想大多数人应该只会买一台吧),可以使用 docker-compose,我这里是使用 Kubernetes 部署的,首先需要准备一个部署清单:

  1. # registry-proxy.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5.   name: gcr
  6.   labels:
  7.     app: gcr
  8. spec:
  9.   replicas: 1 
  10.   selector:
  11.     matchLabels:
  12.       app: gcr
  13.   template:
  14.     metadata:
  15.       labels:
  16.         app: gcr
  17.     spec:
  18.       nodeSelector:
  19.         kubernetes.io/hostname: blog-k3s03
  20.       tolerations:
  21.       - key: node-role.kubernetes.io/ingress
  22.         operator: Exists
  23.         effect: NoSchedule
  24.       hostNetwork: false 
  25.       containers:
  26.       - name: gcr
  27.         image: findsec/registry-proxy:latest 
  28.         env:
  29.         - name: PROXY_REMOTE_URL
  30.           value: https://gcr.io
  31.         ports:
  32.         - containerPort: 5000
  33.           hostPort: 5000
  34.           protocol: TCP
  35.         volumeMounts:
  36.         - mountPath: /etc/localtime
  37.           name: localtime
  38.         - mountPath: /var/lib/registry
  39.           name: registry
  40.       volumes:
  41.       - name: localtime
  42.         hostPath:
  43.           path: /etc/localtime
  44.       - name: registry
  45.         hostPath:
  46.           path: /var/lib/registry
  47. ---
  48. apiVersion: v1
  49. kind: Service
  50. metadata:
  51.   name: gcr
  52.   labels:
  53.     app: gcr
  54. spec:
  55.   sessionAffinity: ClientIP
  56.   selector:
  57.     app: gcr
  58.   ports:
  59.     - protocol: TCP
  60.       name: http
  61.       port: 5000 
  62.       targetPort: 5000 

然后将其部署到 Kubernetes 集群中:

$ kubectl apply -f registry-proxy.yaml

现在再回过头来看看 Envoy 的配置中关于 gcr 的部分,先来看看 LDS

  1. virtual_hosts:
  2. - name: gcr
  3.   domains:
  4.   - gcr.xxx.com
  5.   routes:
  6.   - match:
  7.       prefix: "/"
  8.     route:
  9.       cluster: gcr
  10.       timeout: 600s

很简单,不需要解释,再来看看 CDS:

  1. "@type"type.googleapis.com/envoy.config.cluster.v3.Cluster
  2.   name: gcr
  3.   connect_timeout: 1s
  4.   type: strict_dns
  5.   dns_lookup_family: V4_ONLY
  6.   lb_policy: ROUND_ROBIN
  7.   load_assignment:
  8.     cluster_name: gcr
  9.     endpoints:
  10.     - lb_endpoints:
  11.       - endpoint:
  12.           address:
  13.             socket_address:
  14.               address: gcr.default
  15.               port_value: 5000

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

最后,给服务器换个新内核,开启 BBR 加速不过分吧?不然你的镜像拉取仍然是龟速。

5. Docker 配置

现在你就可以通过代理服务器来拉取公共镜像了。

对于 Docker Hub 来说,只需要将 docker.io 换成 docker.xxx.com 就行了,比如你想拉取 nginx:alpine 镜像,可以使用下面的命令:

???? → docker pull docker.xxx.com/library/nginx:alpine

对于 quay.io 来说,只需要将 quay.io 换成 quay.xxx.com 就行了,比如你想拉取 quay.io/coreos/kube-state-metrics:v1.5.0 镜像,可以使用下面的命令:

???? → docker pull quay.xxx.com/coreos/kube-state-metrics:v1.5.0

对于 gcr.io 来说,只需要将 gcr.io 换成 gcr.xxx.com 就行了,比如你想拉取 gcr.io/google-containers/etcd:3.2.24 镜像,可以使用下面的命令:

???? → docker pull gcr.xxx.com/google-containers/etcd:3.2.24

当然,Docker 是可以设置 registry mirror 的,但只支持 Docker Hub。可以修改配置文件 /etc/docker/daemon.json,添加下面的内容:

  1. {
  2.     "registry-mirrors": [
  3.         "https://docker.xxx.com"
  4.     ]
  5. }

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

  1. ???? → docker pull nginx:alpine
  2. ???? → docker pull docker.io/library/nginx:alpine

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

  1. [plugins.cri.registry.mirrors]
  2. [plugins.cri.registry.mirrors."docker.io"]
  3. endpoint = ["https://docker.xxx.com"]
  4. [plugins.cri.registry.mirrors."quay.io"]
  5. endpoint = ["https://quay.xxx.com"]
  6. [plugins.cri.registry.mirrors."gcr.io"]
  7. endpoint = ["http://gcr.xxx.com"]

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

6. 费用评估

好了,现在我们来评估一下这一切的费用。首先你得有一个会魔法的服务器,国内的肯定不用考虑了,必须选择国外的,而且到国内的速度还过得去的,最低最低不会低于 30 人民币/月 吧。除此之外,你还得拥有一个个人域名,这个价格不好说,总而言之,加起来肯定不会低于 30 吧,多数人肯定是下不去这个手的。没关系,我有一个更便宜的方案,我已经部署好了一切,你可以直接用我的服务,当然我也是自己买的服务器,每个月也是要花钱的,如果你真的想用,只需要每月支付 3 元,以此来保障我每个月的服务器费用。当然肯定不止你一个人,我可能还会赚点钱,但最多不允许超过 40 人,如果人数特别多,我可能会考虑加服务器。这个需要你自己考虑清楚,有意者扫描下方的二维码加入交流群:


你可能还喜欢

点击下方图片即可阅读

伪官宣:Envoy 中文指南新鲜出炉

云原生是一种信仰 ????

码关注公众号

后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!

点击 "阅读原文" 获取更好的阅读体验!

❤️给个「在看」,是对我最大的支持❤️
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/774788
推荐阅读
相关标签
  

闽ICP备14008679号