Container Registry چیست؟ راهنمای جامع Docker Registry، Harbor و GitLab Registry

Container Registry چیست؟ راهنمای جامع Docker Registry، Harbor و GitLab Registry

اگر با Docker، Kubernetes یا CI/CD کار کرده باشید، احتمالاً با مفهومی به نام Container Registry مواجه شده‌اید. Docker Imageهایی که برای اجرای Applicationها ساخته می‌شوند، باید جایی ذخیره شوند تا بتوان آن‌ها را در محیط‌های مختلف دریافت و اجرا کرد.

Container Registry دقیقاً همین نقش را بر عهده دارد؛ یعنی یک سیستم برای ذخیره، مدیریت، انتشار و دریافت Container Imageها.

Registry می‌تواند عمومی باشد و Imageها را برای همه کاربران منتشر کند یا به صورت Private در داخل سازمان راه‌اندازی شود تا فقط کاربران و سرویس‌های مجاز بتوانند به Imageها دسترسی داشته باشند.

در معماری‌های مدرن DevOps و Cloud Native، Container Registry معمولاً یکی از اجزای اصلی زنجیره Software Delivery است و مستقیماً با ابزارهایی مانند Docker، Kubernetes، GitLab CI/CD، Jenkins، ArgoCD و OpenShift در ارتباط است.

Container Registry چیست؟

Container Registry یک Repository یا مخزن برای ذخیره و توزیع Container Imageها است.

وقتی یک Application را با Docker Containerize می‌کنیم، معمولاً یک Image تولید می‌شود. این Image باید در جایی ذخیره شود تا بتوان آن را روی Server، Kubernetes Cluster یا سایر محیط‌های اجرای Container دریافت کرد.


Developer
    │
    ▼
Source Code
    │
    ▼
Dockerfile
    │
    ▼
Docker Build
    │
    ▼
Container Image
    │
    ▼
Container Registry
    │
    ├───────────────┐
    ▼               ▼
Docker Host     Kubernetes

برای مثال فرض کنید یک Application با نام my-app ساخته‌ایم. پس از Build شدن Image می‌توان آن را در یک Registry ذخیره کرد:


my-app:1.0.0

سپس Server یا Kubernetes می‌تواند همین Image را از Registry دریافت کند و Container را اجرا کند.

چرا به Container Registry نیاز داریم؟

در یک پروژه کوچک ممکن است بتوانیم Docker Image را مستقیماً روی Server Build کنیم؛ اما این روش در محیط‌های Production و تیم‌های چندنفره معمولاً مناسب نیست.

Container Registry چند مشکل مهم را حل می‌کند:

  • ذخیره مرکزی Docker Imageها
  • توزیع Image بین Serverهای مختلف
  • مدیریت Versionهای مختلف Image
  • استفاده در CI/CD
  • کنترل دسترسی به Imageها
  • نگهداری Imageهای Private
  • اسکن Imageها از نظر Vulnerability
  • مدیریت Repositoryها و پروژه‌ها
  • حذف و پاک‌سازی Imageهای قدیمی
  • ایجاد یک منبع قابل اعتماد برای Kubernetes و سایر Runtimeها

در واقع Registry را می‌توان بخشی از Software Supply Chain دانست.

Container Image چیست؟

قبل از اینکه Registry را بهتر درک کنیم، باید بدانیم دقیقاً چه چیزی داخل آن ذخیره می‌شود.

Container Image یک Package قابل حمل است که شامل اجزای موردنیاز برای اجرای یک Application در یک Container می‌شود.

برای مثال یک Image مربوط به یک Application مبتنی بر PHP ممکن است شامل موارد زیر باشد:

  • Base Operating System Layer
  • PHP Runtime
  • Required Extensions
  • Application Dependencies
  • Application Source Code
  • Configuration Files

Docker Image معمولاً به صورت چند Layer ساخته می‌شود.


Docker Image
│
├── Layer 1
│   └── Base OS
│
├── Layer 2
│   └── PHP / Node.js / Python
│
├── Layer 3
│   └── Dependencies
│
└── Layer 4
    └── Application

یکی از مزایای این معماری، امکان استفاده مجدد از Layerها و کاهش حجم و زمان انتقال Imageها است.

Docker Registry چگونه کار می‌کند؟

در ساده‌ترین حالت، یک Docker Registry یک سرویس HTTP/HTTPS است که Clientها می‌توانند Imageها را در آن Push یا از آن Pull کنند.


                 Docker Client
                      │
             ┌────────┴────────┐
             │                 │
           docker push     docker pull
             │                 │
             ▼                 ▼
        ┌──────────────────────────┐
        │     Container Registry   │
        │                          │
        │  Images / Layers / Tags  │
        └──────────────────────────┘

برای مثال وقتی دستور زیر را اجرا می‌کنیم:

docker push registry.example.com/my-app:1.0.0

Docker Client Image را به Registry ارسال می‌کند.

در طرف مقابل، وقتی روی یک Server دستور زیر اجرا شود:

docker pull registry.example.com/my-app:1.0.0

Docker Image از Registry دریافت می‌شود.

Docker Hub چیست؟

Docker Hub یکی از شناخته‌شده‌ترین Container Registryها است و به عنوان Registry عمومی و خصوصی برای Docker Imageها استفاده می‌شود.

بسیاری از Imageهای رسمی و محبوب مانند Nginx، Redis، PostgreSQL و بسیاری از ابزارهای دیگر از طریق Docker Hub در دسترس هستند.

برای مثال می‌توان یک Image را با دستور زیر دریافت کرد:

docker pull nginx

در این حالت Docker به صورت پیش‌فرض به Registry پیش‌فرض خود یعنی Docker Hub مراجعه می‌کند.

اما در محیط‌های Enterprise معمولاً سازمان‌ها ترجیح می‌دهند Imageهای اختصاصی خود را در یک Registry داخلی یا Private نگهداری کنند.

Public Registry و Private Registry

Container Registryها را می‌توان از نظر سطح دسترسی به دو گروه کلی تقسیم کرد:

  • Public Registry
  • Private Registry

Public Container Registry

در Public Registry، Imageها می‌توانند برای عموم کاربران قابل دسترسی باشند.

این مدل برای Open Source Projectها و انتشار عمومی Software بسیار مناسب است.

Private Container Registry

