ایران‌ویا
مقالات آموزشی

میرور داکر هاب: رفع تحریم داکر و دریافت سریع ایمیج

۱۰ دقیقه
میرور داکر هاب: رفع تحریم داکر و دریافت سریع ایمیج

برای عبور از تحریم داکر هاب در ایران کافی است آدرس docker.novin.cloud را به ابتدای نام ایمیج اضافه کنید یا آن را به عنوان میرور پیش فرض در فایل daemon.json ثبت کنید. میرور داکر نوین کلاد (Novin Cloud) بدون ثبت نام و بدون تحریم شکن کار می کند، بر پایه استاندارد Docker Registry v2 ساخته شده و همه دستورهای docker pull را از زیرساخت داخلی سرو می کند؛ یعنی بیلدهای شما به جای شکست خوردن، در چند ثانیه تمام می شوند.

در ادامه هر دو روش پیکربندی، تنظیمات containerd و کوبرنتیز، میرور رجیستری های دیگر مثل ghcr و quay، و یک بخش عیب یابی کاربردی را مرور می کنیم. اگر پیش تر مشکل نصب پکیج های npm در ایران را با میرور حل کرده اید، منطق این مقاله برایتان آشناست؛ فقط لایه ابزار عوض شده است.

چرا docker pull در ایران شکست می خورد؟

وقتی دستور docker pull nginx را اجرا می کنید، داکر پشت صحنه به registry-1.docker.io وصل می شود، یک توکن ناشناس می گیرد و بعد لایه های ایمیج را از شبکه توزیع محتوای داکر هاب دانلود می کند. از داخل ایران هر سه مرحله می تواند شکست بخورد: دسترسی از سمت سرویس دهنده محدود شده است، مسیر شبکه پرتاخیر است و دانلود لایه های چندصد مگابایتی نیمه کاره قطع می شود.

به این ها یک محدودیت رسمی هم اضافه کنید: داکر هاب برای کاربران احراز هویت نشده سقف صد pull در هر بازه شش ساعته به ازای هر آدرس IPv4 (یا هر ساب نت 64/ در IPv6) تعیین کرده و برای حساب های شخصی رایگان این عدد دویست pull در شش ساعت است. در یک شبکه اداری که ده ها توسعه دهنده و رانر CI پشت یک IP مشترک هستند، این سقف خیلی زودتر از چیزی که فکر می کنید پر می شود و پاسخ 429 می گیرید.

سه خطای رایجی که احتمالا دیده اید

پیام خطاعلت اصلیراه حل
error pulling image configuration ... 403 Forbiddenمحدودیت جغرافیایی سمت رجیستریاستفاده از میرور داخلی
net/http: TLS handshake timeoutقطعی یا تاخیر مسیر بین المللیاستفاده از میرور داخلی
toomanyrequests: You have reached your pull rate limitعبور از سقف pull داکر هابکش شدن ایمیج ها روی میرور

نکته مهم این است که هیچ کدام از این سه مورد با ری استارت کردن داکر یا تغییر DNS حل نمی شود. تنها راه پایدار، عوض کردن مبدا دریافت ایمیج است.

میرور رجیستری داکر چیست و چطور کار می کند؟

میرور رجیستری (Registry Mirror) که به آن کش عبوری یا pull-through cache هم می گویند، یک رجیستری واسط است که بین کلاینت داکر شما و رجیستری بالادستی می نشیند. اولین باری که ایمیجی درخواست می شود، میرور آن را از منبع اصلی می گیرد، روی دیسک خودش نگه می دارد و به شما تحویل می دهد. دفعه های بعد همان ایمیج مستقیم از حافظه داخلی سرو می شود.

دو نکته را از ابتدا بدانید تا انتظار اشتباه نداشته باشید. اول اینکه میرور فقط برای دریافت (pull) است و امکان docker push روی آن وجود ندارد؛ برای انتشار ایمیج های خصوصی خودتان به یک رجیستری اختصاصی نیاز دارید. دوم اینکه در استاندارد داکر، کلید registry-mirrors فقط روی ایمیج هایی اثر می گذارد که از داکر هاب می آیند و ایمیج هایی مثل ghcr.io/owner/app را شامل نمی شود. توضیح رسمی این رفتار را می توانید در مستندات داکر بخوانید. برای آن رجیستری ها از مسیرهای جداگانه میرور استفاده می کنیم که در ادامه می آید.

