- LoopX
- داکر از صفر تا حرفهای
- مبانی داکر
- تنظیم میرور برای دانلود image در ایران
تنظیم میرور برای دانلود image در ایران
توی این درس یاد میگیری چرا ممکن است docker pull در ایران خطا بدهد یا خیلی کند باشد، میرور (mirror) چیست و چطور با کلید registry-mirrors در فایل daemon.json تنظیمش میکنی، در Docker Desktop و روی لینوکس، چطور تنظیم را با docker info بررسی کنی، و چرا یک میرور خراب میتواند کل دانلودهایت را از کار بیندازد. در انتها هم یک روش تست دسترسی به registry داری که در هر شبکهای جواب میدهد.
مشکل از کجاست؟
Section titled “مشکل از کجاست؟”وقتی docker pull nginx را میزنی، daemon به registry (بهصورت پیشفرض Docker Hub) وصل میشود و image را دانلود میکند. اگر آن اتصال از شبکهی تو عبور نکند یا خیلی کند باشد، دو حالت دارد: دانلود بعد از مدتی timeout میشود و خطا میدهد، یا بسیار آهسته پیش میرود. بدون image، کل داکر بلااستفاده است، چون هر docker run به یک image نیاز دارد.
میرور یک registry دیگر است که نسخهی کششدهی image های Docker Hub را نگه میدارد و از شبکهی تو قابل دسترستر است. مثل یک شعبهی محلی کتابخانهی مرکزی: بهجای رفتن تا ساختمان اصلی، کتاب را از شعبهی نزدیک میگیری.
مثالهای عملی
Section titled “مثالهای عملی”مثال ۱: تشخیص: registry در دسترس است؟
Section titled “مثال ۱: تشخیص: registry در دسترس است؟”قبل از هر تنظیمی، مطمئن شو مشکل دسترسی است. API هر registry روی مسیر /v2/ است و جواب 401 یعنی «زنده است و احراز هویت میخواهد»؛ پس رسیدن به آن یعنی اتصال برقرار است:
curl -s -o /dev/null -m 15 -w "Docker Hub: HTTP %{http_code}\n" https://registry-1.docker.io/v2/Docker Hub: HTTP 401401 یعنی رسیدی. اگر بعد از چند ثانیه هیچ جوابی نیامد، یا 000 گرفتی (یعنی اتصال برقرار نشد)، مشکل دسترسی است. در شبکهای که Docker Hub مشکل داشته باشد، خطای docker pull معمولاً از این جنس است (متن دقیق بسته به نسخه و شبکه فرق میکند):
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)مثال ۲: فایل daemon.json روی لینوکس
Section titled “مثال ۲: فایل daemon.json روی لینوکس”روی لینوکس تنظیمات daemon در /etc/docker/daemon.json است (طبق مستندات داکر). فایل را با sudo nano ویرایش میکنی؛ من برای تست خودکار با tee مینویسم و بعد صحت JSON را میسنجم:
sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json > /dev/null <<'EOT'{ "registry-mirrors": ["https://mirror.example.ir"]}EOTcat /etc/docker/daemon.jsonpython3 -m json.tool /etc/docker/daemon.json > /dev/null && echo "JSON معتبر است"sudo rm /etc/docker/daemon.json{ "registry-mirrors": ["https://mirror.example.ir"]}JSON معتبر استکلید registry-mirrors یک آرایه است؛ میتوانی چند میرور بدهی. فایل باید JSON معتبر باشد (ویرگول و گیومه!)؛ یک ویرگول اضافه یا کم، daemon را از بالا آمدن بازمیدارد (مثال ۴).
مثال ۳: اعمال تنظیم و دیدنش با docker info
Section titled “مثال ۳: اعمال تنظیم و دیدنش با docker info”روی یک daemon ایزوله (که نمیخواهم داکر اصلیات را تغییر بدهم) تنظیم را اعمال میکنیم. اول فایل را مینویسیم ولی هنوز daemon را بهروز نمیکنیم:
cat > /etc/docker/daemon.json <<'EOT'{ "registry-mirrors": ["https://mirror.example.ir"]}EOTecho "قبل از reload:"; docker info 2>/dev/null | grep -A1 "Registry Mirrors" || echo "(هیچ میرور فعالی نیست)"kill -HUP $(pidof dockerd); sleep 2echo "بعد از reload:"; docker info 2>/dev/null | grep -A1 "Registry Mirrors"قبل از reload:(هیچ میرور فعالی نیست)بعد از reload: Registry Mirrors: https://mirror.example.ir/نکتهی مهم: نوشتن فایل کافی نیست. daemon فقط وقتی تنظیم را میخواند که به آن بگویی. روی لینوکس معمولاً sudo systemctl restart docker میزنی (روی سیستم خودت؛ داخل این کانتینر آزمایشی systemd نیست و از سیگنال reload استفاده کردم)، و در Docker Desktop دکمهی Apply & restart همین کار را میکند.
فایل daemon.json را با میرور ویرایش و ذخیره کردی ولی docker info هیچ میرور نشان نمیدهد. محتملترین علت؟
daemon فقط موقع شروع (یا reload) فایل را میخواند. بعد از تغییر، آن را restart کن.
مثال ۴: قبل از restart، فایل را بسنج
Section titled “مثال ۴: قبل از restart، فایل را بسنج”یک JSON خراب باعث میشود daemon بالا نیاید و همهی کانتینرها از کار بیفتند. daemon خودش یک دستور اعتبارسنجی دارد:
echo '{ "registry-mirrors": ["https://mirror.example.ir" ' > /var/tmp/bad.jsondockerd --validate --config-file /var/tmp/bad.json 2>&1 | head -2echo '{"registry-mirrors":["https://mirror.example.ir"]}' > /var/tmp/good.jsondockerd --validate --config-file /var/tmp/good.json 2>&1 | head -2unable to configure the Docker daemon with file /var/tmp/bad.json: invalid JSON: unexpected end of JSON inputconfiguration OKاول invalid JSON، دومی configuration OK. روی سرور واقعی قبل از systemctl restart docker همین را بزن. (این دستور را با sudo dockerd --validate --config-file /etc/docker/daemon.json روی لینوکس خودت اجرا کن.)
مثال ۵: Docker Desktop (مک و ویندوز)
Section titled “مثال ۵: Docker Desktop (مک و ویندوز)”در Docker Desktop فایلی برای ویرایش دستی لازم نیست. طبق مستندات داکر: Settings ← Docker Engine را باز کن، همان JSON را در ویرایشگر داخل برنامه میبینی. کلید registry-mirrors را اضافه کن و Apply & restart را بزن. بعد با docker info در ترمینال بررسی کن (مثال ۳).
{ "registry-mirrors": ["https://mirror.example.ir"]}اگر ویرایشگر JSON از قبل کلیدهای دیگری دارد (مثل builder)، آنها را نگه دار و فقط کلید جدید را اضافه کن؛ بین کلیدها ویرگول لازم است.
مثال ۶: میرور نامعتبر چه میکند؟ (اجرای واقعی)
Section titled “مثال ۶: میرور نامعتبر چه میکند؟ (اجرای واقعی)”روی همان daemon ایزوله، یک میرور که وجود ندارد (آدرس نمونه) تنظیم کردهایم. ببین pull چه میشود و چقدر طول میکشد:
docker rmi alpine >/dev/null 2>&1start=$(date +%s)docker pull alpine 2>&1 | tail -1echo "زمان: $(( $(date +%s) - start )) ثانیه"docker.io/library/alpine:latestزمان: 11 ثانیهدر این اجرا pull بالاخره موفق شد (daemon بعد از شکست میرور به Docker Hub برگشت)، ولی مجبور شد اول به میرور مرده سر بزند. در یک اجرای دیگرِ همان تست، با همین تنظیم یک بار خطای سخت گرفتم (متن ثبتشده در همان تست، نه خروجی اجرای بالا):
Error response from daemon: failed to resolve reference "docker.io/library/alpine:latest": failed to do request: Head "https://mirror.example.ir/v2/library/alpine/manifests/latest?ns=docker.io": dial tcp: lookup mirror.example.ir: no such hostیعنی رفتار یک میرور مرده قابلپیشبینی نیست: ممکن است تأخیر بیندازد یا pull را شکست بدهد. نتیجه: میرور را قبل از گذاشتن تست کن.
حالا برش گردانیم. نکتهی مهم: حذف خود فایل و reload، میرور را پاک نمیکند (daemon فایل ناموجود را نمیخواند و تنظیم قبلی را نگه میدارد). باید فایل را با آرایهی خالی بنویسی (یا daemon را کامل restart کنی):
echo '{"registry-mirrors":[]}' > /etc/docker/daemon.jsonkill -HUP $(pidof dockerd); sleep 2echo "میرورهای فعال: $(docker info 2>/dev/null | grep -c 'Registry Mirrors')"میرورهای فعال: 0شمارنده 0 است؛ دیگر میرور فعالی نیست.
پشت پرده: میرور چطور کار میکند؟
Section titled “پشت پرده: میرور چطور کار میکند؟”میرور یک pull-through cache است. مستندات رسمی داکر میگوید: اولین باری که یک image را از میرور محلی بخواهی، میرور آن را از registry عمومی میگیرد، نزد خودش ذخیره میکند و بعد به تو میدهد. دفعات بعد از کش جواب میدهد. در خطای مثال ۶ هم ردش را دیدی: daemon به آدرس https://mirror.example.ir/v2/library/alpine/manifests/latest?ns=docker.io درخواست زد؛ پارامتر ns=docker.io به میرور میگوید «این از Docker Hub است».
مهم است بدانی:
registry-mirrorsفقط برای image های Docker Hub است. image هایی که آدرس registry دیگری دارند (مثلghcr.io/...) از میرور نمیگذرند.- میرور باید HTTPS باشد (یا بهعنوان
insecure-registriesاعلام شود که توصیه نمیشود). - میرور شخص ثالث میتواند نظریاً image را دستکاری کند. برای image های مهم، از digest استفاده کن (
image@sha256:...) تا مطمئن باشی همان چیزی را گرفتهای که انتظار داری. (در درس «محدودیت Docker Hub و راهحلها» بیشتر میگوییم.)
جدولهای مرجع
Section titled “جدولهای مرجع”کجا و چطور تنظیم کنم؟
Section titled “کجا و چطور تنظیم کنم؟”| سیستم | محل تنظیم | اعمال تغییر |
|---|---|---|
| لینوکس (Engine) | /etc/docker/daemon.json |
sudo systemctl restart docker |
| Docker Desktop (مک و ویندوز) | Settings ← Docker Engine | Apply & restart |
دستورهای تشخیص و بررسی
Section titled “دستورهای تشخیص و بررسی”| دستور | کاربرد |
|---|---|
curl -s -o /dev/null -w "%{http_code}\n" https://registry-1.docker.io/v2/ |
تست رسیدن به Docker Hub (401 = رسیده) |
docker info | grep -A3 Mirrors |
دیدن میرورهای فعال |
dockerd --validate --config-file FILE |
اعتبارسنجی daemon.json قبل از restart |
python3 -m json.tool FILE |
بررسی سادهی صحت JSON |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) JSON خراب
Section titled “۱) JSON خراب”echo '{"registry-mirrors": ["https://mirror.example.ir",]}' > /var/tmp/trailing.jsondockerd --validate --config-file /var/tmp/trailing.json 2>&1 | head -2unable to configure the Docker daemon with file /var/tmp/trailing.json: invalid JSON: invalid character ']' looking for beginning of valueویرگول اضافه بعد از آخرین عضو، JSON را نامعتبر میکند. راهحل: همیشه با --validate یا python3 -m json.tool بسنج.
۲) میرور مرده یا نامعتبر
Section titled “۲) میرور مرده یا نامعتبر”مثال ۶ را ببین: میرور غیرقابلدسترس تأخیر میاندازد یا pull را شکست میدهد. راهحل: قبل از گذاشتن، با curl آدرس /v2/ میرور را تست کن (جواب 200 یا 401 یعنی زنده است)، و اگر مشکلساز شد فوراً برش دار.
۳) فراموش کردن reload
Section titled “۳) فراموش کردن reload”فایل را ذخیره کردی ولی تنظیم اعمال نشده (مثال ۳، «قبل از reload»). راهحل: restart (لینوکس) یا Apply & restart (Docker Desktop)، بعد docker info.
۴) فکر کردن «حذف فایل، میرور را پاک میکند»
Section titled “۴) فکر کردن «حذف فایل، میرور را پاک میکند»”حذف daemon.json و reload کافی نیست (آخر مثال ۶). راهحل: آرایهی خالی بنویس یا daemon را restart کن، بعد docker info را بررسی کن.
۵) ویرایش با ویرایشگر اشتباه روی Docker Desktop
Section titled “۵) ویرایش با ویرایشگر اشتباه روی Docker Desktop”در Docker Desktop فایل daemon.json را از Finder یا Explorer ویرایش نکن؛ از Settings ← Docker Engine استفاده کن تا تغییر درست اعمال شود.
بدون هیچ تنظیمی، با curl ثابت کن به Docker Hub دسترسی داری (فقط کد HTTP را چاپ کن).
دیدن جواب
curl -s -o /dev/null -m 15 -w "%{http_code}\n" https://registry-1.docker.io/v2/401401 یعنی رسیدی. اگر به اینجا نرسیدی، به بخش «داکر در ایران» برگرد.
روی daemon آزمایشی، یک میرور نمونه را در daemon.json بگذار، daemon را reload کن و فقط خطوط مربوط به میرور را از docker info نشان بده. بعد برش دار.
دیدن جواب
echo '{"registry-mirrors":["https://mirror.example.ir"]}' > /etc/docker/daemon.jsonkill -HUP $(pidof dockerd); sleep 2docker info 2>/dev/null | grep -A1 "Registry Mirrors"echo '{"registry-mirrors":[]}' > /etc/docker/daemon.json; kill -HUP $(pidof dockerd); sleep 2docker info 2>/dev/null | grep -c "Registry Mirrors" Registry Mirrors: https://mirror.example.ir/0روی daemon آزمایشی یک فایل با دو میرور نامعتبر بنویس. ثابت کن --validate آن را «OK» میداند (چون ساختار درست است) و docker info هر دو را نشان میدهد. بعد توضیح بده چرا --validate برای سلامت میرور کافی نیست و آخر کار تنظیم را پاک کن.
دیدن جواب
cat > /var/tmp/two.json <<'EOT'{"registry-mirrors":["https://mirror-a.example.ir","https://mirror-b.example.ir"]}EOTdockerd --validate --config-file /var/tmp/two.json 2>&1 | head -1cp /var/tmp/two.json /etc/docker/daemon.json; kill -HUP $(pidof dockerd); sleep 2docker info 2>/dev/null | grep -A2 "Registry Mirrors"echo '{"registry-mirrors":[]}' > /etc/docker/daemon.json; kill -HUP $(pidof dockerd); sleep 2docker info 2>/dev/null | grep -c "Registry Mirrors"configuration OK Registry Mirrors: https://mirror-a.example.ir/ https://mirror-b.example.ir/0--validate فقط ساختار فایل (JSON و کلیدها) را میسنجد، نه اینکه آدرسها زندهاند. برای سلامت میرور باید جداگانه با curl به مسیر /v2/ هر کدام درخواست بزنی (کد 200 یا 401 یعنی زنده).
آزمونک
Section titled “آزمونک”میرور (mirror) چیست؟
میرور مثل شعبهی محلی است: اولین بار از Docker Hub میگیرد، کش میکند و بعد از کش جواب میدهد.
کلید تنظیم میرور در daemon.json کدام است؟
"registry-mirrors": ["https://..."]؛ یک آرایه.
کد HTTP «401» از https://registry-1.docker.io/v2/ یعنی چه؟
رسیدن به API با جواب 401 یعنی اتصال برقرار است.
اگر daemon.json را پاک کنی و daemon را reload کنی، میرور قبلی…
در تست، بعد از حذف فایل و reload، میرور هنوز در docker info بود.
قبل از restart کردن daemon بهتر است چه کنی؟
یک JSON خراب باعث میشود daemon بالا نیاید.
جمعبندی
Section titled “جمعبندی”- در شبکهای که Docker Hub مشکل دارد،
docker pulltimeout میشود؛ اول باcurl .../v2/تشخیص بده. - میرور یک registry کشدار برای image های Docker Hub است؛ در
daemon.jsonبا کلیدregistry-mirrors(آرایه) تنظیم میشود. - لینوکس:
/etc/docker/daemon.json+sudo systemctl restart docker؛ Docker Desktop: Settings ← Docker Engine ← Apply & restart. - با
docker infoمیرور فعال را ببین و باdockerd --validateفایل را قبل از restart بسنج. - میرور مرده تأخیر میاندازد یا pull را شکست میدهد؛ آدرس را قبل از استفاده تست کن. برای پاک کردن میرور، آرایهی خالی بنویس (فقط حذف فایل کافی نیست).
- میرور شخص ثالث را با احتیاط انتخاب کن و برای image های مهم از digest استفاده کن.
| دستور | کاری که میکند |
|---|---|
sudo nano /etc/docker/daemon.json | ویرایش تنظیمات daemon (لینوکس) |
{"registry-mirrors":["https://HOST"]} | کلید میرور در daemon.json |
sudo dockerd --validate --config-file /etc/docker/daemon.json | اعتبارسنجی فایل |
sudo systemctl restart docker | اعمال تغییرات (لینوکس) |
docker info | grep -A3 Mirrors | دیدن میرورهای فعال |
curl -s -o /dev/null -w "%{http_code}\n" https://registry-1.docker.io/v2/ | تست دسترسی به Docker Hub |
python3 -m json.tool FILE | بررسی صحت JSON |