در Private Registry، دسترسی به Imageها محدود به کاربران یا سرویس‌های مجاز است.

برای مثال یک سازمان ممکن است Image مربوط به Application داخلی خود را در Registry زیر قرار دهد:


registry.company.local
        │
        ├── backend
        ├── frontend
        ├── api
        └── worker

در این حالت Applicationهای داخلی، CI/CD Pipelineها و Kubernetes Cluster می‌توانند به Registry متصل شوند، بدون اینکه Imageها روی Internet عمومی منتشر شوند.

Registry و CI/CD چه ارتباطی دارند؟

یکی از مهم‌ترین کاربردهای Container Registry در Pipelineهای CI/CD است.

فرض کنید Developer کدی را در Git Repository Push می‌کند.


Developer
    │
    ▼
Git Push
    │
    ▼
CI/CD Pipeline
    │
    ▼
Docker Build
    │
    ▼
Security Scan
    │
    ▼
Docker Push
    │
    ▼
Container Registry
    │
    ▼
Deployment

در این معماری، Registry نقطه اتصال بین مرحله Build و مرحله Deployment است.

برای مثال GitLab CI می‌تواند Image را Build کند و آن را در Registry قرار دهد. سپس Kubernetes می‌تواند همان Image را Pull کرده و Application جدید را Deploy کند.

Docker Push و Docker Pull چیست؟

دو عملیات بسیار مهم در ارتباط با Registry عبارت‌اند از Push و Pull.

Docker Push

Push یعنی ارسال Image از Docker Client به Registry.

docker push registry.example.com/my-app:1.0.0

Docker Pull

Pull یعنی دریافت Image از Registry به سمت Docker Host یا Container Runtime.

docker pull registry.example.com/my-app:1.0.0

در یک Pipeline معمولاً Push توسط CI/CD انجام می‌شود و Pull توسط محیط Deployment.

ساختار نام Docker Image

یکی از مفاهیم مهم هنگام کار با Registry، ساختار نام Image است.


registry.example.com/team/my-app:1.2.0
│                    │       │
│                    │       └── Tag
│                    │
│                    └── Repository
│
└── Registry

یک Image Reference می‌تواند شامل بخش‌های مختلفی باشد:

  • Registry Host
  • Namespace یا Organization
  • Repository
  • Tag

برای مثال:


registry.ultimateco.cloud/backend/api:2.4.1

در این مثال:

  • registry.ultimateco.cloud نام Registry است.
  • backend Namespace یا Project است.
  • api نام Repository است.
  • 2.4.1 Tag مربوط به Image است.

Docker Image Tag چیست؟

Tag برای مشخص کردن Version یا Variant یک Image استفاده می‌شود.

برای مثال:


my-app:1.0.0
my-app:1.1.0
my-app:2.0.0

هر Tag می‌تواند به یک Image مشخص اشاره کند.

در محیط Production بهتر است از Tagهای مشخص و قابل ردیابی استفاده شود.

برای مثال:


my-app:2026.08.08
my-app:1.4.2
my-app:git-a81f3c2

استفاده از Tagهایی مانند latest در Deploymentهای حساس می‌تواند باعث ابهام شود؛ زیرا محتوای Image پشت این Tag ممکن است در طول زمان تغییر کند.

Image Digest چیست؟

علاوه بر Tag، Docker Image دارای یک Digest نیز است که یک شناسه مبتنی بر Hash برای محتوای Image است.


my-app@sha256:
a8f3c7d91e...

برخلاف Tag که می‌تواند به Image دیگری تغییر کند، Digest به محتوای مشخصی از Image اشاره می‌کند.

به همین دلیل در محیط‌های حساس و مخصوصاً برای Software Supply Chain Security، استفاده از Digest می‌تواند قابلیت Traceability و Reproducibility را افزایش دهد.

Registry فقط محل ذخیره فایل نیست

یک تصور اشتباه این است که Container Registry را صرفاً یک File Storage برای Docker Imageها بدانیم.

Registry مدرن معمولاً قابلیت‌های بسیار بیشتری دارد، از جمله:

  • Authentication
  • Authorization
  • Repository Management
  • Image Tagging
  • Image Retention
  • Garbage Collection
  • Vulnerability Scanning
  • Audit Logs
  • Replication
  • Access Control
  • Integration با CI/CD

همین قابلیت‌ها است که راهکارهایی مانند Harbor را از یک Registry ساده Docker متمایز می‌کند.

Docker Registry چیست؟

Docker Registry یک پیاده‌سازی Open Source و رسمی از Registry API است که برای ذخیره و توزیع Container Imageها استفاده می‌شود.

این پروژه در مقایسه با راهکارهایی مانند Harbor یا GitLab Container Registry، یک Registry نسبتاً ساده و سبک در اختیار شما قرار می‌دهد و تمرکز اصلی آن روی ذخیره و دریافت Imageها است.

برای مثال می‌توان یک Registry داخلی را روی Server سازمان اجرا کرد:


Developer
    │
    ▼
Docker Build
    │
    ▼
docker push
    │
    ▼
┌─────────────────────────┐
│  Docker Registry        │
│                         │
│  registry.company.local │
└─────────────────────────┘
    │
    ▼
docker pull
    │
    ▼
Kubernetes / Docker Host

راه‌اندازی یک Registry ساده با Docker نیز امکان‌پذیر است:

docker run -d \
  --name registry \
  --restart=always \
  -p 5000:5000 \
  registry:3

در این حالت Registry روی Port 5000 در دسترس خواهد بود.

البته این Configuration برای یک محیط Production کافی نیست و موضوعاتی مانند TLS، Authentication، Storage Persistence، Backup و Monitoring باید به شکل جداگانه طراحی شوند.

معماری Docker Registry

در ساده‌ترین معماری، Registry از یک API و Storage Backend تشکیل شده است.


                 Docker Client
                      │
                      │ HTTPS
                      ▼
             ┌─────────────────┐
             │ Registry API    │
             └────────┬────────┘
                      │
                      ▼
             ┌─────────────────┐
             │ Storage Backend │
             └────────┬────────┘
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
        Image       Layers      Metadata

Storage Backend می‌تواند بسته به معماری مورد استفاده متفاوت باشد و حتی می‌توان Registry را به Object Storage متصل کرد.

این موضوع برای محیط‌های بزرگ اهمیت زیادی دارد؛ زیرا Container Imageها ممکن است فضای بسیار زیادی مصرف کنند.

