توی این درس یاد میگیری وقتی دستور docker run را میزنی دقیقاً چه کسی با چه کسی حرف میزند: docker CLI (client) فقط یک پیام به daemon میفرستد، dockerd کار را هماهنگ میکند، containerd و runc کانتینر را میسازند و registry جای image هاست. همهی این اجزا را با docker version و docker info پیدا میکنی و حتی بدون CLI، مستقیم با REST API داکر حرف میزنی.
تشبیه: رستوران
Section titled “تشبیه: رستوران”داکر مثل یک رستوران است. تو مشتری هستی و docker CLI گارسون: فقط سفارش را میگیرد و میبرد. سرآشپز daemon است (dockerd) که برنامهریزی و هماهنگی میکند. او خودش هم همهچیز را نمیپزد؛ کار پخت واقعی را به آشپزهای خط تولید (containerd و runc) میسپارد. انبار مواد (registry) هم جایی است که مواد اولیهی غذا (image) را از آنجا میآورند.
مهمترین نتیجه: گارسون و آشپزخانه دو برنامهی جدا هستند و میتوانند روی دو سیستم متفاوت باشند. تو میتوانی روی لپتاپت سفارش بدهی و آشپزخانه روی یک سرور دور باشد.
نقشهی کلی
Section titled “نقشهی کلی”وقتی docker run hello-world را میزنی، ترتیب ماجرا این است:
مثالهای عملی
Section titled “مثالهای عملی”مثال ۱: دو طرف را ببین (docker version)
Section titled “مثال ۱: دو طرف را ببین (docker version)”docker versionClient: 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)”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 استفاده میکنی:
docker info --format 'نسخه: {{.ServerVersion}} | runtime پیشفرض: {{.DefaultRuntime}} | کرنل: {{.KernelVersion}}'نسخه: 29.8.1 | runtime پیشفرض: runc | کرنل: 7.0.14-linuxkitمثال ۳: CLI به کجا وصل است؟ (context)
Section titled “مثال ۳: CLI به کجا وصل است؟ (context)”docker context ls | sed 's#/Users/[^/]*#~#g'NAME DESCRIPTION DOCKER ENDPOINT ERRORdefault Current DOCKER_HOST based configuration unix:///var/run/docker.sockdesktop-linux * Docker Desktop unix://~/.docker/run/docker.sockستون DOCKER ENDPOINT آدرس daemon است. ستارهی کنار یکی از ردیفها یعنی «context فعلی». هر context یک آدرس daemon است؛ برای وصل شدن به daemon یک سرور دیگر کافی است یک context تازه بسازی یا DOCKER_HOST را عوض کنی. حالا خود آدرس:
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 فقط درخواست را به daemon میفرستد؛ daemon وصل به registry میشود و image را pull میکند.
مثال ۴: بدون CLI، مستقیم با API (curl)
Section titled “مثال ۴: بدون CLI، مستقیم با API (curl)”CLI فقط یک «کلاینت REST» است. میتوانی با curl همان سوکت را صدا بزنی:
SOCK=$(docker context inspect --format '{{.Endpoints.docker.Host}}' | sed 's#unix://##')curl -s --unix-socket "$SOCK" http://localhost/_ping; echocurl -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"])'OKVersion: 29.8.1ApiVersion: 1.56Os/Arch: linux/arm64_ping جواب OK میدهد (daemon زنده است) و /version همان اطلاعات docker version را بهصورت JSON میدهد. همهی دستورهای docker در واقع درخواستهایی مثل POST /containers/create یا GET /containers/json هستند.
مثال ۵: ببین در پشتصحنه چه رویدادهایی رخ میدهد
Section titled “مثال ۵: ببین در پشتصحنه چه رویدادهایی رخ میدهد”t=$(date +%s)docker run --rm hello-world > /dev/nulldocker events --since "$t" --until "$(( $(date +%s) + 1 ))" --filter image=hello-world --format '{{.Action}}'createattachstartdiedestroydaemon برای هر کار یک رویداد میفرستد: ساخت (create)، اتصال (attach)، شروع (start)، پایان (die) و پاک شدن (destroy). دستور docker events همین جریان را نشان میدهد؛ ابزارهای مانیتورینگ هم از همین استفاده میکنند.
پشت پرده: چرا چند لایه؟
Section titled “پشت پرده: چرا چند لایه؟”چرا CLI و daemon جدا هستند؟
Section titled “چرا CLI و daemon جدا هستند؟”جدا بودنشان یک تصمیم طراحی است: CLI سبک است و daemon همیشه روشن میماند و وضعیت (image ها، کانتینرها، شبکهها) را نگه میدارد. اگر terminal را ببندی، کانتینرها همچنان کار میکنند چون daemon آنها را نگه داشته است.
dockerd، containerd و runc
Section titled “dockerd، containerd و runc”| جزء | وظیفه | تشبیه |
|---|---|---|
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
Section titled “Docker Desktop”روی مک و ویندوز، Docker Desktop یک VM لینوکسی کوچک میسازد و dockerd را داخل آن اجرا میکند؛ CLI روی سیستم اصلی تو است و با سوکتی که Docker Desktop در اختیارش گذاشته حرف میزند (همان context بالا). روی لینوکس این VM وجود ندارد و daemon مستقیم روی خود سیستم اجرا میشود.
جدولهای مرجع
Section titled “جدولهای مرجع”| دستور | چه چیزی را نشان میدهد؟ |
|---|---|
docker version |
نسخهی Client و Server و اجزای داخلی (containerd، runc) |
docker info |
وضعیت کلی daemon: تعداد کانتینر و image، storage driver، runtime، کرنل |
docker context ls |
فهرست daemon هایی که CLI میتواند به آنها وصل شود |
docker events |
جریان زندهی رویدادهای daemon |
DOCKER_HOST=... |
متغیر محیطی که آدرس daemon را برای یک دستور عوض میکند |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) «به daemon وصل نمیشود»
Section titled “۱) «به daemon وصل نمیشود»”DOCKER_HOST=tcp://127.0.0.1:9999 docker psCannot 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 با فرمت اشتباه”docker -H foo://bar psFailed to initialize: unable to resolve docker endpoint: invalid bind address format: foo://barآدرس باید با unix:// یا tcp:// یا ssh:// شروع شود. راهحل: فرمت صحیح را بنویس.
۳) فکر کردن «CLI = داکر»
Section titled “۳) فکر کردن «CLI = داکر»”نصب فقط CLI (بدون daemon) کافی نیست. اگر docker version فقط بخش Client را نشان میدهد و Server خطا دارد، daemon وجود ندارد یا روشن نیست.
فقط نسخهی Server (daemon) را با --format چاپ کن.
دیدن جواب
docker version --format 'Server: {{.Server.Version}}'Server: 29.8.1بدون استفاده از docker، فقط با curl و سوکت، بفهم daemon زنده است و Os و Arch آن چیست.
دیدن جواب
SOCK=$(docker context inspect --format '{{.Endpoints.docker.Host}}' | sed 's#unix://##')curl -s --unix-socket "$SOCK" http://localhost/_ping; echocurl -s --unix-socket "$SOCK" http://localhost/version | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d["Os"], d["Arch"])'OKlinux arm64ثابت کن docker ps -q و API (/containers/json) تعداد کانتینرهای در حال اجرا را یکسان میگویند. هر دو عدد را چاپ کن.
دیدن جواب
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: 8API: 8هر دو عدد برابرند، چون docker ps همان درخواست GET /containers/json است.
آزمونک
Section titled “آزمونک”CLI و daemon چه رابطهای دارند؟
docker یک کلاینت است و کار اصلی را dockerd انجام میدهد.
کدام جزء کانتینر را با namespace و cgroup واقعاً میسازد؟
runc ابزار سطح پایین OCI است که کانتینر را روی هسته میسازد.
ستاره در docker context ls یعنی چه؟
ستاره context فعالی را نشان میدهد که CLI از آن استفاده میکند.
اگر terminal را ببندی، کانتینرهای در حال اجرا چه میشوند؟
کانتینرها زیر نظر daemon هستند، نه ترمینال.
پیام «Cannot connect to the Docker daemon» یعنی چه؟
اول مطمئن شو داکر روشن است و DOCKER_HOST درست است.
جمعبندی
Section titled “جمعبندی”dockerCLI فقط یک کلاینت است؛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 ls | daemon های قابل اتصال |
docker context inspect | جزئیات یک context (آدرس سوکت) |
docker events | جریان رویدادهای daemon |
curl --unix-socket SOCK http://localhost/_ping | تست مستقیم API |
DOCKER_HOST=tcp://host:port docker ps | اجرای یک دستور روی daemon دیگر |