چگونه یک رجیستری خصوصی داکر را در اوبونتو اجرا و راه اندازی کنیم

چگونه یک رجیستری خصوصی داکر را در اوبونتو اجرا و راه اندازی کنیم

مقدمه

Docker Registry یک برنامه است که مدیریت ذخیره‌سازی و تحویل ایمیج‌های کانتینر داکر را بر عهده دارد. رجیستری‌ها ایمج های کانتینر را متمرکز کرده و زمان ساخت را برای توسعه‌دهندگان کاهش می‌دهند. ایمیج‌های داکر محیط اجرایی یکسانی را از طریق مجازی‌سازی تضمین می‌کنند، اما ساخت یک ایمیج ممکن است نیازمند صرف زمان زیادی باشد. به عنوان مثال، به جای نصب جداگانه وابستگی‌ها و پکیج‌ها برای استفاده از داکر، توسعه‌دهندگان می‌توانند یک ایمیج فشرده از رجیستری دانلود کنند که شامل تمام اجزای موردنیاز است. علاوه بر این، توسعه‌دهندگان می‌توانند با استفاده از ابزارهای یکپارچه‌سازی مستمر مانند TravisCI، ارسال خودکار ایمیج‌ها به رجیستری را انجام دهند تا ایمیج‌ها را در زمان تولید و توسعه بدون دردسر به‌روزرسانی کنند.

Docker Hub یک رجیستری عمومی رایگان است که می‌تواند میزبان ایمیج‌های سفارشی داکر شما باشد، اما در برخی موارد ممکن است نخواهید ایمیج شما به صورت عمومی در دسترس باشد. ایمیج‌ها معمولاً شامل تمام کدی هستند که برای اجرای یک برنامه مورد نیاز است، بنابراین استفاده از یک رجیستری خصوصی هنگام استفاده از نرم‌افزار اختصاصی می‌تواند ترجیح داده شود.

در این آموزش، شما رجیستری خصوصی داکر خودتان را راه‌اندازی و ایمن‌سازی خواهید کرد. شما از Docker Compose برای تعریف تنظیماتی که کانتینرهای داکر شما را اجرا می‌کنند استفاده خواهید کرد، و از Nginx برای هدایت ترافیک سرور از اینترنت به کانتینر در حال اجرای داکر بهره خواهید برد. پس از اتمام این آموزش، قادر خواهید بود یک ایمیج سفارشی داکر را به رجیستری خصوصی خود ارسال کرده و آن را به صورت ایمن از یک سرور راه دور دریافت (pull) کنید.

پیش‌نیازها

برای تکمیل این آموزش، به موارد زیر نیاز خواهید داشت:

  • دو سرور Ubuntu 22.04 که با دنبال کردن راهنمای «تنظیمات اولیه سرور اوبونتو 22.04» پیکربندی شده باشند، شامل:
    • یک کاربر غیرریشه با دسترسی sudo
    • یک فایروال فعال , یکی از این سرورها میزبان Docker Registry خصوصی شما خواهد بود و دیگری به عنوان کلاینت استفاده می‌شود.
  • نصب Docker روی هر دو سرور، که می‌توانید با دنبال کردن مراحل ۱ و ۲ از راهنمای «نصب و استفاده از Docker در Ubuntu 22.04» انجام دهید.

 

در سرور میزبان، به موارد زیر نیاز خواهید داشت:

  • نصب Docker Compose روی سرور میزبان، که می‌توانید با دنبال کردن مرحله ۱ از راهنمای «نصب و استفاده از Docker Compose در Ubuntu 22.04» انجام دهید.
  • نصب Nginx روی سرور میزبان، که می‌توانید با دنبال کردن مراحل راهنمای «نصب Nginx در Ubuntu 22.04» انجام دهید.
  • ایمن‌سازی Nginx با Let’s Encrypt روی سرور میزبان برای رجیستری خصوصی Docker، که می‌توانید با دنبال کردن راهنمای «ایمن‌سازی Nginx با Let’s Encrypt در Ubuntu 22.04» انجام دهید.
    حتماً در مرحله ۴، تمام ترافیک را از HTTP به HTTPS هدایت (redirect) کنید.
  • یک نام دامنه ثبت‌شده که به سروری که رجیستری خصوصی Docker روی آن میزبانی می‌شود اشاره می‌کند. شما این را به عنوان بخشی از پیش‌نیاز Let’s Encrypt تنظیم خواهید کرد. در این آموزش، به آن با نام your_domain اشاره خواهیم کرد.