Registry و Object Storage

یکی از معماری‌های رایج برای Registryهای Enterprise این است که Imageها به جای Local Disk روی Object Storage ذخیره شوند.


                Registry
                    │
                    ▼
              Storage Driver
                    │
                    ▼
              Object Storage
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
       S3          MinIO      Cloud Storage

برای مثال می‌توان Registry را به MinIO متصل کرد و داده‌های Image را روی یک Object Storage Cluster نگهداری کرد.

این معماری مزایایی مانند Scalability، مدیریت ساده‌تر Storage و امکان استفاده از Storageهای Distributed را فراهم می‌کند.

Authentication در Container Registry

در یک Registry عمومی ممکن است همه کاربران بتوانند Imageها را Pull کنند، اما در یک Registry سازمانی معمولاً باید دسترسی‌ها کنترل شوند.

Authentication مشخص می‌کند که کاربر یا سرویس چه کسی است.

برای مثال:


Developer
    │
    │ Username / Password
    ▼
Registry
    │
    ├── Authentication
    │
    └── Access Granted

Docker Client می‌تواند با Registry Login کند:

docker login registry.company.local

پس از Authentication، Client می‌تواند بر اساس Permissionهای خود Imageها را Push یا Pull کند.

Authorization چیست؟

Authentication و Authorization دو مفهوم متفاوت هستند.

  • Authentication: شما چه کسی هستید؟
  • Authorization: چه کاری اجازه دارید انجام دهید؟

برای مثال ممکن است یک Developer بتواند Image را Pull کند اما اجازه Push به Repository Production را نداشته باشد.


User
 │
 ▼
Authentication
 │
 ▼
Identity
 │
 ▼
Authorization
 │
 ├── Pull ✓
 ├── Push ✓
 ├── Delete ✕
 └── Admin  ✕

TLS و HTTPS در Container Registry

استفاده از HTTPS در Registryهای Production بسیار مهم است.

Registry معمولاً شامل Imageهایی است که ممکن است شامل کد اختصاصی، Dependencyهای داخلی یا اطلاعات حساس باشند. بنابراین ارتباط بین Client و Registry باید رمزنگاری شود.


Docker Client
     │
     │ HTTPS / TLS
     ▼
┌──────────────────────┐
│ Container Registry   │
└──────────────────────┘

در محیط Production بهتر است Registry با یک Domain مشخص و Certificate معتبر در دسترس باشد:


registry.example.com
        │
        ▼
      HTTPS
        │
        ▼
      :443

استفاده از Reverse Proxyهایی مانند Nginx، Caddy یا HAProxy نیز می‌تواند برای Terminate کردن TLS و کنترل دسترسی به Registry مفید باشد.

آیا می‌توان Registry را بدون HTTPS اجرا کرد؟

از نظر فنی امکان اجرای Registry بدون TLS وجود دارد، اما این روش برای Production مناسب نیست.

Docker در چنین شرایطی Registry را به عنوان یک Insecure Registry در نظر می‌گیرد و باید روی Clientها تنظیمات خاصی انجام شود.

برای مثال:


{
  "insecure-registries": [
    "registry.example.com:5000"
  ]
}

این روش بیشتر برای Lab، Development یا محیط‌های کاملاً کنترل‌شده کاربرد دارد و برای Registry Production بهتر است از TLS معتبر استفاده شود.

Harbor چیست؟

Harbor یکی از محبوب‌ترین راهکارهای Open Source برای راه‌اندازی یک Enterprise Container Registry است.

Harbor در واقع فقط یک Docker Registry ساده نیست؛ بلکه مجموعه‌ای از قابلیت‌های مدیریتی، امنیتی و عملیاتی را روی Registry ارائه می‌کند.

به همین دلیل Harbor در بسیاری از Data Centerها، Private Cloudها و Kubernetes Environmentها مورد استفاده قرار می‌گیرد.

چرا Harbor به وجود آمد؟

یک Registry ساده وظیفه اصلی خود یعنی ذخیره و توزیع Imageها را به خوبی انجام می‌دهد، اما در یک سازمان بزرگ معمولاً نیازهای بیشتری داریم.

برای مثال:

  • مدیریت چندین Project
  • مدیریت User و Team
  • Role-Based Access Control
  • Vulnerability Scanning
  • Image Replication
  • Audit Log
  • Image Retention
  • Garbage Collection
  • OIDC / LDAP Integration
  • Web UI
  • Policy Management

Harbor برای پاسخ دادن به همین نیازها ساخته شده است.

معماری Harbor

Harbor از چند Component تشکیل شده که در کنار یکدیگر یک Container Registry کامل را ایجاد می‌کنند.


                    Users / CI/CD
                         │
                         ▼
                  ┌─────────────┐
                  │    Harbor   │
                  │     UI      │
                  └──────┬──────┘
                         │
                         ▼
                ┌─────────────────┐
                │ Harbor Proxy    │
                └────────┬────────┘
                         │
        ┌────────────────┼────────────────┐
        ▼                ▼                ▼
   Registry           Core API        Scanner
        │                │                │
        └────────────────┼────────────────┘
                         ▼
                    Database
                         │
                         ▼
                    Redis / Cache
                         │
                         ▼
                  Storage Backend

معماری دقیق Harbor بسته به Version و Configuration می‌تواند متفاوت باشد، اما به صورت مفهومی می‌توان آن را مجموعه‌ای از سرویس‌های مرتبط دانست که روی یک Registry Core قرار گرفته‌اند.

مهم‌ترین قابلیت‌های Harbor

1. Project Management

در Harbor می‌توان Imageها را در قالب Projectهای مختلف مدیریت کرد.


Harbor
│
├── project-backend
│   ├── api
│   ├── worker
│   └── scheduler
│
├── project-frontend
│   ├── web
│   └── nginx
│
└── project-infrastructure
    ├── monitoring
    ├── logging
    └── tools

این ساختار برای سازمان‌هایی که تیم‌ها و Applicationهای متعددی دارند بسیار مفید است.

2. Role-Based Access Control

Harbor امکان تعریف Roleهای مختلف برای کاربران و Projectها را فراهم می‌کند.

برای مثال:

  • Project Admin
  • Developer
  • Guest
  • Maintainer

