Docker 映象加速教程
阿新 • • 發佈:2021-02-26
> 原文連結:[https://fuckcloudnative.io/posts/docker-registry-proxy/](https://fuckcloudnative.io/posts/docker-registry-proxy/)
在使用 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` 的映象倉庫代理站點。利用 Docker 的開源專案 [registry](https://docs.docker.com/registry/) 就可以實現這個需求,registry 不僅可以作為本地私有映象倉庫,還可以作為上游映象倉庫的快取,也就是 `pull through cache`。
先來感受下速度:
![](https://img2020.cnblogs.com/other/1737323/202102/1737323-20210226113336007-1953466932.png)
![](https://img2020.cnblogs.com/other/1737323/202102/1737323-20210226113336333-128206995.png)
![](https://img2020.cnblogs.com/other/1737323/202102/1737323-20210226113336584-1917842955.jpg)
![](https://img2020.cnblogs.com/other/1737323/202102/1737323-20210226113336796-1931131649.jpg)
## 1. 前提條件
----
+ 一臺能夠施展魔法的伺服器(你懂得,可以直接訪問 gcr.io)
+ 一個域名和域名相關的 SSL 證書(docker pull 映象時需要驗證域名證書),一般用 [Let's Encrypt](https://letsencrypt.org/) 就夠了。
## 2. 核心思路
----
registry 可以通過設定引數 `remoteurl` 將其作為遠端倉庫的快取倉庫,這樣當你通過這個私有倉庫的地址拉取映象時,regiistry 會先將映象快取到本地儲存,然後再提供給拉取的客戶端(有可能這兩個步驟是同時的,我也不太清楚)。我們可以先部署一個私有 registry,然後將 `remoteurl` 設為需要加速的映象倉庫地址,基本上就可以了。
## 3. 定製 registry
為了能夠支援快取 `docker.io`、`gcr.io`、`k8s.gcr.io`、`quay.io` 和 `ghcr.io` 等常見的公共映象倉庫,我們需要對 registry 的配置檔案進行定製,Dockerfile 如下:
```dockerfile
FROM registry:2.6
LABEL maintainer="registry-proxy Docker Maintainers https://fuckcloudnative.io"
ENV PROXY_REMOTE_URL="" \
DELETE_ENABLED=""
COPY entrypoint.sh /entrypoint.sh
```
其中 `entrypoint.sh` 用來將環境變數傳入配置檔案:
{{< expand "entrypoint.sh" >}}
```bash
#!/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_YML
sed -i "/headers/a\ Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']" $CONFIG_YML
sed -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 "$@"
```
{{< /expand > }}
## 4. 啟動快取服務
構建好 Docker 映象之後,就可以啟動服務了。如果你不想自己構建,可以直接用我的映象:`yangchuansheng/registry-proxy`。
一般來說,即使你要同時快取 `docker.io`、`gcr.io`、`k8s.gcr.io`、`quay.io` 和 `ghcr.io`,一臺 `1C 2G` 的雲主機也足夠了(前提是你不在上面跑其他的服務)。我的部落格、評論服務和其他一堆亂七八糟的服務都要跑在雲主機上,所以一臺是不滿足我的需求的,我直接買了兩臺騰訊雲香港輕量級伺服器。
![](https://img2020.cnblogs.com/other/1737323/202102/1737323-20210226113337036-1470446188.png)
既然買了兩臺,肯定得[組個 k3s 叢集](https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/)啦,看主機名就知道我是用來幹啥的。其中 2C 4G 作為 master 節點,1C 2G 作為 node 節點。
以 `docker.io` 為例,建立資源清單:
{{< expand "dockerhub.yaml" >}}
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dockerhub
labels:
app: dockerhub
spec:
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: v1
kind: Service
metadata:
name: dockerhub
labels:
app: dockerhub
spec:
selector:
app: dockerhub
ports:
- protocol: TCP
name: http
port: 5000
targetPort: 5000
```
{{< /expand > }}
使用資源清單建立對應的服務:
```bash