مرحله 1 — نصب و پیکربندی Docker Registry


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

با Docker Compose، شما یک فایل .yml می‌نویسید تا تنظیمات هر کانتینر و اطلاعات موردنیاز برای ارتباط بین کانتینرها را تعیین کنید. می‌توانید با ابزار docker compose دستورات را به تمام اجزای برنامه بدهید و آن‌ها را به صورت یک گروه کنترل کنید.

Docker Registry خود یک برنامه با اجزای متعدد است، بنابراین برای مدیریت آن از Docker Compose استفاده خواهید کرد. برای شروع یک نمونه از رجیستری، یک فایل docker-compose.yml تنظیم خواهید کرد تا آن را تعریف کند و مکان ذخیره‌سازی داده‌ها در دیسک را مشخص نماید.

شما پیکربندی را در دایرکتوری‌ای به نام docker-registry روی سرور میزبان ذخیره خواهید کرد. با اجرای دستور زیر آن را ایجاد کنید:

mkdir ~/docker-registry

سپس وارد آن شوید:

cd ~/docker-registry

سپس یک زیرپوشه به نام data بسازید، جایی که رجیستری شما ایمیج‌ها را ذخیره خواهد کرد:

mkdir data

یک فایل به نام docker-compose.yml ایجاد و باز کنید:

nano docker-compose.yml

خطوط زیر را اضافه کنید که یک نمونه پایه از Docker Registry را تعریف می‌کنند:

~/docker-registry/docker-compose.yml

version: '3'

services:
  registry:
    image: registry:latest
    ports:
    - "5000:5000"
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./data:/data

ابتدا، اولین سرویس را با نام registry نام‌گذاری می‌کنید و ایمیج‌ آن را registry با آخرین نسخه تنظیم می‌کنید. سپس در قسمت ports، پورت ۵۰۰۰ روی میزبان را به پورت ۵۰۰۰ در کانتینر نگاشت می‌کنید، که این امکان را می‌دهد که درخواست به پورت ۵۰۰۰ روی سرور ارسال شده و به رجیستری منتقل شود.

در بخش environment، متغیر REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY را روی /data تنظیم می‌کنید تا مشخص شود داده‌ها در کدام حجم ذخیره شوند. سپس، در بخش volumes، دایرکتوری /data روی سیستم فایل میزبان را به /data در کانتینر نگاشت می‌کنید که به صورت passthrough عمل می‌کند. در واقع داده‌ها روی سیستم فایل میزبان ذخیره خواهند شد.

فایل را ذخیره کرده و ببندید.

اکنون می‌توانید پیکربندی را با اجرای دستور زیر آغاز کنید:

docker compose up

کانتینر رجیستری و وابستگی‌های آن دانلود و راه‌اندازی خواهند شد.

خروجی:

[+] Running 2/2
 ⠿ Network docker-registry_default       Created  0.1s
 ⠿ Container docker-registry-registry-1  Created  0.1s
Attaching to docker-registry-registry-1
docker-registry-registry-1  | time="2022-11-19T14:31:20.40444638Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
docker-registry-registry-1  | time="2022-11-19T14:31:20.404960549Z" level=info msg="redis not configured" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
docker-registry-registry-1  | time="2022-11-19T14:31:20.412312462Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
docker-registry-registry-1  | time="2022-11-19T14:31:20.412803878Z" level=info msg="Starting upload purge in 52m0s" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
docker-registry-registry-1  | time="2022-11-19T14:31:20.41296431Z" level=info msg="listening on [::]:5000" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
...