در نتیجه می‌توان مشخص کرد چه کسی اجازه Push، Pull یا مدیریت Repositoryها را داشته باشد.

3. Vulnerability Scanning

یکی از مهم‌ترین ویژگی‌های Harbor قابلیت اسکن Container Imageها برای پیدا کردن Vulnerabilityهای شناخته‌شده است.


Docker Image
     │
     ▼
Harbor
     │
     ▼
Vulnerability Scanner
     │
     ├── Critical
     ├── High
     ├── Medium
     └── Low

این قابلیت کمک می‌کند قبل از Deploy شدن Image در Production، وضعیت امنیتی آن بررسی شود.

در معماری‌های DevSecOps می‌توان این فرآیند را با CI/CD نیز ترکیب کرد تا Imageهای دارای Vulnerabilityهای مشخص اجازه ورود به محیط Production را نداشته باشند.

4. Image Replication

Harbor می‌تواند Imageها را بین Registryهای مختلف Replicate کند.


             Harbor - Site A
                    │
                    │ Replication
                    ▼
             Harbor - Site B
                    │
                    ▼
             Disaster Recovery

این قابلیت برای سازمان‌هایی که چند Data Center دارند بسیار کاربردی است.

برای مثال می‌توان Registry اصلی را در Data Center اول قرار داد و Imageهای مهم را به Registry موجود در Data Center دوم Replicate کرد.

5. Image Retention

در پروژه‌های بزرگ ممکن است تعداد Imageها و Tagها به سرعت افزایش پیدا کند.


my-app
│
├── 1.0.0
├── 1.0.1
├── 1.0.2
├── 1.0.3
├── 1.0.4
├── ...
├── 1.9.8
└── latest

اگر هیچ Policy برای حذف Versionهای قدیمی وجود نداشته باشد، Storage Registry به مرور زمان پر خواهد شد.

Retention Policy کمک می‌کند Imageها و Artifactهای قدیمی بر اساس Ruleهای مشخص حذف یا نگهداری شوند.

6. Garbage Collection

حذف یک Tag الزاماً به معنی آزاد شدن فوری تمام فضای Disk نیست.

Container Imageها از Layerهایی تشکیل شده‌اند و ممکن است یک Layer توسط چند Image مورد استفاده قرار گرفته باشد.


Image A ──┐
          ├── Layer 1
Image B ──┘

Image A ───── Layer 2

Image B ───── Layer 3

Registry باید تشخیص دهد کدام Layerها دیگر توسط هیچ Imageای استفاده نمی‌شوند و می‌توان آن‌ها را حذف کرد.

این فرآیند در قالب Garbage Collection انجام می‌شود.

Harbor و Kubernetes

Harbor یکی از گزینه‌های محبوب برای Kubernetes Clusterهای Private و Enterprise است.

Kubernetes برای اجرای یک Pod ممکن است نیاز داشته باشد Image را از Registry دریافت کند.


Kubernetes
    │
    ▼
Pod Specification
    │
    ▼
Container Image
    │
    ▼
Harbor
    │
    ▼
Image Pull
    │
    ▼
Container Runtime

اگر Harbor Private باشد، Kubernetes باید Credential لازم برای دسترسی به Registry را داشته باشد.

این کار معمولاً با استفاده از imagePullSecrets انجام می‌شود.

apiVersion: v1
kind: Secret
metadata:
  name: registry-secret
type: kubernetes.io/dockerconfigjson

سپس می‌توان Secret را در Deployment یا Service Account مورد استفاده قرار داد.

Harbor و Kubernetes در یک معماری Private Cloud

در یک زیرساخت Private Cloud مدرن، Harbor می‌تواند بین CI/CD و Kubernetes قرار بگیرد.


                 Developer
                     │
                     ▼
                Git Repository
                     │
                     ▼
                  CI/CD
                     │
              Docker Build
                     │
                     ▼
              Security Scan
                     │
                     ▼
                  Harbor
                     │
                     ▼
                Kubernetes
                     │
                     ▼
                  Pods

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

Harbor و GitLab چه تفاوتی دارند؟

Harbor و GitLab Container Registry هر دو می‌توانند Container Imageها را ذخیره کنند، اما هدف اصلی آن‌ها متفاوت است.

Harbor در درجه اول یک Container Registry و Artifact Management Platform است، در حالی که GitLab یک پلتفرم کامل DevSecOps است که Container Registry یکی از قابلیت‌های آن محسوب می‌شود.


GitLab
│
├── Git Repository
├── Issues
├── CI/CD
├── Packages
├── Container Registry
├── Security
└── DevSecOps

در مقابل:


Harbor
│
├── Container Registry
├── Artifact Management
├── Vulnerability Scanning
├── Replication
├── RBAC
└── Security Policies

بنابراین انتخاب بین این دو به معماری سازمان و ابزارهای موجود بستگی دارد.

GitLab Container Registry چیست؟

GitLab Container Registry Registry داخلی GitLab برای ذخیره و مدیریت Container Imageها است.

مزیت مهم آن این است که Repository، Source Code، CI/CD Pipeline و Container Registry می‌توانند در یک پلتفرم واحد قرار داشته باشند.


                    GitLab
                       │
       ┌───────────────┼────────────────┐
       ▼               ▼                ▼
   Repository        CI/CD         Container Registry
       │               │                │
       └───────────────┼────────────────┘
                       ▼
                   Deployment

برای تیم‌هایی که از GitLab به عنوان پلتفرم اصلی Development و خدمات دواپس استفاده می‌کنند، این Integration می‌تواند بسیار ارزشمند باشد.

Docker Registry یا Harbor یا GitLab Registry؟

انتخاب Registry مناسب به اندازه و نیاز سازمان بستگی دارد.

ویژگی Docker Registry Harbor GitLab Registry
Open Source بله بله بله
سادگی بسیار زیاد متوسط متوسط
Web UI به صورت Native محدود بله بله
RBAC محدود قوی قوی
Vulnerability Scanning Native محدود بله بله
Replication محدود بله بسته به معماری
CI/CD Integration نیازمند Integration بسیار خوب عالی
Git Repository خیر خیر بله
DevSecOps Platform خیر خیر بله
مناسب برای Enterprise با طراحی مناسب بسیار مناسب بسیار مناسب

چه زمانی Docker Registry ساده انتخاب خوبی است؟