مخزن داکر نوین کلاد دقیقا همین نقش را ایفا می کند: عمومی است، نیاز به لاگین ندارد و روی زیرساخت داخلی اجرا می شود. اگر سرور یا کلاستر شما هم روی همین زیرساخت باشد، مسیر دریافت ایمیج تقریبا داخل شبکه طی می شود.

روش اول: استفاده مستقیم از دامنه میرور بدون تغییر تنظیمات

ساده ترین راه، که حتی روی لپ تاپ شخصی و بدون دسترسی روت هم کار می کند، این است که نام میرور را به ابتدای نام ایمیج بچسبانید. هیچ فایلی را ویرایش نمی کنید و هیچ سرویسی را ری استارت نمی کنید.

docker pull docker.novin.cloud/library/nginx
docker pull docker.novin.cloud/hello-world
docker pull docker.novin.cloud/bitnami/postgresql

مسیر عمومی میرور هم در دسترس است و همان محتوا را سرو می کند؛ این شکل طولانی تر ولی صریح تر است:

docker pull mirror.novin.cloud/docker/library/nginx

همین روش را می توانید در Dockerfile هم به کار ببرید تا مرحله بیلد در هر محیطی قابل تکرار باشد:

FROM docker.novin.cloud/library/node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]

اگر با curl مسیر /v2/ را صدا بزنید و پاسخ 401 بگیرید نگران نشوید؛ این بخشی از فرایند استاندارد دریافت توکن در پروتکل داکر است و خود کلاینت داکر آن را خودکار انجام می دهد. جزئیات بیشتر در مستندات داکر و OCI نوین کلاد آمده است.

روش دوم: تنظیم میرور سراسری در daemon.json

اگر می خواهید همه دستورهای docker pull روی یک سرور بدون تغییر نام ایمیج از میرور عبور کنند، میرور را در سطح دیمن داکر ثبت کنید. این روش برای سرورهای تیمی، ماشین های بیلد و سرورهای مجازی بهترین گزینه است، چون کد و مانیفست های شما دست نخورده باقی می مانند.

  1. فایل /etc/docker/daemon.json را باز کنید (اگر وجود ندارد بسازید).
  2. کلید registry-mirrors را اضافه کنید.
  3. سرویس داکر را ری استارت کنید.
  4. با یک pull آزمایشی نتیجه را بررسی کنید.
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
  "registry-mirrors": ["https://docker.novin.cloud"]
}
EOF

sudo systemctl restart docker

اگر از قبل کلیدهای دیگری مثل log-driver در این فایل دارید، حتما آن ها را حفظ کنید؛ بازنویسی کامل فایل یکی از رایج ترین اشتباه ها در این مرحله است. برای اطمینان از درستی JSON پیش از ری استارت، از jq کمک بگیرید.

jq . /etc/docker/daemon.json
docker info | grep -A2 "Registry Mirrors"
docker pull hello-world

خروجی docker info باید آدرس میرور را نشان دهد. از این لحظه به بعد دستور ساده docker pull redis:7 هم بدون هیچ پیشوندی از میرور داخلی دریافت می شود.

برگشت به حالت قبل

برای بازگشت کافی است کلید registry-mirrors را از فایل حذف و سرویس را ری استارت کنید. pullهای مستقیم با پیشوند دامنه هم نیازی به بازگشت ندارند؛ فقط دوباره نام کامل docker.io/... را به کار ببرید.

پیکربندی containerd و نودهای کوبرنتیز

کلاسترهای امروزی کوبرنتیز به جای داکر از containerd استفاده می کنند، بنابراین تنظیم daemon.json روی نود آن ها اثری ندارد. برای containerd دو روش وجود دارد. روش قدیمی تر در فایل /etc/containerd/config.toml:

[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
  endpoint = ["https://docker.novin.cloud"]

روش جدیدتر و توصیه شده، فایل hosts.toml در مسیر /etc/containerd/certs.d/docker.io/hosts.toml است که مدیریت آن با ابزارهای پیکربندی تمیزتر انجام می شود:

server = "https://docker.io"

[host."https://docker.novin.cloud"]
  capabilities = ["pull", "resolve"]
sudo systemctl restart containerd
sudo ctr images pull docker.io/library/alpine:3.20

روی کلاستر، همین فایل را با Ansible یا داخل ایمیج پایه نود توزیع کنید تا همه پادها بدون تغییر در مانیفست از میرور pull کنند. اگر کلاستر را با kubeadm بالا می آورید، ایمیج های سیستمی مثل pause و etcd هم باید از میرور بیایند:

kubeadm init --image-repository mirror.novin.cloud/docker-k8s
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "mirror.novin.cloud/docker-k8s/pause:3.10"

راهنمای گام به گام بالا آوردن کلاستر را در مقاله راه اندازی سریع کوبرنتیز توضیح داده ایم و اگر ترجیح می دهید خودتان درگیر نگهداری کنترل پلین نشوید، کوبرنتیز مدیریت شده همین تنظیمات را از پیش روی نودها دارد. جزئیات فنی کامل هم در مستندات containerd و مستندات کوبرنتیز در دسترس است.

میرور بقیه رجیستری ها: ghcr، quay، gcr و بقیه

همان طور که گفتیم کلید registry-mirrors فقط داکر هاب را پوشش می دهد. برای رجیستری های دیگر، هر کدام مخزن جداگانه ای دارند و کافی است نام ایمیج را بازنویسی کنید:

رجیستری بالادستینام مخزن میرورنمونه دستور
ghcr.iodocker-ghcrmirror.novin.cloud/docker-ghcr/owner/image
quay.iodocker-quaymirror.novin.cloud/docker-quay/prometheus/busybox
gcr.iodocker-gcrmirror.novin.cloud/docker-gcr/project/image
registry.k8s.iodocker-k8smirror.novin.cloud/docker-k8s/pause:3.10
mcr.microsoft.comdocker-mcrmirror.novin.cloud/docker-mcr/dotnet/sdk
nvcr.iodocker-nvidiamirror.novin.cloud/docker-nvidia/nvidia/cuda
registry.redhat.iodocker-redhatmirror.novin.cloud/docker-redhat/ubi9/ubi
registry.gitlab.comdocker-gitlabmirror.novin.cloud/docker-gitlab/group/project
public.ecr.awsdocker-ecr-publicmirror.novin.cloud/docker-ecr-public/ns/image

نصب خود Docker Engine از میرور

روی سروری که تازه تحویل گرفته اید، حتی نصب خود داکر هم ممکن است به مشکل بخورد چون download.docker.com در دسترس نیست. مخزن apt داکر هم میرور شده است:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://mirror.novin.cloud/docker-apt-ubuntu/gpg |   sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://mirror.novin.cloud/docker-apt-ubuntu noble stable" |   sudo tee /etc/apt/sources.list.d/docker.list

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

روی CentOS و RHEL هم مخزن های docker-yum-centos و docker-yum-rhel همان چیدمان مسیرهای رسمی را دارند. باینری های استاتیک داکر نیز از مسیر mirror.novin.cloud/docker-static-binaries/ قابل دریافت هستند. فهرست کامل مخزن ها در سرویس میرورها و مستندات فهرست مخزن ها آمده است.

استفاده در خط CI/CD

بیشترین سود میرور در خط لوله CI دیده می شود، جایی که هر کامیت یک بیلد تازه راه می اندازد و شکست در مرحله pull یعنی شکست کل بیلد. در GitLab Runner کافی است پیشوند ایمیج را عوض کنید و دیگر نیازی به احراز هویت یا تحریم شکن نخواهید داشت:

build:
  image: docker.novin.cloud/library/node:20
  script:
    - npm ci
    - npm run build

اگر رانرها را خودتان روی سرور مدیریت می کنید، بهتر است میرور را یک بار در daemon.json همان ماشین ثبت کنید تا همه پروژه ها بدون تغییر فایل پیکربندی از آن بهره ببرند. برای تیم های کوچک و استارتاپ ها همین یک تغییر معمولا چند دقیقه از زمان هر بیلد کم می کند و نرخ شکست بیلدهای شبانه را به شکل محسوسی پایین می آورد.

عیب یابی: وقتی میرور کار نمی کند

اگر بعد از پیکربندی هنوز خطا می گیرید، این چهار مورد را به ترتیب بررسی کنید.

  1. JSON نامعتبر: اگر daemon.json خراب باشد، سرویس داکر اصلا بالا نمی آید. با systemctl status docker و journalctl -u docker -n 50 لاگ را ببینید.
  2. ایمیج از رجیستری دیگری می آید: اگر نام ایمیج با ghcr.io یا quay.io شروع شود، کلید میرور روی آن اثر ندارد. از جدول مخزن ها استفاده کنید.
  3. کش لایه های قدیمی: با docker pull دوباره و بررسی خروجی docker image inspect مطمئن شوید که دایجست ایمیج همانی است که انتظار دارید.
  4. پروکسی یا فایروال محلی: اگر روی سرور متغیرهای HTTP_PROXY تنظیم شده اند، ممکن است ترافیک میرور هم از همان مسیر برود. متغیرهای محیطی سرویس داکر را در /etc/systemd/system/docker.service.d/ بررسی کنید.

برای بررسی نهایی، دایجست ایمیج را مقایسه کنید. محتوای دریافتی از میرور باید دقیقا همان چیزی باشد که از منبع اصلی می آمد:

docker pull docker.novin.cloud/library/hello-world
docker image inspect hello-world --format '{{.RepoDigests}}'

سؤالات متداول

آیا برای استفاده از میرور داکر نوین کلاد باید ثبت نام کنم؟

خیر. مخزن داکر عمومی است و docker pull بدون لاگین کار می کند. اگر با curl مسیر /v2/ را صدا بزنید و 401 ببینید، این پاسخ طبیعی است و بخشی از فرایند دریافت توکن ناشناس در پروتکل استاندارد داکر محسوب می شود.

آیا می توانم ایمیج خودم را روی این میرور push کنم؟

خیر. میرور فقط کش عبوری برای دریافت ایمیج است و عملیات push روی آن پشتیبانی نمی شود. برای نگهداری ایمیج های خصوصی به یک رجیستری اختصاصی نیاز دارید که معمولا روی سرور یا کلاستر خودتان اجرا می شود.

تنظیم registry-mirrors روی ایمیج های ghcr.io هم اثر دارد؟

نه. طبق طراحی خود داکر، کلید registry-mirrors فقط برای ایمیج هایی به کار می رود که مبدا آن ها داکر هاب است. برای ghcr، quay، gcr و بقیه باید نام ایمیج را با پیشوند مخزن مربوطه بازنویسی کنید.

برای کوبرنتیز کدام روش درست است؟

اگر نودها از containerd استفاده می کنند (که در نسخه های جدید کوبرنتیز پیش فرض است)، باید hosts.toml یا بلوک registry.mirrors را در containerd تنظیم کنید؛ فایل daemon.json روی این نودها اثری ندارد. ایمیج های سیستمی کلاستر هم باید از مخزن docker-k8s بیایند.

آیا استفاده از میرور سرعت بیلد را واقعا زیاد می کند؟

در عمل بیشترین تفاوت از حذف شکست ها و تلاش های دوباره می آید، نه صرفا از پهنای باند. وقتی مرحله pull قابل پیش بینی شد، زمان کل بیلد هم پایدار می شود. میزان دقیق بهبود به حجم ایمیج، مسیر شبکه و محل قرارگیری سرور شما بستگی دارد، بنابراین بهتر است پیش و پس از تغییر، زمان همان بیلد را خودتان اندازه بگیرید.

جمع بندی

تحریم داکر هاب یک مشکل شبکه ای نیست که با DNS یا ری استارت حل شود؛ راه حل درست، عوض کردن مبدا دریافت ایمیج است. با یک خط تغییر در daemon.json یا اضافه کردن پیشوند docker.novin.cloud به نام ایمیج، هم خطاهای 403 و timeout را کنار می گذارید و هم دیگر درگیر سقف صد pull در شش ساعت داکر هاب نمی شوید. برای نودهای کوبرنتیز همین کار را در containerd انجام دهید و ایمیج های سیستمی را از مخزن docker-k8s بگیرید.

نوین کلاد (Novin Cloud) که کاربران گاهی نام آن را ابرنوین یا نوین کلود هم می نویسند، این میرور را به صورت عمومی و بدون نیاز به ثبت نام ارائه می کند. برای شروع، صفحه مخزن داکر نوین کلاد را ببینید یا مستقیم اولین ایمیج خود را از docker.novin.cloud دریافت کنید.