رفتن به محتوا
LoopX

معماری داکر

توی این درس یاد می‌گیری وقتی دستور docker run را می‌زنی دقیقاً چه کسی با چه کسی حرف می‌زند: docker CLI (client) فقط یک پیام به daemon می‌فرستد، dockerd کار را هماهنگ می‌کند، containerd و runc کانتینر را می‌سازند و registry جای image هاست. همه‌ی این اجزا را با docker version و docker info پیدا می‌کنی و حتی بدون CLI، مستقیم با REST API داکر حرف می‌زنی.

داکر مثل یک رستوران است. تو مشتری هستی و docker CLI گارسون: فقط سفارش را می‌گیرد و می‌برد. سرآشپز daemon است (dockerd) که برنامه‌ریزی و هماهنگی می‌کند. او خودش هم همه‌چیز را نمی‌پزد؛ کار پخت واقعی را به آشپزهای خط تولید (containerd و runc) می‌سپارد. انبار مواد (registry) هم جایی است که مواد اولیه‌ی غذا (image) را از آنجا می‌آورند.

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

CLI به daemon پیام می‌فرستد؛ daemon از registry image می‌گیرد و کار ساخت کانتینر را به containerd و runc می‌سپارد که روی هسته‌ی لینوکس اجرا می‌شوند.

وقتی docker run hello-world را می‌زنی، ترتیب ماجرا این است:

ترتیب پیام‌ها هنگام docker run: CLI، daemon، registry (در صورت نبودن image) و containerd/runc.

مثال ۱: دو طرف را ببین (docker version)

Section titled “مثال ۱: دو طرف را ببین (docker version)”
Terminal window
docker version
خروجی
Client:
Version: 29.8.1
API version: 1.56
Go version: go1.26.8
Git commit: 4a63305
Built: Tue Sep 15 16:24:48 2026
OS/Arch: darwin/arm64
Context: desktop-linux
Server: Docker Desktop 4.93.0 (240920)
Engine:
Version: 29.8.1
API version: 1.56 (minimum version 1.40)
Go version: go1.26.8
Git commit: 464cd50
Built: Tue Sep 15 16:25:04 2026
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: v2.3.5
GitCommit: 1294c24a7da8e5a793ed378161673abe94118892
runc:
Version: 1.5.1
GitCommit: v1.5.1-0-g8f2685a4
docker-init:
Version: 0.19.0
GitCommit: de40ad0

خروجی دو بخش دارد. Client برنامه‌ی docker روی سیستم تو است. Server همان daemon است و زیرش اجزای داخلی‌اش را فهرست می‌کند: Engine (همان dockerd)، containerd، runc و docker-init. دقت کن Client و Server سیستم‌عامل متفاوت دارند (روی مک، darwin و linux)، چون daemon داخل یک VM لینوکسی اجرا می‌شود.

مثال ۲: اطلاعات کامل daemon (docker info)

Section titled “مثال ۲: اطلاعات کامل daemon (docker info)”
Terminal window
docker info | sed 's#/Users/[^/]*#~#g'
خروجی (بخشی از آن)
Client:
Version: 29.8.1
Context: desktop-linux
Debug Mode: false
Plugins:
agent: Docker AI Agent Runner (Docker Inc.)
Version: v1.141.0
Path: ~/.docker/cli-plugins/docker-agent
ai: Docker AI Agent - Ask Gordon (Docker Inc.)
Version: v1.31.0
Path: ~/.docker/cli-plugins/docker-ai
buildx: Docker Buildx (Docker Inc.)
Version: v0.37.1
Path: ~/.docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v5.5.1
Path: ~/.docker/cli-plugins/docker-compose
debug: Get a shell into any image or container (Docker Inc.)
Version: 0.0.47
Path: ~/.docker/cli-plugins/docker-debug
desktop: Docker Desktop commands (Docker Inc.)
Version: v0.4.4
Path: ~/.docker/cli-plugins/docker-desktop
dhi: CLI for managing Docker Hardened Images (Docker Inc.)
Version: v0.0.7
Path: ~/.docker/cli-plugins/docker-dhi
extension: Manages Docker extensions (Docker Inc.)
Version: v0.2.31
Path: ~/.docker/cli-plugins/docker-extension
init: Creates Docker-related starter files for your project (Docker Inc.)
Version: v1.4.0
Path: ~/.docker/cli-plugins/docker-init
mcp: Docker MCP Plugin (Docker Inc.)
Version: v0.43.3
Path: ~/.docker/cli-plugins/docker-mcp
model: Docker Model Runner (Docker Inc.)
Version: v1.2.6
Path: ~/.docker/cli-plugins/docker-model
offload: Docker Offload (Docker Inc.)
Version: v0.6.33

این خروجی جزئیات زیادی دارد: تعداد کانتینرها و image ها، Storage Driver، Runtimes (که runc در آن است)، Kernel Version، Operating System و مسیر داده‌ها. اگر Server Version یا Runtimes را نمی‌بینی، یعنی به daemon وصل نیستی.