اگر فقط به یک Registry سبک برای ذخیره و دریافت Image نیاز دارید، Docker Registry می‌تواند انتخاب بسیار خوبی باشد.

برای مثال:

  • Lab و Development
  • پروژه‌های کوچک
  • محیط‌های داخلی ساده
  • CI/CD ساده
  • Registry موقت

مزیت اصلی آن سادگی و مصرف پایین منابع است.

چه زمانی Harbor انتخاب بهتری است؟

Harbor زمانی جذاب‌تر می‌شود که Registry بخشی از یک Infrastructure جدی باشد.

برای مثال:

  • Private Cloud
  • Kubernetes Production
  • چندین تیم Development
  • نیاز به RBAC
  • نیاز به Vulnerability Scanning
  • چند Data Center
  • نیاز به Image Replication
  • نیاز به Audit و Governance

چه زمانی GitLab Container Registry انتخاب بهتری است؟

اگر GitLab از قبل پلتفرم اصلی تیم باشد، استفاده از Container Registry داخلی GitLab معمولاً بسیار منطقی است.

در این حالت می‌توان کل مسیر زیر را در یک Platform مدیریت کرد:


Code
  │
  ▼
GitLab Repository
  │
  ▼
GitLab CI/CD
  │
  ▼
Docker Build
  │
  ▼
GitLab Container Registry
  │
  ▼
Kubernetes

این مدل پیچیدگی Integration بین سیستم‌های مختلف را کاهش می‌دهد.

Harbor در مقابل Docker Hub

Docker Hub یک سرویس Registry عمومی و Cloud-based است، در حالی که Harbor را می‌توان داخل Infrastructure سازمان Deploy کرد.

ویژگی Docker Hub Harbor
نوع Cloud Service Self-hosted
کنترل زیرساخت محدود کامل
Private Registry بله بله
استقرار داخل Data Center خیر بله
Replication بین Registryها محدودتر بله
Integration با Private Cloud خوب عالی

برای سازمان‌هایی که به دلایل امنیتی، Compliance یا Network Architecture نمی‌توانند Imageهای خود را در یک سرویس عمومی نگهداری کنند، Self-hosted Registry مانند Harbor گزینه بسیار مناسبی است.

Container Registry و Software Supply Chain

در معماری‌های مدرن DevOps، Container Registry دیگر صرفاً یک Storage برای Imageها نیست و به یکی از نقاط مهم Software Supply Chain تبدیل شده است.


Source Code
    │
    ▼
Build
    │
    ▼
Container Image
    │
    ▼
Security Scan
    │
    ▼
Registry
    │
    ▼
Deployment
    │
    ▼
Production

اگر Image آلوده یا دارای Vulnerability شدید وارد Registry شود و بدون کنترل به Production برسد، کل زنجیره Software Delivery تحت تأثیر قرار می‌گیرد.

به همین دلیل Registryهای مدرن معمولاً با ابزارهای Security و CI/CD یکپارچه می‌شوند.

Image Signing چیست؟

یکی از موضوعات مهم‌تر در امنیت Containerها، اطمینان از اصالت Image است.

در یک Supply Chain امن، فقط اینکه Image از Registry داخلی آمده باشد کافی نیست؛ باید بتوانیم بررسی کنیم Image توسط منبع مورد اعتماد ساخته و منتشر شده است.


Container Image
      │
      ▼
   Signing
      │
      ▼
   Registry
      │
      ▼
Verification
      │
      ▼
  Deployment

فناوری‌هایی مانند Sigstore، Cosign و Notary در این حوزه مورد استفاده قرار می‌گیرند.

این موضوع مخصوصاً در محیط‌های Enterprise و Kubernetes که Security و Supply Chain اهمیت بالایی دارند، اهمیت زیادی پیدا می‌کند.

Image Scanning در CI/CD

بهتر است Vulnerability Scanning فقط بعد از ورود Image به Registry انجام نشود و بخشی از Pipeline نیز باشد.


Git Push
   │
   ▼
CI Pipeline
   │
   ▼
Docker Build
   │
   ▼
Vulnerability Scan
   │
   ├── Critical ──► STOP
   │
   └── Pass
        │
        ▼
      Push
        │
        ▼
     Registry

در این مدل می‌توان Policy تعریف کرد که مثلاً Image دارای Vulnerability با Severity مشخص اجازه ورود به Production را نداشته باشد.

Container Registry و Air-Gapped Environment

در برخی سازمان‌ها Infrastructure به Internet دسترسی مستقیم ندارد. این محیط‌ها را معمولاً Air-Gapped یا محدود از نظر Network Connectivity می‌دانیم.

در چنین محیط‌هایی داشتن یک Private Registry داخلی اهمیت بسیار زیادی دارد.


             Internet
                │
                X
                │
        ┌─────────────────┐
        │ Air-Gapped DC   │
        │                 │
        │ Harbor          │
        │    │            │
        │    ▼            │
        │ Kubernetes      │
        └─────────────────┘

در این معماری Imageهای موردنیاز می‌توانند از طریق فرآیندهای کنترل‌شده وارد محیط شوند و سپس Kubernetes و سایر سرویس‌ها فقط از Registry داخلی استفاده کنند.

Registry Mirror چیست؟

در برخی معماری‌ها به جای اینکه تمام Serverها مستقیماً Imageهای موردنیاز خود را از Docker Hub یا Registry خارجی دریافت کنند، یک Registry داخلی به عنوان Mirror یا Cache در نظر گرفته می‌شود.


                Docker Hub
                     │
                     ▼
               Registry Mirror
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
        Node 1     Node 2     Node 3

این معماری می‌تواند باعث کاهش ترافیک Internet، افزایش سرعت Pull و کاهش وابستگی به سرویس‌های خارجی شود.

در محیط‌هایی که تعداد زیادی Kubernetes Node یا CI Runner وجود دارد، این موضوع می‌تواند تأثیر قابل توجهی روی Network و زمان Deployment داشته باشد.

طراحی Container Registry برای محیط Production

راه‌اندازی یک Container Registry در محیط Development معمولاً ساده است، اما وقتی Registry وارد محیط Production می‌شود، باید آن را مانند هر سرویس زیرساختی مهم دیگری طراحی و مدیریت کرد.

Registry ممکن است محل نگهداری صدها یا هزاران Image مربوط به Applicationهای سازمان باشد و اختلال در آن می‌تواند مستقیماً روی فرآیندهای Deployment تأثیر بگذارد.