شما در ادامه‌ی این آموزش به پیام هشدار No HTTP secret provided رسیدگی خواهید کرد.

آخرین خط خروجی نشان می‌دهد که رجیستری با موفقیت راه‌اندازی شده و در حال گوش دادن روی پورت ۵۰۰۰ است.

برای متوقف کردن اجرای آن، می‌توانید کلیدهای CTRL+C را فشار دهید.

در این مرحله، یک پیکربندی Docker Compose ایجاد کردید که یک Docker Registry را روی پورت ۵۰۰۰ راه‌اندازی می‌کند. در مراحل بعدی، آن را روی دامنه خود منتشر کرده و احراز هویت را تنظیم خواهید کرد.

مرحله ۲ — راه‌اندازی Port Forwarding در Nginx

به عنوان بخشی از پیش‌نیازها، شما HTTPS را روی دامنه‌تان فعال کرده‌اید. برای اینکه Docker Registry ایمن خود را از طریق این دامنه در دسترس قرار دهید، باید Nginx را طوری پیکربندی کنید که ترافیک را از دامنه به کانتینر رجیستری هدایت کند.

قبلاً فایل پیکربندی سرور خود را در مسیر /etc/nginx/sites-available/your_domain تنظیم کرده‌اید. برای ویرایش آن، دستور زیر را اجرا کنید:

sudo nano /etc/nginx/sites-available/your_domain

در فایل بازشده، بلوک location موجود را پیدا کنید:

...
    location / {
    ...
    }
...

شما باید ترافیک را به پورت ۵۰۰۰ هدایت کنید، جایی که رجیستری منتظر ترافیک خواهد بود. همچنین لازم است هدرهایی را به درخواست ارسالی اضافه کنید که اطلاعات بیشتری درباره‌ی درخواست فراهم کند. محتوای موجود در بلوک location را با خطوط زیر جایگزین کنید:

location / {
    # عدم پذیرش اتصال از Docker نسخه‌های ۱.۵ و پایین‌تر
    # docker قبل از نسخه ۱.۶.۰ user agent را به درستی تنظیم نمی‌کرد، بررسی "Go *" برای جلوگیری از دسترسی برنامه‌های نوشته‌شده با Go
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
      return 404;
    }

    proxy_pass                          http://localhost:5000;
    proxy_set_header  Host              $http_host;   # برای سازگاری با docker client
    proxy_set_header  X-Real-IP         $remote_addr; # ارسال IP واقعی کلاینت
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
}

بلوک if user agent درخواست را بررسی می‌کند تا مطمئن شود که نسخه‌ی کلاینت Docker بالاتر از ۱.۵ است و درخواست از یک اپلیکیشن نوشته‌شده با Go نیست.

فایل را ذخیره کرده و ببندید، سپس Nginx را ریستارت کنید تا تغییرات اعمال شود:

sudo systemctl restart nginx

اگر پیغام خطا دریافت کردید، پیکربندی واردشده را دوباره بررسی کنید.

اکنون برای بررسی اینکه آیا Nginx به درستی ترافیک را به کانتینر رجیستری هدایت می‌کند، کانتینر را اجرا کنید:

docker compose up

سپس در مرورگر به آدرس زیر بروید:

https://your_domain/v2

مرورگر یک شیء JSON خالی نمایش می‌دهد:

{}

در ترمینال خروجی مشابه زیر را دریافت خواهید کرد:

GET /v2 HTTP/1.0 → 301
GET /v2/ HTTP/1.0 → 200

این نشان می‌دهد که درخواست به /v2/ ارسال شده و رجیستری پاسخ موفق داده است (200 OK).

با فشردن CTRL+C اجرای کانتینر را متوقف کنید.

مرحله ۳ — راه‌اندازی احراز هویت (Authentication)