برای یک مقدار مشخص از --format استفاده می‌کنی:

Terminal window
docker info --format 'نسخه: {{.ServerVersion}} | runtime پیش‌فرض: {{.DefaultRuntime}} | کرنل: {{.KernelVersion}}'
خروجی
نسخه: 29.8.1 | runtime پیش‌فرض: runc | کرنل: 7.0.14-linuxkit

مثال ۳: CLI به کجا وصل است؟ (context)

Section titled “مثال ۳: CLI به کجا وصل است؟ (context)”
Terminal window
docker context ls | sed 's#/Users/[^/]*#~#g'
خروجی
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
desktop-linux * Docker Desktop unix://~/.docker/run/docker.sock

ستون DOCKER ENDPOINT آدرس daemon است. ستاره‌ی کنار یکی از ردیف‌ها یعنی «context فعلی». هر context یک آدرس daemon است؛ برای وصل شدن به daemon یک سرور دیگر کافی است یک context تازه بسازی یا DOCKER_HOST را عوض کنی. حالا خود آدرس:

Terminal window
docker context inspect --format 'آدرس daemon: {{.Endpoints.docker.Host}}' | sed 's#/Users/[^/]*#~#g'
خروجی
آدرس daemon: unix://~/.docker/run/docker.sock

یک سوکت یونیکسی است (یک فایل مخصوص برای ارتباط بین دو برنامه روی یک سیستم). روی لینوکس معمولاً /var/run/docker.sock است.

⚡ بررسی سریع

در دستور docker run، چه کسی واقعاً image را از registry دانلود می‌کند؟

مثال ۴: بدون CLI، مستقیم با API (curl)

Section titled “مثال ۴: بدون CLI، مستقیم با API (curl)”

CLI فقط یک «کلاینت REST» است. می‌توانی با curl همان سوکت را صدا بزنی:

Terminal window
SOCK=$(docker context inspect --format '{{.Endpoints.docker.Host}}' | sed 's#unix://##')
curl -s --unix-socket "$SOCK" http://localhost/_ping; echo
curl -s --unix-socket "$SOCK" http://localhost/version | python3 -c 'import sys,json; d=json.load(sys.stdin); print("Version:", d["Version"]); print("ApiVersion:", d["ApiVersion"]); print("Os/Arch:", d["Os"]+"/"+d["Arch"])'
خروجی
OK
Version: 29.8.1
ApiVersion: 1.56
Os/Arch: linux/arm64

_ping جواب OK می‌دهد (daemon زنده است) و /version همان اطلاعات docker version را به‌صورت JSON می‌دهد. همه‌ی دستورهای docker در واقع درخواست‌هایی مثل POST /containers/create یا GET /containers/json هستند.

مثال ۵: ببین در پشت‌صحنه چه رویدادهایی رخ می‌دهد

Section titled “مثال ۵: ببین در پشت‌صحنه چه رویدادهایی رخ می‌دهد”
Terminal window
t=$(date +%s)
docker run --rm hello-world > /dev/null
docker events --since "$t" --until "$(( $(date +%s) + 1 ))" --filter image=hello-world --format '{{.Action}}'
خروجی
create
attach
start
die
destroy

daemon برای هر کار یک رویداد می‌فرستد: ساخت (create)، اتصال (attach)، شروع (start)، پایان (die) و پاک شدن (destroy). دستور docker events همین جریان را نشان می‌دهد؛ ابزارهای مانیتورینگ هم از همین استفاده می‌کنند.

جدا بودنشان یک تصمیم طراحی است: CLI سبک است و daemon همیشه روشن می‌ماند و وضعیت (image ها، کانتینرها، شبکه‌ها) را نگه می‌دارد. اگر terminal را ببندی، کانتینرها همچنان کار می‌کنند چون daemon آن‌ها را نگه داشته است.

جزء وظیفه تشبیه
docker CLI دستور تو را به درخواست REST تبدیل می‌کند گارسون
dockerd API، image ها، شبکه، volume ها سرآشپز
containerd چرخه‌ی عمر کانتینر و مدیریت image در سطح پایین مدیر خط تولید
runc ساخت واقعی کانتینر با namespace و cgroup آشپز
Registry ذخیره و توزیع image ها انبار مواد

استانداردی به نام OCI (Open Container Initiative) شکل image و رفتار runtime را مشخص می‌کند؛ به همین دلیل runc و containerd فقط مال داکر نیستند و ابزارهای دیگر (مثل Kubernetes) هم از آن‌ها استفاده می‌کنند.

روی مک و ویندوز، Docker Desktop یک VM لینوکسی کوچک می‌سازد و dockerd را داخل آن اجرا می‌کند؛ CLI روی سیستم اصلی تو است و با سوکتی که Docker Desktop در اختیارش گذاشته حرف می‌زند (همان context بالا). روی لینوکس این VM وجود ندارد و daemon مستقیم روی خود سیستم اجرا می‌شود.