یک معماری Production معمولاً باید حداقل موارد زیر را در نظر بگیرد:

  • High Availability
  • Persistent Storage
  • TLS
  • Authentication و Authorization
  • Backup
  • Monitoring
  • Logging
  • Vulnerability Scanning
  • Image Retention
  • Disaster Recovery

Storage در Container Registry

Storage یکی از مهم‌ترین بخش‌های معماری Registry است؛ زیرا حجم Container Imageها می‌تواند به سرعت افزایش پیدا کند.

فرض کنید یک تیم ۲۰ Application دارد و هر Application به صورت میانگین ۱۰ Version مختلف از Image خود را نگهداری می‌کند. اگر حجم متوسط هر Image حدود 500MB باشد، خیلی سریع با چندین ده گیگابایت داده مواجه خواهیم شد.

در سازمان‌های بزرگ این مقدار می‌تواند به صدها گیگابایت یا حتی چندین ترابایت برسد.

Local Storage

در ساده‌ترین معماری، Imageها روی Local Disk همان Server ذخیره می‌شوند.


Registry
   │
   ▼
Local Disk
   │
   ├── Image Layers
   ├── Metadata
   └── Artifacts

این روش ساده است اما برای معماری‌های Highly Available محدودیت‌هایی دارد.

Network Storage

در برخی معماری‌ها Storage روی یک Shared Storage قرار می‌گیرد.


             Registry
                │
                ▼
         Shared Storage
                │
       ┌────────┼────────┐
       ▼        ▼        ▼
     Node 1   Node 2   Node 3

این روش امکان اجرای چند Instance از Registry را ساده‌تر می‌کند، البته باید Performance، Consistency و قابلیت‌های Storage مورد استفاده نیز به دقت بررسی شوند.

Object Storage

برای Registryهای بزرگ، استفاده از Object Storage یکی از معماری‌های بسیار مناسب است.


                 Registry
                     │
                     ▼
                Object Storage
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
         S3        MinIO      Cloud Object Storage

Object Storageهایی مانند S3 و MinIO می‌توانند برای ذخیره Layerهای Image و Artifactها مورد استفاده قرار بگیرند.

این معماری مخصوصاً زمانی جذاب است که Registry باید در یک Private Cloud یا Data Center بزرگ اجرا شود.

High Availability برای Container Registry

اگر Registry فقط روی یک Server اجرا شود، همان Server به یک Single Point of Failure تبدیل خواهد شد.


                  Clients
                     │
                     ▼
               ┌──────────┐
               │ Registry │
               │  Node 1  │
               └────┬─────┘
                    │
                  Failure
                    │
                    X

در این حالت اگر Server از دسترس خارج شود، Kubernetes و CI/CD Pipelineهایی که به آن Registry وابسته هستند نیز ممکن است با مشکل مواجه شوند.

برای افزایش Availability می‌توان چند Instance از Registry را پشت Load Balancer قرار داد.


                    Clients
                       │
                       ▼
                ┌─────────────┐
                │ Load Balancer│
                └──────┬──────┘
                       │
              ┌────────┴────────┐
              ▼                 ▼
       ┌────────────┐    ┌────────────┐
       │ Registry 1 │    │ Registry 2 │
       └──────┬─────┘    └──────┬─────┘
              │                 │
              └────────┬────────┘
                       ▼
                Shared Storage

البته High Availability واقعی فقط با اضافه کردن دو Registry Instance ایجاد نمی‌شود و تمام Componentهای معماری، از Storage تا Database و Load Balancer، باید از نظر Availability بررسی شوند.

Load Balancer در مقابل Container Registry

قرار دادن Load Balancer جلوی Registry باعث می‌شود Clientها به جای اتصال مستقیم به یک Node، از یک Endpoint واحد استفاده کنند.


docker / Kubernetes / CI
            │
            ▼
     registry.example.com
            │
            ▼
       Load Balancer
        │         │
        ▼         ▼
    Registry 1  Registry 2

این Load Balancer می‌تواند با ابزارهایی مانند HAProxy، Nginx، Caddy یا Load Balancerهای Cloud پیاده‌سازی شود.

در محیط‌های Enterprise بهتر است Health Check نیز فعال باشد تا در صورت Down شدن یکی از Registry Nodeها، Traffic به Node سالم منتقل شود.

Backup از Container Registry

یکی از اشتباهات رایج این است که چون Imageها از Source Code قابل Build هستند، نیازی به Backup Registry نداریم.

در واقع ممکن است Registry علاوه بر Container Image، شامل Artifactهای مهم، Configurationها، Metadata و Imageهای Release شده‌ای باشد که Rebuild کردن آن‌ها همیشه ساده یا حتی ممکن نیست.

بنابراین Backup باید بخشی از طراحی Registry باشد.

چه چیزهایی باید Backup شوند؟

  • Container Imageها
  • Artifactها
  • Metadata
  • Database
  • Registry Configuration
  • Authentication Configuration
  • Security Policyها
  • Replication Configuration

در Harbor نیز باید علاوه بر Storage مربوط به Imageها، Componentهای مدیریتی و Database نیز در برنامه Backup و Disaster Recovery در نظر گرفته شوند.

Disaster Recovery برای Registry

در زیرساخت‌های حساس، داشتن Backup به تنهایی کافی نیست. باید مشخص باشد که در صورت از دست رفتن کامل Data Center چگونه Registry را دوباره راه‌اندازی خواهیم کرد.


             Primary Data Center
                    │
                    │ Replication
                    ▼
             Secondary DC
                    │
                    ▼
              DR Registry

یکی از روش‌های متداول، Replication Imageها به Registry موجود در یک Data Center دیگر است.

در این حالت اگر Data Center اصلی از دسترس خارج شود، کوبرنتیز و CI/CD می‌توانند به Registry ثانویه متصل شوند.

Container Registry و Multi-Data Center

در سازمان‌هایی که چند Data Center دارند، می‌توان برای هر Data Center یک Registry محلی در نظر گرفت.


                 CI/CD
                   │
                   ▼
             Primary Harbor
              /          \
             /            \
            ▼              ▼
       Data Center 1   Data Center 2
         Harbor           Harbor
            │                │
            ▼                ▼
       Kubernetes        Kubernetes

