هر مهندس DevOps در ایران این پیام را دیده است:
Error response from daemon: error from registry: 403 Forbidden
Docker Hub دسترسی IPهای ایرانی را محدود کرده است. اضافه بر این، Rate Limit برای کاربران ناشناس، کندی اینترنت بینالملل و قطعیهای ناگهانی هم وجود دارد. نتیجهاش Pipelineهایی است که بیدلیل شکست میخورند و Podهایی که در وضعیت ImagePullBackOff میمانند.
راهحل پایدار، یک لایهی Mirror داخل سازمان است: Harbor برای Imageها و Nexus برای پکیجها. در همهی پروژههایی که راهاندازی کردهام، این دو جزو اولین زیرساختها بودهاند.
معماری کلی
Developers / CI Runners / Kubernetes nodes
│
┌─────────┴─────────┐
▼ ▼
Harbor Nexus
(container images) (npm, PyPI, NuGet, Maven)
│ │
└───── server with stable upstream access ─────▶ Docker Hub, ghcr.io, npmjs, pypi.org …
فقط سرور Harbor و Nexus به منابع خارجی دسترسی دارند؛ مثلاً از طریق یک سرور خارج از کشور یا یک Proxy پایدار. بقیهی سیستمها فقط با این دو صحبت میکنند. هر Image یا پکیج یکبار از بیرون دریافت و بعد از Cache داخلی سرو میشود.
بخش اول: Harbor بهعنوان Proxy Cache
۱. تعریف Registry بالادستی
در پنل Harbor:
- Administration → Registries → New Endpoint
- نوع Provider را Docker Hub انتخاب کنید و اگر حساب Docker Hub دارید، اطلاعاتش را وارد کنید تا Rate Limit بالاتری داشته باشید.
- همین کار را برای
ghcr.io،quay.ioوregistry.k8s.ioهم تکرار کنید (نوع Docker Registry).
۲. ساخت پروژهی Proxy Cache
Projects → New Project، گزینهی Proxy Cache را فعال کنید و Endpoint مربوطه را انتخاب کنید. پیشنهاد نامگذاری:
| پروژه در Harbor | منبع |
|---|---|
dockerhub |
Docker Hub |
ghcr |
ghcr.io |
k8s |
registry.k8s.io |
quay |
quay.io |
۳. استفاده
# before
docker pull nginx:1.27
# after (official images live under "library/")
docker pull harbor.example.ir/dockerhub/library/nginx:1.27
docker pull harbor.example.ir/ghcr/aquasecurity/trivy-db:2
بخش دوم: Kubernetes بدون تغییر Manifestها
عوض کردن آدرس همهی Imageها در همهی Helm Chartها عملی نیست؛ بهخصوص برای Chartهای آماده مثل kube-prometheus-stack. راه بهتر این است که containerd روی هر Node، درخواستهای docker.io را خودش به Harbor بفرستد.
در containerd نسخهی 1.7 مسیر پیکربندی را در /etc/containerd/config.toml فعال کنید:
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
سپس برای هر Registry یک فایل hosts.toml بسازید:
# /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://registry-1.docker.io"
[host."https://harbor.example.ir/v2/dockerhub"]
capabilities = ["pull", "resolve"]
override_path = true
# /etc/containerd/certs.d/registry.k8s.io/hosts.toml
server = "https://registry.k8s.io"
[host."https://harbor.example.ir/v2/k8s"]
capabilities = ["pull", "resolve"]
override_path = true
sudo systemctl restart containerd
# test from the node
sudo crictl pull nginx:1.27
حالا هر Pod که image: nginx:1.27 دارد، بیآنکه چیزی در Manifestش عوض شود، از Harbor دریافت میشود. این تنظیم را حتماً در Ansible یا ابزار IaC خودتان بنویسید تا Nodeهای جدید هم خودکار آن را داشته باشند.
بخش سوم: Nexus برای پکیجها
Docker فقط نیمی از ماجراست. npm install، pip install و dotnet restore هم به اینترنت خارجی نیاز دارند. Sonatype Nexus Repository برای هر اکوسیستم یک Proxy Repository میسازد:
| اکوسیستم | Repository در Nexus | منبع |
|---|---|---|
| npm | npm-proxy |
https://registry.npmjs.org |
| PyPI | pypi-proxy |
https://pypi.org |
| NuGet | nuget-proxy |
https://api.nuget.org/v3/index.json |
| Maven | maven-proxy |
https://repo1.maven.org/maven2/ |
برای هر کدام یک Group Repository هم بسازید که Proxy و پکیجهای داخلی سازمان (Hosted) را با یک آدرس سرو کند.
تنظیم کلاینتها:
# npm (.npmrc)
registry=https://nexus.example.ir/repository/npm-group/
# pip (/etc/pip.conf or ~/.config/pip/pip.conf)
[global]
index-url = https://nexus.example.ir/repository/pypi-group/simple
<!-- NuGet: nuget.config -->
<configuration>
<packageSources>
<clear />
<add key="nexus" value="https://nexus.example.ir/repository/nuget-group/index.json" />
</packageSources>
</configuration>
نکات نگهداری
- Garbage Collection در Harbor را هفتگی زمانبندی کنید و برای پروژههای Proxy، Retention Policy بگذارید (مثلاً حذف Imageهایی که ۹۰ روز Pull نشدهاند).
- Storage را روی MinIO یا یک دیسک جدا بگذارید و از دیتابیس Harbor و Nexus بکاپ منظم بگیرید.
- Vulnerability Scanning: Harbor بهصورت داخلی از Trivy پشتیبانی میکند. اسکن خودکار هنگام Push را فعال کنید.
- High Availability: اگر کل سازمان به این دو سرویس وابسته است، برای آنها هم مانیتورینگ و Alert تعریف کنید. قطعی Harbor یعنی هیچ Podی نمیتواند Image جدید بگیرد.
جمعبندی
Harbor و Nexus برای تیمهای ایرانی یک انتخاب لوکس نیستند؛ زیرساخت پایهاند. یکبار راهاندازی درست، Pipelineها را سریعتر، Deployها را قابل اعتماد و کل تیم را از نوسانات اینترنت بینالملل مستقل میکند.