Nginx به شما اجازه می‌دهد احراز هویت HTTP را برای سایت‌هایی که مدیریت می‌کند، تنظیم کنید. برای محدود کردن دسترسی به Docker Registry، از این قابلیت استفاده می‌کنیم.

برای این کار ابتدا ابزار htpasswd را نصب کنید:

sudo apt install apache2-utils -y

فایلی برای ذخیره‌ی اطلاعات احراز هویت ایجاد کنید:

mkdir ~/docker-registry/auth
cd ~/docker-registry/auth

اکنون اولین کاربر را ایجاد کنید (به‌جای username، نام کاربری دلخواه را وارد کنید):

htpasswd -Bc registry.password username

هنگام درخواست، رمز عبور را وارد کنید. ترکیب نام کاربری و رمز در فایل registry.password ذخیره می‌شود.

اگر خواستید کاربران بیشتری اضافه کنید، این دستور را بدون گزینه -c اجرا کنید:

htpasswd -B registry.password newuser

اکنون فایل docker-compose.yml را ویرایش کنید تا مشخص کنید رجیستری از این فایل برای احراز هویت استفاده کند:

nano ~/docker-registry/docker-compose.yml

خطوط زیر را به بخش environment و volumes اضافه کنید:

version: '3'

services:
  registry:
    image: registry:latest
    ports:
    - "5000:5000"
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./auth:/auth
      - ./data:/data

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

فایل را ذخیره کرده و ببندید.

برای آزمایش، به دایرکتوری اصلی پروژه بروید و رجیستری را اجرا کنید:

cd ~/docker-registry
docker compose up

اکنون در مرورگر، دوباره به دامنه‌ی خود مراجعه کنید. این بار از شما نام کاربری و رمز خواسته می‌شود. پس از وارد کردن اطلاعات معتبر، صفحه‌ی {} نمایش داده خواهد شد.

با CTRL+C اجرای کانتینر را متوقف کنید.

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

مرحله ۴ — اجرای Docker Registry به عنوان سرویس

برای اینکه رجیستری شما بعد از ریبوت سیستم یا کرش دوباره اجرا شود، می‌توانید به Docker Compose دستور دهید که همیشه آن را روشن نگه دارد.

فایل docker-compose.yml را باز کنید:

nano docker-compose.yml

خط زیر را به بلاک registry: اضافه کنید:

...
  registry:
    restart: always
...

تنظیم گزینه restart: always باعث می‌شود کانتینر حتی بعد از ریبوت شدن سیستم یا در صورت کرش، به طور خودکار دوباره اجرا شود.

فایل را ذخیره و ببندید.

اکنون رجیستری را در پس‌زمینه اجرا کنید:

docker compose up -d

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

مرحله ۵ — افزایش حداکثر حجم آپلود در Nginx

از آنجا که ایمیج‌های Docker ممکن است حجم بالایی داشته باشند، باید محدودیت پیش‌فرض آپلود فایل در Nginx را افزایش دهید. مقدار پیش‌فرض ۱ مگابایت است که برای ایمیج‌های Docker کافی نیست.

فایل اصلی پیکربندی Nginx را باز کنید:

sudo nano /etc/nginx/nginx.conf