این معماری چند مزیت مهم دارد:

  • کاهش Latency هنگام Pull کردن Image
  • کاهش مصرف لینک بین Data Centerها
  • افزایش Availability
  • امکان Disaster Recovery
  • کاهش وابستگی به یک Registry واحد

Monitoring برای Container Registry

Registry نیز مانند سایر سرویس‌های زیرساختی باید Monitoring شود.

برخی Metricهای مهم عبارت‌اند از:

  • CPU Usage
  • Memory Usage
  • Disk Usage
  • Storage Growth
  • HTTP Request Rate
  • HTTP Error Rate
  • Pull / Push Latency
  • Failed Authentication
  • Registry Availability
  • Garbage Collection Duration

در معماری‌های Kubernetes معمولاً می‌توان Metricها را با Prometheus جمع‌آوری و در Grafana نمایش داد.


Container Registry
       │
       │ Metrics
       ▼
   Prometheus
       │
       ▼
    Grafana
       │
       ▼
    Alerting

Logging و Audit در Registry

Monitoring به ما می‌گوید سیستم چه وضعیتی دارد، اما برای فهمیدن اینکه چه اتفاقی افتاده است، به Logging و Audit نیاز داریم.

برای مثال ممکن است بخواهیم بدانیم:

  • چه کسی یک Image را Push کرده است؟
  • چه کسی Image را Delete کرده است؟
  • چه کسی به یک Project دسترسی پیدا کرده است؟
  • چه زمانی یک Authentication ناموفق رخ داده است؟
  • کدام Image بیشترین Pull را داشته است؟

در محیط‌های Enterprise این اطلاعات برای Security، Troubleshooting و Compliance اهمیت زیادی دارند.

Image Lifecycle Management

هر Image باید یک Lifecycle مشخص داشته باشد.

برای مثال:


Build
  │
  ▼
Test
  │
  ▼
Scan
  │
  ▼
Registry
  │
  ▼
Staging
  │
  ▼
Production
  │
  ▼
Retention
  │
  ▼
Cleanup

بدون Lifecycle Management، Registry به مرور زمان پر از Imageهای قدیمی و غیرضروری می‌شود.

چرا استفاده از latest همیشه ایده خوبی نیست؟

Tag معروف latest برای شروع کار ساده و راحت است، اما در Production می‌تواند مشکلاتی ایجاد کند.

فرض کنید Deployment ما از این Image استفاده می‌کند:


registry.example.com/my-app:latest

امروز latest به Version 1.5 اشاره می‌کند و فردا Developer یک Image جدید Push می‌کند که Version 1.6 است.

در نتیجه مشخص نیست Pod جدید دقیقاً چه نسخه‌ای را اجرا خواهد کرد.

روش بهتر استفاده از Versionهای مشخص است:


registry.example.com/my-app:1.5.0
registry.example.com/my-app:1.5.1
registry.example.com/my-app:1.6.0

حتی بهتر از آن، در Deploymentهای حساس می‌توان از Digest استفاده کرد.


registry.example.com/my-app@sha256:abc123...

Best Practices برای Container Registry

برای داشتن یک Registry امن، پایدار و قابل مدیریت، رعایت چند اصل مهم توصیه می‌شود.

۱. همیشه از TLS استفاده کنید

Registry Production را روی HTTPS قرار دهید و از Certificate معتبر استفاده کنید.

۲. Authentication را فعال کنید

Registry نباید بدون کنترل دسترسی روی Internet یا Network داخلی قرار بگیرد.

۳. Push و Pull را از هم تفکیک کنید

هر User یا Service نباید الزاماً اجازه Push داشته باشد.

۴. از RBAC استفاده کنید

دسترسی‌ها را بر اساس Project، Team و Role مدیریت کنید.

۵. Imageها را Scan کنید

قبل از Production Deployment، Imageها را از نظر Vulnerability بررسی کنید.

۶. Retention Policy تعریف کنید

Imageهای قدیمی و غیرضروری را به صورت کنترل‌شده پاک‌سازی کنید.

۷. از Backup غافل نشوید

برای Registry یک Backup و Disaster Recovery Strategy مشخص داشته باشید.

۸. Image Tagging استاندارد داشته باشید

از Versioning مشخص و قابل ردیابی استفاده کنید.

۹. Registry را Monitor کنید

Disk، Storage Growth، Error Rate، Latency و Availability را تحت نظر داشته باشید.

۱۰. Registry را مستقیماً روی Internet رها نکنید

در صورت نیاز به دسترسی خارجی، از Firewall، Reverse Proxy، TLS، Authentication و Access Policy مناسب استفاده کنید.

نمونه معماری پیشنهادی برای یک Private Cloud

برای یک سازمان متوسط یا بزرگ که Kubernetes و CI/CD را در یک Private Cloud اجرا می‌کند، می‌توان معماری زیر را در نظر گرفت:


                         Developers
                              │
                              ▼
                         GitLab / Git
                              │
                              ▼
                         CI/CD Runners
                              │
                       Docker Build
                              │
                              ▼
                       Image Scanning
                              │
                              ▼
                     ┌─────────────────┐
                     │     Harbor      │
                     │                 │
                     │  Registry       │
                     │  RBAC           │
                     │  Scanner        │
                     │  Replication    │
                     └────────┬────────┘
                              │
                       Object Storage
                              │
                              ▼
                         Kubernetes
                              │
                    ┌─────────┼─────────┐
                    ▼         ▼         ▼
                  Node 1    Node 2    Node 3

در چنین معماری‌ای GitLab مسئول Source Code و CI/CD است، Harbor وظیفه مدیریت Container Image و Artifactها را بر عهده دارد و Kubernetes محیط اجرای Applicationها است.

آیا هر سازمانی به Harbor نیاز دارد؟

خیر.

انتخاب Registry باید بر اساس نیاز واقعی Infrastructure انجام شود.

اگر فقط یک پروژه کوچک دارید و چند Image ساده نگهداری می‌کنید، یک Registry ساده می‌تواند کاملاً کافی باشد.

اما وقتی تعداد Applicationها، تیم‌ها، Kubernetes Clusterها و Data Centerها افزایش پیدا می‌کند، قابلیت‌هایی مانند RBAC، Scanning، Replication، Audit و Retention اهمیت بیشتری پیدا می‌کنند.

