بازگشت به وبلاگ

تنظیم پروکسی در داکر برای بارگیری تصاویر و برنامه‌های کانتینری: راهنمای کامل

نحوه تنظیم پروکسی در داکر برای دانلود تصاویر از طریق فایروال‌های شرکتی و برای برنامه‌ها درون کانتینرها را بررسی می‌کنیم - با مثال‌های پیکربندی و سناریوهای واقعی.

📅۱۵ فروردین ۱۴۰۵
```html

آیا با Docker در یک شبکه شرکتی، روی سروری با دسترسی محدود کار می‌کنید یا می‌خواهید کانتینرهای شما از طریق یک IP خاص به اینترنت دسترسی پیدا کنند؟ بدون تنظیمات صحیح پروکسی، Docker نمی‌تواند تصاویر را از Docker Hub یا هر مخزن دیگری دانلود کند. در این مقاله تمام سطوح پروکسی‌سازی را بررسی خواهیم کرد — از دیمون تا کانتینرهای جداگانه.

چرا Docker به پروکسی نیاز دارد

Docker ابزاری است که به طور مداوم به منابع خارجی مراجعه می‌کند. در هر بار docker pull یا docker build، دیمون به Docker Hub، GitHub Container Registry، Google Container Registry یا مخزن خصوصی شما مراجعه می‌کند. و در اینجا مشکلات آغاز می‌شود.

شرایطی که در آن‌ها بدون پروکسی نمی‌توان کار کرد:

  • شبکه شرکتی با فایروال — تمام ترافیک باید از طریق سرور پروکسی شرکتی عبور کند، در غیر این صورت اتصال مسدود می‌شود.
  • محدودیت‌های جغرافیایی — Docker Hub یا مخازن خاص از کشور یا دیتاسنتر شما در دسترس نیستند.
  • سرور محدود بدون دسترسی مستقیم به اینترنت — VPS در یک محیط بسته، جایی که اینترنت فقط از طریق دروازه در دسترس است.
  • کنترل ترافیک خروجی کانتینرها — شما می‌خواهید برنامه‌های داخل کانتینرها از طریق یک IP خاص به شبکه دسترسی پیدا کنند، به عنوان مثال برای تجزیه، درخواست‌های API یا آزمایش محتوای وابسته به جغرافیا.
  • ناشناس‌سازی درخواست‌ها — پنهان کردن IP واقعی سرور هنگام مراجعه به خدمات خارجی از داخل کانتینر.
  • محدودیت نرخ — Docker Hub تعداد درخواست‌های pull را برای کاربران ناشناس محدود می‌کند (100 pull در 6 ساعت). از طریق پروکسی با چرخش IP می‌توان این محدودیت را دور زد.

مهم است که درک کنیم Docker یک برنامه واحد نیست، بلکه سیستمی از چندین مؤلفه است. دیمون (dockerd) بر روی هاست زندگی می‌کند و تصاویر را بارگیری می‌کند. کانتینرها فرآیندهای ایزوله‌شده‌ای هستند که تنظیمات شبکه خود را دارند. بنابراین، تنظیم پروکسی برای دیمون و برای کانتینرها دو وظیفه متفاوت است که به روش‌های مختلفی حل می‌شود.

سه سطح پروکسی‌سازی در Docker

قبل از اینکه به تنظیمات بروید، باید معماری را درک کنید. در Docker سه سطح مستقل وجود دارد که هر کدام نیاز به تنظیمات پروکسی جداگانه دارند:

سطح چه کاری انجام می‌دهد کجا تنظیم می‌شود
دیمون Docker تصاویر را بارگیری می‌کند (docker pull)، به مخازن مراجعه می‌کند systemd override یا daemon.json
ساخت Docker دستورات را در حین ساخت تصویر اجرا می‌کند (RUN apt-get، pip install و غیره) ARG و ENV در Dockerfile یا --build-arg
کانتینر در حال اجرا برنامه‌ای که HTTP درخواست‌ها را انجام می‌دهد ENV در زمان docker run یا در docker-compose.yml

یک اشتباه رایج این است که پروکسی را فقط در یک سطح تنظیم کنید و تعجب کنید که چرا تصاویر هنوز بارگیری نمی‌شوند یا برنامه پروکسی را نمی‌بیند. بیایید هر سطح را به تفصیل بررسی کنیم.

تنظیم پروکسی برای دیمون Docker (بارگیری تصاویر)

این مهم‌ترین تنظیم است اگر می‌خواهید تصاویر را از طریق پروکسی بارگیری کنید. دیمون Docker یک سرویس سیستمی است که از طریق systemd اجرا می‌شود. متغیرهای محیطی کاربر شما یا حتی root را نمی‌بیند. باید پروکسی را به محیط سرویس منتقل کنید.

روش 1: از طریق systemd override (توصیه می‌شود)

یک دایرکتوری برای نادیده گرفتن تنظیمات سرویس ایجاد کنید:

sudo mkdir -p /etc/systemd/system/docker.service.d

یک فایل /etc/systemd/system/docker.service.d/http-proxy.conf با محتوای زیر ایجاد کنید:

[Service]
Environment="HTTP_PROXY=http://username:password@proxy-host:port"
Environment="HTTPS_PROXY=http://username:password@proxy-host:port"
Environment="NO_PROXY=localhost,127.0.0.1,::1,your-private-registry.example.com"

اگر پروکسی بدون احراز هویت است — فقط username:password@ را حذف کنید. پس از ایجاد فایل، پیکربندی systemd را دوباره بارگذاری کرده و Docker را دوباره راه‌اندازی کنید:

sudo systemctl daemon-reload
sudo systemctl restart docker

بررسی کنید که آیا تنظیمات اعمال شده‌اند:

sudo systemctl show --property=Environment docker

در خروجی باید متغیرهای شما HTTP_PROXY و HTTPS_PROXY ظاهر شوند.

روش 2: از طریق ~/.docker/config.json (Docker Desktop و نسخه‌های جدید)

از نسخه 23.0 Docker Engine یک روش راحت‌تر برای تنظیم پروکسی از طریق فایل پیکربندی کلاینت ایجاد شده است. فایل ~/.docker/config.json را ایجاد یا ویرایش کنید:

{
  "proxies": {
    "default": {
      "httpProxy": "http://username:password@proxy-host:port",
      "httpsProxy": "http://username:password@proxy-host:port",
      "noProxy": "localhost,127.0.0.1,::1"
    }
  }
}

این روش از آن جهت راحت است که نیاز به دسترسی root و راه‌اندازی مجدد دیمون ندارد. تنظیمات به طور خودکار در هنگام ساخت به کانتینرها به عنوان آرگومان‌های build منتقل می‌شوند. با این حال، برای مدیریت درخواست‌های pull خود دیمون، هنوز به روش systemd نیاز دارید.

💡 نکته مهم در مورد NO_PROXY

همیشه آدرس‌های مخازن و خدمات داخلی خود را به NO_PROXY اضافه کنید. در غیر این صورت، Docker سعی خواهد کرد به آن‌ها از طریق پروکسی دسترسی پیدا کند و خطاهای اتصال دریافت کند. لیست معمول: localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

پروکسی درون کانتینر در زمان ساخت (build-time)

زمانی که Docker یک تصویر را می‌سازد و دستورات مانند RUN apt-get install، RUN pip install یا RUN npm install را اجرا می‌کند — این دستورات درون یک کانتینر موقت اجرا می‌شوند. به طور پیش‌فرض، این کانتینر به پروکسی هاست دسترسی ندارد. باید پروکسی را به وضوح از طریق آرگومان‌های build منتقل کنید.

انتقال پروکسی از طریق --build-arg

docker build \
  --build-arg HTTP_PROXY=http://proxy-host:port \
  --build-arg HTTPS_PROXY=http://proxy-host:port \
  --build-arg NO_PROXY=localhost,127.0.0.1 \
  -t my-image .

تنظیم در Dockerfile

اگر پروکسی فقط در مرحله ساخت نیاز است و نمی‌خواهید که در تصویر نهایی قرار گیرد — از ARG به جای ENV استفاده کنید:

FROM ubuntu:22.04

# اعلام آرگومان‌های ساخت
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

# استفاده از آن‌ها در دستورات
RUN apt-get update && apt-get install -y curl wget

# پس از این بلوک، پروکسی در ENV کانتینر نخواهد بود

اما اگر پروکسی در کانتینر در حال اجرا نیز نیاز است — از ENV استفاده کنید:

FROM python:3.11

ENV HTTP_PROXY=http://proxy-host:port
ENV HTTPS_PROXY=http://proxy-host:port
ENV NO_PROXY=localhost,127.0.0.1

RUN pip install requests beautifulsoup4

CMD ["python", "app.py"]

⚠️ توجه: امنیت

نام کاربری و رمز عبور پروکسی را به طور مستقیم در Dockerfile هاردکد نکنید، اگر تصویر عمومی باشد یا به مخزن منتقل شود. از --build-arg استفاده کنید و مقادیر را از متغیرهای محیطی سیستم CI/CD منتقل کنید. دستور docker history می‌تواند مقادیر ARG را نشان دهد، بنابراین برای اسرار از Docker BuildKit secrets استفاده کنید.

پروکسی برای کانتینر در حال اجرا (runtime)

این رایج‌ترین سناریو برای برنامه‌هایی است که در حین کار HTTP درخواست‌ها را انجام می‌دهند — تجزیه‌کننده‌ها، ربات‌ها، میکروسرویس‌هایی که به خروجی از طریق یک IP خاص نیاز دارند. در اینجا تنظیمات به حداکثر سادگی است: باید متغیرهای محیطی را هنگام راه‌اندازی کانتینر منتقل کنید.

از طریق docker run

docker run \
  -e HTTP_PROXY=http://username:password@proxy-host:port \
  -e HTTPS_PROXY=http://username:password@proxy-host:port \
  -e NO_PROXY=localhost,127.0.0.1 \
  my-image

بیشتر کتابخانه‌های HTTP محبوب به طور خودکار متغیرهای HTTP_PROXY و HTTPS_PROXY را شناسایی می‌کنند: Python requests، curl، wget، net/http در Go، https-proxy-agent در Node.js و دیگران. نیازی به نوشتن هیچ چیز اضافی در کد نیست.

از طریق فایل .env

راحت‌تر است که تنظیمات را در یک فایل .env ذخیره کنید و آن را به طور کامل منتقل کنید:

# فایل .env
HTTP_PROXY=http://username:password@proxy-host:port
HTTPS_PROXY=http://username:password@proxy-host:port
NO_PROXY=localhost,127.0.0.1
docker run --env-file .env my-image

پروکسی SOCKS5 در کانتینر

اگر از پروکسی SOCKS5 استفاده می‌کنید (به عنوان مثال، پروکسی‌های مسکونی معمولاً از این پروتکل پشتیبانی می‌کنند)، سینتکس کمی متفاوت است:

docker run \
  -e ALL_PROXY=socks5://username:password@proxy-host:port \
  my-image

توجه داشته باشید: همه کتابخانه‌ها از SOCKS5 از طریق متغیر محیطی بدون وابستگی‌های اضافی پشتیبانی نمی‌کنند. Python requests نیاز به نصب requests[socks] دارد، curl باید با پشتیبانی از libcurl-socks ساخته شود.

پروکسی در Docker Compose

در پروژه‌های واقعی به ندرت از docker run خالی استفاده می‌شود. بیشتر با Docker Compose کار می‌کنند، جایی که چندین سرویس در یک فایل توصیف شده‌اند. تنظیم پروکسی در اینجا در سطح هر سرویس یا از طریق فایل متغیرها انجام می‌شود.

گزینه 1: environment در docker-compose.yml

version: '3.8'

services:
  scraper:
    image: my-scraper:latest
    environment:
      - HTTP_PROXY=http://username:password@proxy-host:port
      - HTTPS_PROXY=http://username:password@proxy-host:port
      - NO_PROXY=localhost,127.0.0.1
    restart: unless-stopped

  api:
    image: my-api:latest
    # این سرویس بدون پروکسی است — فقط به منابع داخلی مراجعه می‌کند
    ports:
      - "8080:8080"

گزینه 2: از طریق فایل .env (توصیه می‌شود)

یک .env در دایرکتوری با docker-compose.yml ایجاد کنید. Docker Compose به طور خودکار این فایل را شناسایی می‌کند:

# .env
PROXY_HOST=proxy-host
PROXY_PORT=8080
PROXY_USER=username
PROXY_PASS=password
version: '3.8'

services:
  scraper:
    image: my-scraper:latest
    environment:
      - HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - NO_PROXY=localhost,127.0.0.1

پروکسی در زمان ساخت در Compose

اگر در Compose بخشی build وجود دارد و نیاز به انتقال پروکسی در زمان ساخت دارید:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        HTTP_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
        HTTPS_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
    environment:
      - HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}

کدام نوع پروکسی برای Docker انتخاب کنیم

انتخاب نوع پروکسی بستگی به وظیفه دارد. برای محیط‌های Docker سه نوع اصلی وجود دارد که هر کدام جایگاه خاص خود را دارند:

نوع پروکسی سرعت ناشناس بودن بهترین سناریو برای Docker
دیتاسنتر ⚡ بالا متوسط بارگیری تصاویر، خطوط CI/CD، دور زدن محدودیت نرخ Docker Hub
مسکونی 🔄 متوسط بالا تجزیه سایت‌ها با حفاظت، API با محدودیت‌های جغرافیایی، آزمایش
موبایل 🔄 متوسط حداکثر برنامه‌هایی که با API‌های موبایل کار می‌کنند (Instagram، TikTok)

برای بارگیری تصاویر و CI/CD پروکسی‌های دیتاسنتر بهینه‌ترین گزینه هستند — آن‌ها حداکثر سرعت را در بارگیری تصاویر بزرگ (چند گیگابایت) و اتصال پایدار برای ساخت‌های طولانی ارائه می‌دهند.

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

برای برنامه‌هایی که با پلتفرم‌های موبایل کار می‌کنند — Instagram Graph API، TikTok API، نسخه‌های موبایل خدمات — باید پروکسی‌های موبایل را در نظر بگیرید. آن‌ها از IP‌های اپراتورهای تلفن همراه استفاده می‌کنند و حداقل شک و تردید را در سیستم‌های ضد ربات ایجاد می‌کنند.

پروتکل‌ها: HTTP در مقابل SOCKS5

دیمون Docker فقط از پروکسی‌های HTTP/HTTPS پشتیبانی می‌کند — SOCKS5 برای بارگیری تصاویر کار نمی‌کند. اگر پروکسی SOCKS5 دارید و نیاز به بارگیری تصاویر دارید، باید از یک تبدیل‌کننده محلی مانند privoxy یا microsocks استفاده کنید که HTTP را دریافت کرده و از طریق SOCKS5 پروکسی می‌کند.

برای کانتینرهای در حال اجرا، وضعیت بهتر است: بیشتر کتابخانه‌های HTTP به طور مستقیم از SOCKS5 از طریق متغیر ALL_PROXY=socks5://... پشتیبانی می‌کنند.

اشکالات رایج و نحوه رفع آن‌ها

بیایید به بررسی رایج‌ترین مشکلاتی بپردازیم که هنگام تنظیم پروکسی در Docker با آن‌ها مواجه می‌شوید:

خطا 1: پروکسی در هاست تنظیم شده، اما Docker آن را نمی‌بیند

علائم:

Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp: connection refused

علت: دیمون Docker به عنوان یک سرویس سیستمی اجرا می‌شود و متغیرهای محیطی کاربر فعلی را به ارث نمی‌برد، حتی اگر شما export HTTPS_PROXY=... را در ترمینال تنظیم کرده باشید.

راه‌حل: پروکسی را از طریق systemd override تنظیم کنید (روش 1 از بخش بالا). حتماً systemctl daemon-reload && systemctl restart docker را اجرا کنید.

خطا 2: apt-get / pip / npm در زمان ساخت کار نمی‌کنند

علائم:

Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
Could not connect to archive.ubuntu.com:80

علت: تنظیم پروکسی برای دیمون به طور خودکار به دستورات داخل RUN در Dockerfile منتقل نمی‌شود. این دو زمینه متفاوت هستند.

راه‌حل: پروکسی را از طریق --build-arg منتقل کنید یا از ~/.docker/config.json با بخش proxies (Docker 23.0+، به طور خودکار آرگومان‌ها را در زمان ساخت منتقل می‌کند) استفاده کنید.

خطا 3: خدمات داخلی از طریق پروکسی در دسترس نیستند

علائم:

curl: (7) Failed to connect to internal-service.local port 8080: Connection refused

علت: پروکسی سعی می‌کند درخواست‌ها را به آدرس‌های داخلی پروکسی کند که از خارج در دسترس نیستند.

راه‌حل: تمام دامنه‌ها و زیرشبکه‌های داخلی را به NO_PROXY اضافه کنید. برای شبکه‌های شرکتی، لیست معمول: localhost,127.0.0.1,::1,.internal,.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

خطا 4: احراز هویت پروکسی کار نمی‌کند — کاراکترهای خاص در رمز عبور

اگر رمز عبور شامل کاراکترهای خاص (@, #, %) باشد، URL به درستی تجزیه نمی‌شود.

راه‌حل: رمز عبور را در URL-encoding کدگذاری کنید. به عنوان مثال، p@ss#wordp%40ss%23word. در Python می‌توانید به سرعت نسخه کدگذاری شده را دریافت کنید:

python3 -c "from urllib.parse import quote; print(quote('p@ss#word', safe=''))"
# خروجی: p%40ss%23word

خطا 5: پروکسی کار می‌کند، اما گواهی SSL تأیید نمی‌شود

پروکسی‌های شرکتی اغلب بازرسی SSL (MITM) انجام می‌دهند و گواهی‌ها را تغییر می‌دهند. در این صورت Docker خطا می‌دهد:

x509: certificate signed by unknown authority

راه‌حل: گواهی ریشه شرکتی را به لیست گواهی‌های معتبر در هاست اضافه کرده و Docker را دوباره راه‌اندازی کنید. در Ubuntu/Debian:

sudo cp corporate-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
sudo systemctl restart docker

خطا 6: Kubernetes / Docker Swarm — پروکسی در همه نودها کار نمی‌کند

در محیط‌های خوشه‌ای، باید پروکسی را به طور جداگانه در هر نود تنظیم کنید. برای Kubernetes، علاوه بر این، باید متغیرهای محیطی را در مانیفست‌های پادها یا از طریق ConfigMap تنظیم کنید. می‌توانید این کار را از طریق Ansible یا سایر ابزارهای مدیریت پیکربندی خودکار کنید.

نتیجه‌گیری

تنظیم پروکسی در Docker یک تنظیم واحد نیست، بلکه سه سطح مستقل است: دیمون برای بارگیری تصاویر، build-time برای ساخت و runtime برای کانتینرهای در حال اجرا. با درک این معماری، می‌توانید به طور انعطاف‌پذیر مدیریت کنید که چه ترافیکی از طریق پروکسی عبور می‌کند و چه ترافیکی به طور مستقیم.

چک‌لیست کوتاه برای تنظیم صحیح:

  • ✅ برای بارگیری تصاویر — تنظیم systemd override با متغیرهای HTTP_PROXY و HTTPS_PROXY
  • ✅ برای ساخت — پروکسی را از طریق --build-arg یا ~/.docker/config.json منتقل کنید
  • ✅ برای runtime — از متغیرهای محیطی از طریق -e یا --env-file استفاده کنید
  • ✅ همیشه NO_PROXY را برای آدرس‌های داخلی تنظیم کنید
  • ✅ رمزهای عبور پروکسی را در Dockerfile ذخیره نکنید — از build-args و فایل‌های .env استفاده کنید
  • ✅ برای خطوط CI/CD پروکسی‌های سریع دیتاسنتر را انتخاب کنید
  • ✅ برای کانتینرهای تجزیه‌کننده — پروکسی‌های مسکونی یا موبایل

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

```