در بخش http { خط زیر را اضافه کنید:

http {
    client_max_body_size 16384m;
    ...
}

این خط اندازه مجاز فایل‌های ارسالی را به ۱۶ گیگابایت افزایش می‌دهد.

فایل را ذخیره کرده و ببندید، سپس Nginx را ریستارت کنید:

sudo systemctl restart nginx

اکنون می‌توانید ایمیج‌های حجیم را بدون خطا به رجیستری خود ارسال کنید.

مرحله ۶ — ارسال (Push) به رجیستری Docker خصوصی

اکنون که رجیستری شما فعال است و می‌تواند فایل‌های حجیم را قبول کند، می‌توانید یک ایمیج‌ را به آن Push کنید. برای آزمایش، از ایمیج‌ ubuntu موجود در Docker Hub استفاده می‌کنیم.

در یک ترمینال جدید، دستور زیر را اجرا کنید:

docker run -t -i ubuntu /bin/bash

فلگ‌های -t و -i دسترسی تعاملی (interactive shell) به داخل کانتینر را فراهم می‌کنند.

داخل کانتینر، یک فایل به نام SUCCESS ایجاد کنید:

touch /SUCCESS

این کار باعث می‌شود که کانتینر شخصی‌سازی‌شده باشد.

برای خروج از کانتینر:

exit

اکنون از این کانتینر شخصی‌سازی‌شده یک ایمیج جدید بسازید:

docker commit $(docker ps -lq) test-image

سپس وارد رجیستری خصوصی خود شوید:

docker login https://your_domain

نام کاربری و رمزی را که در مرحله ۳ ساختید وارد کنید.

خروجی به شکل زیر خواهد بود:

Login Succeeded

اکنون ایمیج‌ را تگ کنید تا قابل ارسال به رجیستری باشد:

docker tag test-image your_domain/test-image

و در نهایت ایمیج‌ را Push کنید:

docker push your_domain/test-image

خروجی مشابه زیر خواهد بود:

Using default tag: latest
The push refers to a repository [your_domain/test-image]
1cf9c9034825: Pushed
f4a670ac65b6: Pushed
latest: digest: sha256:...

شما اکنون تأیید کرده‌اید که:

  • احراز هویت به درستی انجام شده است.
  • کاربران معتبر می‌توانند ایمیج‌ه را به رجیستری ارسال کنند.

در ادامه می‌توانید بررسی کنید که آیا می‌توان این ایمیج‌ را از رجیستری نیز Pull کرد یا نه.

مرحله ۷ — Pull کردن از رجیستری خصوصی Docker

حالا که ایمیج‌ خود را به رجیستری خصوصی Push کرده‌اید، می‌خواهید از آن Pull (دریافت) کنید.

ابتدا در سرور اصلی وارد رجیستری شوید:

docker login https://your_domain

نام کاربری و رمز عبوری که در مرحله قبل ساختید را وارد کنید.

سپس ایمیج‌ تستی را Pull کنید:

docker pull your_domain/test-image

Docker ایمیج‌ را دریافت خواهد کرد. حالا برای اجرای کانتینر، دستور زیر را بزنید:

docker run -it your_domain/test-image /bin/bash

این دستور پوسته (shell) کانتینر را بارگذاری می‌کند.

برای دیدن فایل‌های موجود:

ls

در لیست فایل‌ها باید فایل SUCCESS که قبلاً ایجاد کرده بودید، مشاهده شود:

SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

وجود فایل SUCCESS تأیید می‌کند که این دقیقاً همان ایمیجی است که خودتان ساخته و Push کرده‌اید.

برای خروج از کانتینر:

exit

نتیجه‌گیری

در این آموزش، یک رجیستری خصوصی Docker راه‌اندازی کردید، احراز هویت را پیکربندی نمودید، محدودیت آپلود را افزایش دادید و یک ایمیج سفارشی را Push و Pull کردید.

اکنون می‌توانید از این رجیستری برای ذخیره ایمیج‌های اختصاصی پروژه‌هایتان استفاده کنید. همچنین می‌توانید با استفاده از ابزارهای CI مانند TravisCI، ارسال خودکار ایمیج ها را به رجیستری تنظیم کنید.

استفاده از کانتینرهای Docker در روند توسعه، تضمین می‌کند که برنامه شما در هر محیطی (توسعه، تست یا تولید) رفتار یکسانی داشته باشد.

برای یادگیری بیشتر در مورد ساخت Dockerfile های بهینه، به مستندات رسمی Best Practices for Writing Dockerfiles مراجعه کنید.

 

منبع DigitalOcean

۴
۱۴۰۴/۴/۱۵