دستور چه چیزی را نشان می‌دهد؟
docker version نسخه‌ی Client و Server و اجزای داخلی (containerd، runc)
docker info وضعیت کلی daemon: تعداد کانتینر و image، storage driver، runtime، کرنل
docker context ls فهرست daemon هایی که CLI می‌تواند به آن‌ها وصل شود
docker events جریان زنده‌ی رویدادهای daemon
DOCKER_HOST=... متغیر محیطی که آدرس daemon را برای یک دستور عوض می‌کند

۱) «به daemon وصل نمی‌شود»

Section titled “۱) «به daemon وصل نمی‌شود»”
Terminal window
DOCKER_HOST=tcp://127.0.0.1:9999 docker ps
خروجی
Cannot connect to the Docker daemon at tcp://127.0.0.1:9999. Is the docker daemon running?

یعنی CLI نتوانست به آدرس داده‌شده برسد (daemon خاموش است یا آدرس غلط). راه‌حل: مطمئن شو داکر روشن است (Docker Desktop را باز کن، یا روی لینوکس sudo systemctl start docker). اگر DOCKER_HOST را قبلاً تنظیم کرده‌ای، آن را پاک کن (unset DOCKER_HOST).

۲) آدرس daemon با فرمت اشتباه

Section titled “۲) آدرس daemon با فرمت اشتباه”
Terminal window
docker -H foo://bar ps
خروجی
Failed to initialize: unable to resolve docker endpoint: invalid bind address format: foo://bar

آدرس باید با unix:// یا tcp:// یا ssh:// شروع شود. راه‌حل: فرمت صحیح را بنویس.

نصب فقط CLI (بدون daemon) کافی نیست. اگر docker version فقط بخش Client را نشان می‌دهد و Server خطا دارد، daemon وجود ندارد یا روشن نیست.

✎ تمرینآسان

فقط نسخه‌ی Server (daemon) را با --format چاپ کن.

دیدن جواب
Terminal window
docker version --format 'Server: {{.Server.Version}}'
خروجی
Server: 29.8.1
✎ تمرینمتوسط

بدون استفاده از docker، فقط با curl و سوکت، بفهم daemon زنده است و Os و Arch آن چیست.

دیدن جواب
Terminal window
SOCK=$(docker context inspect --format '{{.Endpoints.docker.Host}}' | sed 's#unix://##')
curl -s --unix-socket "$SOCK" http://localhost/_ping; echo
curl -s --unix-socket "$SOCK" http://localhost/version | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d["Os"], d["Arch"])'
خروجی
OK
linux arm64
✎ تمرینسخت

ثابت کن docker ps -q و API (/containers/json) تعداد کانتینرهای در حال اجرا را یکسان می‌گویند. هر دو عدد را چاپ کن.

دیدن جواب
Terminal window
SOCK=$(docker context inspect --format '{{.Endpoints.docker.Host}}' | sed 's#unix://##')
echo "CLI: $(docker ps -q | wc -l | tr -d ' ')"
echo "API: $(curl -s --unix-socket "$SOCK" http://localhost/containers/json | python3 -c 'import sys,json; print(len(json.load(sys.stdin)))')"
خروجی
CLI: 8
API: 8

هر دو عدد برابرند، چون docker ps همان درخواست GET /containers/json است.

؟ آزمونک
  1. CLI و daemon چه رابطه‌ای دارند؟

  2. کدام جزء کانتینر را با namespace و cgroup واقعاً می‌سازد؟

  3. ستاره در docker context ls یعنی چه؟

  4. اگر terminal را ببندی، کانتینرهای در حال اجرا چه می‌شوند؟

  5. پیام «Cannot connect to the Docker daemon» یعنی چه؟

  • docker CLI فقط یک کلاینت است؛ dockerd کار را هماهنگ می‌کند و containerd و runc کانتینر را می‌سازند.
  • CLI با daemon از راه REST API روی یک سوکت (یا آدرس شبکه) حرف می‌زند؛ docker context آدرس را مدیریت می‌کند.
  • docker version و docker info اجزا و وضعیت را نشان می‌دهند؛ docker events رویدادها را.
  • روی مک و ویندوز، daemon داخل یک VM لینوکسی اجرا می‌شود.
  • استاندارد OCI باعث می‌شود runc و containerd مال یک شرکت نباشند.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
docker versionنسخه‌ی Client و Server و اجزا
docker version --format "{{.Server.Version}}"فقط نسخه‌ی daemon
docker infoاطلاعات کامل daemon
docker info --format "{{.DefaultRuntime}}"runtime پیش‌فرض (runc)
docker context lsdaemon های قابل اتصال
docker context inspectجزئیات یک context (آدرس سوکت)
docker eventsجریان رویدادهای daemon
curl --unix-socket SOCK http://localhost/_pingتست مستقیم API
DOCKER_HOST=tcp://host:port docker psاجرای یک دستور روی daemon دیگر