راه‌اندازی رجیستری خصوصی داکر با Nexus Repository Manager

وقتی یک تیم چند نفره روی چند پروژه کار می‌کنه، هر docker pull یعنی دانلود مجدد از اینترنت: هم کند، هم مصرف پهنای باند، هم گیر کردن روی محدودیت‌های شبکه و rate limit داکرهاب. از طرف دیگه ایمیج‌هایی که خودمون می‌سازیم باید جایی نگه‌داری بشن که تحت کنترل ما باشه.

خب حالا میخوایم از نکسوس به عنوان mirror رجیستری داکر استفاده کنیم. مثلا ریپوی پروکسی‌ای ساختیم به اسم arvan-miror که به میرور لیارا وصل میشه. آدرسی که UI بهمون میده اینه:

http://<server-ip>:8081/repository/arvan-mirror/

اما اگر این آدرس رو جایی به داکر بدیم کار نمی‌کنه! چرا؟ چون API رجیستری داکر نمی‌تونه روی یک مسیر زیرشاخه‌ای (path-based) سرو بشه؛ داکر همیشه منتظر API روی root یک host:port هست.
راه حل : باید نوع connector سرویس nexus رو از path based به other connectors و در نهایت یک پورت http (یا https) انتخاب کنیم

سه نوع ریپازیتوری در نکسوس

قبل از ادامه این سه نوع رو باید خوب بفهمیم:

Typeوظیفهمثال
proxyواسط بین ما و یک رجیستری remote؛ اولین درخواست رو از اینترنت میگیره و روی سرور کش می‌کنه؛ درخواست‌های بعدی از کش جواب داده میشنپروکسی Docker Hub
hostedریپوی خصوصی خودمون؛ ایمیج‌هایی که خودمون build کردیم رو اینجا push می‌کنیمایمیج‌های داخلی تیم
groupیک URL واحد که چند ریپوی دیگه (proxy و hosted) رو کنار هم قرار میده؛ به ترتیب چک می‌کنه و از اولین منبعی که آرتیفکت رو داشته جواب میدهیک پورت برای همه چیز

ترتیب اعضا در group مهمه

اعضای group به ترتیب اولویت چک میشن؛ همیشه hosted رو بالاتر از proxy بذارید تا ایمیج‌های داخلی خودتون اولویت داشته باشن. ضمنا group خودش چیزی ذخیره نمی‌کنه؛ فقط یک روتر هوشمنده.

 

ساخت ریپوی proxy (کش داکرهاب)

از settings → Repository → Repositories → Create repository نوع docker (proxy) رو انتخاب کنید.

Name: docker-proxy

فیلد Repository Connectors: ابتدا other connectors رو انتخاب کنید بعد تیک HTTP رو بزنید و پورت 8082 رو وارد کنید. این پورت آدرس رجیستری این ریپو می‌شه.

فیلد Allow anonymous docker pull: اگر می‌خواید کلاینت‌ها بدون docker login بتونن pull کنن، تیکش رو بزنید.

Remote storage: (به عنوان مثال مخزن اروان رو استفاده میکنیم)

https://docker.arvancloud.ir

فیلد Docker Index: گزینه‌ی Use proxy registry رو انتخاب کنید. این تنظیم مسئول جست‌وجوی ایمیج‌هاست و اگر برای پروکسی داکرهاب روی Custom بمونه، بعضی pull ها با خطاهای گمراه‌کننده می‌شکنن. برای پروکسی رجیستری‌های دیگه (مثل ghcr.io یا میرورهای داخلی) این گزینه رو روی Use proxy registry بذارید.

فیلد Authentication (اختیاری ولی توصیه‌شده): در بخش HTTP → Authentication نوع Username رو انتخاب و یک اکانت داکرهاب وارد کنید. سهمیه‌ی pull اکانت‌دار خیلی بیشتر از IP ناشناسه و برای تیم چند‌نفره تفاوت محسوسی داره.


ساخت ریپوی hosted (رجیستری خصوصی)

ریپوری خصوصی و لوکال تنظیمات نوع پروکسی رو نداره و تنها چیزی که میشه بهش توجه کرد Deployment policy هست که دو حالت داره allow redeploy اجازه میده که تگ های ایمیج ها قابلیت بازنویسی داشته باشن و در صورت disable این اجازه داده نمیشه
روش امن‌تر: دو ریپوی hosted جدا بسازید، یکی docker-snapshots با redeploy آزاد و یکی docker-releases با redeploy بسته.