به همین دلیل Harbor معمولاً زمانی ارزش خود را نشان می‌دهد که Container Registry به یک جزء مهم از معماری DevOps و Private Cloud تبدیل شده باشد.

جمع‌بندی

Container Registry یکی از اجزای پایه‌ای معماری‌های مدرن Container و Cloud Native است. Registry محل نگهداری و توزیع Docker Imageها و سایر Container Artifactها است و معمولاً بین فرآیند Build و محیط Deployment قرار می‌گیرد.

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

GitLab Container Registry برای تیم‌هایی که GitLab را به عنوان پلتفرم اصلی Source Code و CI/CD خود استفاده می‌کنند، مزیت Integration بسیار خوبی دارد.

در مقابل، Harbor یک راهکار کامل‌تر برای سازمان‌هایی است که به قابلیت‌هایی مانند RBAC، Vulnerability Scanning، Replication، Retention، Audit و مدیریت Enterprise-level Container Imageها نیاز دارند.

در یک زیرساخت Private Cloud و Kubernetes Production، Registry را نباید صرفاً یک Storage ساده در نظر گرفت. Registry بخشی از Software Supply Chain است و امنیت، Availability، Backup، Monitoring و Lifecycle Management آن مستقیماً روی فرآیند Software Delivery تأثیر می‌گذارد.

به طور خلاصه، اگر معماری شما شامل Docker + Kubernetes + CI/CD است، داشتن یک Container Registry استاندارد و امن تقریباً یک جزء ضروری از معماری محسوب می‌شود.

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

Container Registry چیست؟

Container Registry سرویسی برای ذخیره، مدیریت و توزیع Container Imageها است. Docker، Kubernetes و CI/CD Pipelineها می‌توانند Imageها را در Registry Push یا از آن Pull کنند.

تفاوت Docker Registry و Docker Hub چیست؟

Docker Registry یک نرم‌افزار برای راه‌اندازی Registry است، در حالی که Docker Hub یک سرویس عمومی و مدیریت‌شده برای میزبانی Container Imageها است.

Harbor چیست؟

Harbor یک Container Registry متن‌باز و Enterprise-oriented است که علاوه بر ذخیره Image، قابلیت‌هایی مانند RBAC، Vulnerability Scanning، Replication، Retention و Audit را ارائه می‌دهد.

آیا Harbor رایگان است؟

Harbor یک پروژه Open Source است و می‌توان آن را به صورت Self-hosted در زیرساخت سازمان اجرا کرد. هزینه اصلی معمولاً مربوط به Infrastructure، Storage، مدیریت و نگهداری آن است.

آیا GitLab خودش Container Registry دارد؟

بله. GitLab دارای Container Registry داخلی است که با Git Repository و CI/CD آن یکپارچه می‌شود.

برای Kubernetes بهتر است از چه Registry استفاده کنیم؟

برای محیط‌های کوچک می‌توان از Registryهای ساده استفاده کرد، اما در Kubernetes Production و Private Cloud، راهکارهایی مانند Harbor یا GitLab Container Registry معمولاً قابلیت‌های مدیریتی و امنیتی بیشتری ارائه می‌کنند.

آیا Container Registry باید روی همان کلاستر کوبرنتیز باشد؟

الزامی نیست و در بسیاری از معماری‌ها حتی بهتر است Registry به صورت مستقل از Kubernetes Cluster اجرا شود تا در صورت بروز مشکل در Cluster، Registry همچنان در دسترس باشد.

آیا می‌توان Harbor را روی Kubernetes اجرا کرد؟

بله. Harbor می‌تواند در معماری‌های کوبرنتیس نیز Deploy شود، اما انتخاب روش Deployment باید با توجه به Storage، Availability، Backup و پیچیدگی عملیاتی سازمان انجام شود.

آیا Docker Registry از کوبرنتیز پشتیبانی می‌کند؟

بله. Kubernetes برای Pull کردن Container Image به Registry خاصی وابسته نیست و می‌تواند از Registryهای سازگار با استاندارد OCI/Docker Registry استفاده کند.

آیا Container Registry فقط برای Docker Image است؟

خیر. Registryهای مدرن می‌توانند علاوه بر Container Image، انواع Artifactهای مرتبط با Cloud Native و Software Supply Chain را نیز مدیریت کنند.

آیا استفاده از latest در Production مناسب است؟

معمولاً توصیه نمی‌شود. استفاده از Versionهای مشخص یا حتی Image Digest باعث می‌شود Deploymentها قابل پیش‌بینی‌تر و قابل ردیابی‌تر باشند.

آیا Container Registry نیاز به Backup دارد؟

بله. در محیط‌های Production باید Imageها، Metadata، Database و Configurationهای مرتبط بر اساس معماری Registry در برنامه Backup و Disaster Recovery قرار بگیرند.

آیا می‌توان Container Registry را روی MinIO قرار داد؟

بله. برخی Registryها و راهکارهایی مانند Harbor می‌توانند از Object Storageهای سازگار با S3 برای ذخیره Imageها و Artifactها استفاده کنند. این معماری برای Private Cloudهای بزرگ می‌تواند گزینه مناسبی باشد.

تفاوت Image Tag و Image Digest چیست؟

Tag یک نام قابل تغییر برای اشاره به یک Version از Image است، اما Digest بر اساس محتوای Image تولید می‌شود و یک مرجع دقیق‌تر و Immutable برای همان Image فراهم می‌کند.

آیا Harbor برای یک پروژه کوچک مناسب است؟

از نظر فنی بله، اما ممکن است قابلیت‌ها و پیچیدگی Harbor برای یک پروژه کوچک بیشتر از نیاز واقعی باشد. در چنین شرایطی یک Registry ساده یا Registry داخلی GitLab می‌تواند انتخاب منطقی‌تری باشد.

Container Registry چه نقشی در DevOps دارد؟

Registry معمولاً نقطه اتصال بین Build و Deployment است. CI/CD Image را Build و Push می‌کند و Kubernetes یا سایر محیط‌های اجرای Container آن را Pull و اجرا می‌کنند.

درخواست مشاوره تخصصی

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

تلفن: 021-91692276
مورد اعتماد شرکت‌های بزرگ
گلرنگ
تومن
اسنپ
روم ویو
دماتجهیز
لپیور
اورس
گاما
لطفا حداقل یک خدمت را انتخاب کنید
مشاوره تخصصی