赞
踩
在使用 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
的镜像仓库代理站点。直接反代可以保证获取到的镜像是最新最全的,比缓存靠谱多了。
一台能够施展魔法的服务器(你懂得,可以直接访问 gcr.io)
一个域名和域名相关的 SSL 证书(docker pull 镜像时需要验证域名证书),一般用 Let's Encrypt 就够了。
quay.io
和 Docker 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 反代,基本上就可以了。
方案确定了之后,就可以动手配置了。还是使用我之前反复提到的方法:通过文件动态更新配置。如果你不是很清楚我在说什么,请参考 Envoy 基础教程:基于文件系统动态更新配置。这里我就直接贴配置了。
bootstrap
配置:
- # envoy.yaml
- node:
- id: node0
- cluster: cluster0
- dynamic_resources:
- lds_config:
- path: /etc/envoy/lds.yaml
- cds_config:
- path: /etc/envoy/cds.yaml
- admin:
- access_log_path: "/dev/stdout"
- address:
- socket_address:
- address: "0.0.0.0"
- port_value: 15001
LDS
的配置:
- # lds.yaml
- 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/xxx.com/fullchain.cer"
- private_key:
- filename: "/root/.acme.sh/xxx.com/xxx.com.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: gcr
- domains:
- - gcr.xxx.com
- routes:
- - match:
- prefix: "/"
- route:
- cluster: gcr
- timeout: 600s
- - name: quay
- domains:
- - quay.xxx.com
- routes:
- - match:
- prefix: "/"
- route:
- cluster: quay
- host_rewrite_literal: quay.io
- - name: docker
- domains:
- - docker.xxx.com
- routes:
- - match:
- prefix: "/"
- route:
- cluster: dockerhub
- host_rewrite_literal: registry-1.docker.io
- http_filters:
- - name: envoy.filters.http.router
- typed_config:
- "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
友情提醒:我这里使用的是
v3
版本的 API,v2
版本的 API 即将被废弃,请奔走相告。
CDS
的配置:
- # cds.yaml
- version_info: "0"
- resources:
- - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
- name: gcr
- connect_timeout: 1s
- type: strict_dns
- dns_lookup_family: V4_ONLY
- lb_policy: ROUND_ROBIN
- load_assignment:
- cluster_name: gcr
- endpoints:
- - lb_endpoints:
- - endpoint:
- address:
- socket_address:
- address: gcr.default
- port_value: 5000
- - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
- name: dockerhub
- connect_timeout: 15s
- type: logical_dns
- dns_lookup_family: V4_ONLY
- dns_resolvers:
- socket_address:
- address: 8.8.8.8
- port_value: 53
- lb_policy: ROUND_ROBIN
- load_assignment:
- cluster_name: dockerhub
- endpoints:
- - lb_endpoints:
- - endpoint:
- address:
- socket_address:
- address: registry-1.docker.io
- port_value: 443
- transport_socket:
- name: envoy.transport_sockets.tls
- typed_config:
- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
- sni: registry-1.docker.io
- - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
- name: quay
- connect_timeout: 15s
- type: logical_dns
- dns_lookup_family: V4_ONLY
- dns_resolvers:
- socket_address:
- address: 8.8.8.8
- port_value: 53
- lb_policy: ROUND_ROBIN
- load_assignment:
- cluster_name: quay
- endpoints:
- - lb_endpoints:
- - endpoint:
- address:
- socket_address:
- address: quay.io
- port_value: 443
- transport_socket:
- name: envoy.transport_sockets.tls
- typed_config:
- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
- sni: quay.io
各个字段的含义我实在是懒得解释,可以直接去看上面提到的电子书。
配置好了 Envoy 之后,就可以通过代理服务器拉取 Docker Hub
和 quay.io
的镜像了。最后来解决 gcr.io 镜像的难题。
首先需要部署一个私有的 registry,如果你只有一台服务器(我想大多数人应该只会买一台吧),可以使用 docker-compose
,我这里是使用 Kubernetes 部署的,首先需要准备一个部署清单:
- # registry-proxy.yaml
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: gcr
- labels:
- app: gcr
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: gcr
- template:
- metadata:
- labels:
- app: gcr
- spec:
- nodeSelector:
- kubernetes.io/hostname: blog-k3s03
- tolerations:
- - key: node-role.kubernetes.io/ingress
- operator: Exists
- effect: NoSchedule
- hostNetwork: false
- containers:
- - name: gcr
- image: findsec/registry-proxy:latest
- env:
- - name: PROXY_REMOTE_URL
- value: https://gcr.io
- ports:
- - containerPort: 5000
- hostPort: 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: v1
- kind: Service
- metadata:
- name: gcr
- labels:
- app: gcr
- spec:
- sessionAffinity: ClientIP
- selector:
- app: gcr
- ports:
- - protocol: TCP
- name: http
- port: 5000
- targetPort: 5000
然后将其部署到 Kubernetes 集群中:
$ kubectl apply -f registry-proxy.yaml
现在再回过头来看看 Envoy 的配置中关于 gcr
的部分,先来看看 LDS
:
- virtual_hosts:
- - name: gcr
- domains:
- - gcr.xxx.com
- routes:
- - match:
- prefix: "/"
- route:
- cluster: gcr
- timeout: 600s
很简单,不需要解释,再来看看 CDS:
- - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
- name: gcr
- connect_timeout: 1s
- type: strict_dns
- dns_lookup_family: V4_ONLY
- lb_policy: ROUND_ROBIN
- load_assignment:
- cluster_name: gcr
- endpoints:
- - lb_endpoints:
- - endpoint:
- address:
- socket_address:
- address: gcr.default
- port_value: 5000
这里的 address
使用的是 Kubernetes 集群内部域名,其他部署方式请自己斟酌。
最后,给服务器换个新内核,开启 BBR
加速不过分吧?不然你的镜像拉取仍然是龟速。
现在你就可以通过代理服务器来拉取公共镜像了。
对于 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
,添加下面的内容:
- {
- "registry-mirrors": [
- "https://docker.xxx.com"
- ]
- }
然后重启 Docker 服务,就可以直接拉取 Docker Hub 的镜像了,不需要显示指定代理服务器的地址,Docker 服务本身会自动通过代理服务器去拉取镜像。比如:
- ???? → docker pull nginx:alpine
- ???? → docker pull docker.io/library/nginx:alpine
Containerd 就比较简单了,它支持任意 registry 的 mirror,只需要修改配置文件 /etc/containerd/config.toml
,添加如下的配置:
- [plugins.cri.registry.mirrors]
- [plugins.cri.registry.mirrors."docker.io"]
- endpoint = ["https://docker.xxx.com"]
- [plugins.cri.registry.mirrors."quay.io"]
- endpoint = ["https://quay.xxx.com"]
- [plugins.cri.registry.mirrors."gcr.io"]
- endpoint = ["http://gcr.xxx.com"]
重启 Containerd
服务后,就可以直接拉取 Docker Hub
、gcr.io
和 quay.io
的镜像了,不需要修改任何前缀,Containerd 会根据配置自动选择相应的代理 URL 拉取镜像。
好了,现在我们来评估一下这一切的费用。首先你得有一个会魔法的服务器,国内的肯定不用考虑了,必须选择国外的,而且到国内的速度还过得去的,最低最低不会低于 30 人民币/月 吧。除此之外,你还得拥有一个个人域名,这个价格不好说,总而言之,加起来肯定不会低于 30 吧,多数人肯定是下不去这个手的。没关系,我有一个更便宜的方案,我已经部署好了一切,你可以直接用我的服务,当然我也是自己买的服务器,每个月也是要花钱的,如果你真的想用,只需要每月支付 3 元,以此来保障我每个月的服务器费用。当然肯定不止你一个人,我可能还会赚点钱,但最多不允许超过 40 人,如果人数特别多,我可能会考虑加服务器。这个需要你自己考虑清楚,有意者扫描下方的二维码加入交流群:
你可能还喜欢
点击下方图片即可阅读
云原生是一种信仰 ????
扫码关注公众号
后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!
点击 "阅读原文" 获取更好的阅读体验!
❤️给个「在看」,是对我最大的支持❤️
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。