ساخت ریپوی group (آدرس واحد)

Create repository → docker (group)

Name: docker-group
Repository Connectors: HTTP روی پورت 8084
Member repositories: به این ترتیب اضافه کنید:

  1. docker-hosted
  2. docker-proxy

از این به بعد کلاینت‌ها فقط با پورت 8084 (و بعد از Nginx، فقط با یک دامنه) کار می‌کنن و نمی‌دونن ایمیج از کش اومده یا از انبار داخلی.

سیستم push به group: ریپوی group به‌صورت پیش‌فرض فقط خواندنیه. در نسخه‌های جدید نکسوس فیلد Writable member برای group وجود داره که با ست کردنش می‌تونید push رو هم از همون آدرس انجام بدید. اگر این فیلد رو در نسخه‌ی خودتون دیدید، docker-hosted رو انتخاب کنید؛ در غیر این صورت مثل نمونه‌ی این مقاله، آدرس push رو جدا نگه دارید.

همچنین ترتیب مخزن ها در group مهمه و نکسوس هنگام pull گرفتن به ترتیب موجود بودن اون ایمیج رو چک میکنه پس بهتره که نمونه hosted در اولویت اول قرار بگیره تا همیشه در صورت امکان از مخزن لوکال ایمیج ها دانلود بشن

تنظیمات مخزن های داکر

برای هر مخزن داکر علاوه بر اسم و مقدار url که خود nexus بهمون برای دسترسی سریعتر و راحت تر به ادرس اختصاصی اون مخزن میده. مقداری تنظیمات برای مشخص کردن رفتار اون مخزن هم در اختیار میزاره. به عنوان مثال نوع connector رو در بخش قبلی عوض کردیم.

یا برای مخزن داکر از نوع proxy باید ادرس مخزن اصلی که قراره nexus از اون ایمیج هارو دریافت کنه رو وارد میکنیم
دو متغیر دیگری که مخزن های داکر دارن متغیر های maximum component age و maximum metadata age هست

  • maximum component age
    نشان دهنده مقدار زمانی هست که nexus برای دریافت یک ایمیج از cache خودش استفاده میکنه و برای دریافت اون ایمیج به مخزن proxy مراجعه نمیکنه که با مقدار -1 معنی بی نهایت رو میده
  • maximum metadata age
    معنی مشابهی داره اما برای metadata انجام میشه. به عنوان مثال اگر ایمیج با تگ latest در cache سرور ذخیره شده باشه بعد از تایم مشخص شده در این متغیر اون ایمیج دوباره بررسی میشه که ایا ورژن جدیدی منتشر شده یا نه

تست پراکسی

اول چک می‌کنیم connector درسته:

curl http://<server-ip>:8082/v2/

اگر جواب {} یا کد 200 بود یعنی درسته. حالا pull:

docker pull <server-ip>:8082/alpine

اما دو تا خطای رایج این مرحله:

خطای اول — HTTPS client به سرور HTTP:

http: server gave HTTP response to HTTPS client

داکر به صورت پیش‌فرض سعی می‌کنه با HTTPS وصل بشه، ولی کانکتور ما HTTP هست. باید به داکر بگیم این رجیستری رو به عنوان insecure قبول کنه. در لینوکس فایل /etc/docker/daemon.json:

{
  "insecure-registries": ["<server-ip>:8082"]
}
sudo systemctl restart docker

و در ویندوز (Docker Desktop) این تنظیم از داخل برنامه میشه: Settings → Docker Engine → همون JSON رو اضافه می‌کنیم → Apply & Restart.

خطای دوم no basic auth credentials:

pull access denied ... may require authorization: no basic auth credentials

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

راه اول (برای mirror عمومی راحت‌تره):
فعال کردن دسترسی anonymous. در Server administration → Security → Anonymous فعالش می‌کنیم و در تنظیمات خود ریپو هم anonymous access رو Allow می‌کنیم.

راه دوم: login با کاربر نکسوس:

docker login <server-ip>:8082

تست hosted و group

فرض کنیم hosted رو روی پورت 8083 و group (شامل hosted + proxy) رو روی پورت 8084 بردیم. هر سه پورت رو به insecure-registries اضافه می‌کنیم و برای push حتما login می‌کنیم:

docker login <server-ip>:8083
docker tag alpine <server-ip>:8083/my-alpine:test
docker push <server-ip>:8083/my-alpine:test

و تست group که باید هر دو رو سرو کنه:

docker pull <server-ip>:8084/my-alpine:test   # از hosted جواب میگیره
docker pull <server-ip>:8084/nginx            # از proxy میگیره و کش می‌کنه

یک برداشت اشتباه رایج درباره group

شاید فکر کنیم وقتی از group ایمیج عمومی می‌گیریم، چون ایمیج در hosted نیست، از proxy گرفته میشه و داخل hosted ذخیره میشه. اینطور نیست! ایمیج در کش خود ریپوی proxy ذخیره میشه و hosted دست‌نخورده می‌مونه. یعنی:

  • pull از group → کش میشه در proxy → pull های بعدی از همون کش
  • group هیچ‌وقت چیزی داخل hosted نمی‌ریزه

نکته خوب اینه که کش proxy به صورت پیش‌فرض دائمی هست؛ چیزی پاک نمیشه مگه اینکه خودمون Cleanup Policy تعریف کنیم. پس برای اکثر موارد اصلا نیازی به کپی کردن داخل hosted نیست.

مرحله اخر HTTPS کردن رجیستری (حذف insecure-registries)

تنظیم insecure-registries روی همه کلاینت‌ها اذیت‌کننده‌ست و راه درستش گذوندن رجیستری روی HTTPS با گواهی معتبره

مسیر اول (بدون نیاز به nginx) استفاده از TLS داخلی خود نکسوسه:

1. گرفتن گواهی با certbot (پورت 80 باید آزاد باشه):

sudo apt install -y certbot
sudo certbot certonly --standalone -d nexus.yourdomain.com
# خروجی: /etc/letsencrypt/live/nexus.yourdomain.com/

2. ایمپورت در نکسوس: در UI مسیر Security → TLS certificates → افزودن گواهی جدید؛ محتوای privkey.pem به عنوان کلید خصوصی و fullchain.pem به عنوان زنجیره گواهی.

3. تغییر Docker Connector ها به HTTPS: در تنظیمات هر ریپو، به جای HTTP گزینه HTTPS رو با پورت جدید (مثلا 8442 و 8443 و 8444) فعال می‌کنیم و گواهی ایمپورت شده رو انتخاب می‌کنیم.

4. باز کردن پورت‌ها در فایروال و بعد از اطمینان، حذف insecure-registries از همه کلاینت‌ها و restart داکر. از این به بعد همه چیز بدون هیچ تنظیم اضافه‌ای کار می‌کنه:

docker pull nexus.yourdomain.com:8444/alpine
docker login nexus.yourdomain.com:8443

تمدید گواهی فراموش نشه

گواهی‌های Let's Encrypt هر ۹۰ روز منقضی میشن. بعد از هر بار certbot renew باید گواهی جدید در نکسوس هم آپدیت بشه (دستی از UI یا با اسکریپت REST API) — وگرنه یک روز داکر کلاینت‌ها خطای گواهی می‌گیرن.

راه جایگزین: گذاشتن nginx به عنوان reverse proxy با TLS termination جلوی نکسوس؛ مزیتش اینه که certbot --nginx تمدید رو خودکار می‌کنه و UI خود نکسوس هم HTTPS میشه. برای راه اندازی nginx می‌تونید مقاله‌ی ریورس پروکسی nginx رو ببینید.
برای انجام دادن این روش دو مقاله راه اندازی ریورس پروکسی در nginx و نحوه فعال کردن https در nginx رو میتونید مطالعه کنید

نکات تکمیلی برای محیط عملیاتی

  • تغییر پسورد admin بعد از اولین login و فعال کردن anonymous فقط در حد لازم — اگر رجیستری روی اینترنت عمومیه، anonymous رو محدود به خواندن از ریپوهای proxy/group کنید.
  • مدیریت رم: تنظیمات heap در فایل bin/nexus.vmoptions (یا nexus.vmoptions در data dir) قابل تغییره؛ روی سرورهای کم‌رم می‌شه -Xms و -Xmx رو دستی کم کرد.
  • Cleanup Policy: برای اینکه کش proxy و ریپوهای hosted بی‌نهایت بزرگ نشن، از Administration → Repository → Cleanup policies می‌توانیم قانون حذف بر اساس آخرین دسترسی یا تاریخ دانلود تعریف و به ریپوها متصل کنیم.
  • Blob Store: داده هر ریپو در یک blob store ذخیره میشه؛ میشه برای هر ریپو blob store جدا (حتی روی دیسک جدا) تعریف کرد.
  • بکاپ: ساده‌ترین راه بکاپ گیری از کل دایرکتوری /opt/sonatype-work در زمانی که سرویس down یا حداقل بیکاره.
  • ثبت در UI چه اتفاقی افتاد: برای دیدن اینکه واقعا ایمیج‌ها از کش سرو شدن یا نه، بخش Browse هر ریپو لیست کامپوننت‌های کش شده رو نشون میده.

مدیریت کاربر ها و تنظیم سطح دسترسی

برای ایجاد کاربر های بیشتر و مدیریت سطح دسترسی هر کاربر به عملیاتی که روی هر repository بتونه انجام بده باید به بخش settings -> security -> user بریم و گزینه ایجاد کاربر رو بزنیم
قبل از اون باید role همراه با دسترسی های مورد نظر رو ایجاد کنیم تا بشه این role رو به هر user که مدنظرمونه وصل کنیم

انواع role ها

برای ساخت role هم به مسیر settings -> security -> roles
توی nexus دو دسته کلی از Privilege ها داریم(جزییات دسترسی که به یک role تخصیص داده میشن)
nx-repository-view و `nx-repository-admin
که نقش view برای مدیریت محتوای درون repository هاست و admin برای مدیریت خود repository ها

 

دسترسی ها برای view

ActionWhat it allows
browseSee the repo in the UI and list/navigate components (tree, search, metadata) — but not open/download files
readDownload the actual artifact (HTTP GET, pull packages)
addUpload/deploy new components
editOverwrite/modify existing components (redeploy)
deleteRemove components

دسترسی ها برای admin

ActionWhat it allows
browseSee the repo listed under Administration/server config
readView its settings page (URL, storage, connectors)
editChange its configuration (change settings, blob store, policies)
addCreate new repositories
deleteDelete the whole repository

به عنوان مثال برای درست کردن یک role برای دسترسی فقط به push و pull از سرور hosted میتونیم فقط دسترسی های read و edit و add و browse از گروه view رو برای اون مخزن خاص رو باز کنیم

نگه‌داری

Cleanup Policy

کش ریپوی proxy سقف رشد نداره و بزرگ‌ترین علت پر شدن دیسک سرور نکسوسه. حتماً سیاست پاک‌سازی تعریف کنید.

settings → Repository → Cleanup Policies → Create Cleanup Policy

فیلدمقدار پیشنهادی برای proxy
Namedocker-proxy-cleanup
Formatdocker
Component usage — last downloaded before30 روز

این یعنی هر ایمیجی که ۳۰ روز pull نشده حذف می‌شه. برای کش پروکسی کاملاً بی‌خطره چون در صورت نیاز دوباره از داکرهاب گرفته می‌شه.

برای docker-hosted محافظه‌کارتر باشید و به‌جای معیار دانلود، از Component age با بازه‌ی بلندتر (مثلاً ۹۰ روز) استفاده کنید، و ریپوی release رو معمولاً بهتره کلاً از سیاست پاک‌سازی خارج نگه دارید.

سیاست رو در تب Cleanup تنظیمات هر ریپو انتخاب کنید. بعد سه تسک زمان‌بندی‌شده در Administration → System → Tasks بسازید:

تسککارکرد
Admin - Cleanup repositories using their associated policiesاجرای سیاست‌های پاک‌سازی
Admin - Cleanup tags یا حذف مانیفست‌های بلااستفاده‌ی داکرپاک کردن مانیفست‌ها و لایه‌های بی‌ارجاع
Admin - Compact blob storeآزاد کردن واقعی فضای دیسک

نکته‌ی مهم: تا وقتی Compact blob store اجرا نشه، فضای دیسک آزاد نمی‌شه. حذف در نکسوس اول soft delete هست. تسک‌ها رو در ساعت کم‌ترافیک شبانه زمان‌بندی کنید.

جمع بندی

مسیر کلی چیزی که ساختیم:

docker hub  ←→  proxy (8082)  ←┐
                               ├──  group (8084)  ←→  کلاینت‌ها (pull)
private imgs  →  hosted (8083) ←┘        ↑
                                    (push ایمیج‌های خودمون)

الان یک رجیستری داکر عملیاتی دارید: docker.example.com برای pull (که پشت صحنه هم کش داکرهابه هم انبار خصوصی)، docker-push.example.com برای انتشار ایمیج‌های خودتون، هر دو روی HTTPS معتبر، با دسترسی‌های تفکیک‌شده و سیاست پاک‌سازی خودکار.