راهاندازی کلاستر Docker Swarm روی چند سرور مجازی و اختصاصی: نصب، Overlay Network و استقرار Stack
وقتی اجرای چند کانتینر روی یک سرور دیگر کافی نیست، باید راهی برای توزیع سرویسها میان چند ماشین، جایگزینی خودکار کانتینرهای خراب و انتشار نسخههای جدید پیدا کنیم. Docker Swarm این قابلیتها را داخل خود Docker Engine فراهم میکند و برای کلاسترهای کوچک و متوسط، پیچیدگی کمتری نسبت به Kubernetes دارد.
در این آموزش، راهاندازی Docker Swarm را روی چند سرور لینوکسی از ابتدا انجام میدهیم. ابتدا Docker را نصب میکنیم، سپس نودهای Manager و Worker را به کلاستر متصل میکنیم، پورتهای لازم و شبکه Overlay را بررسی میکنیم و در پایان یک Stack واقعی را با فایل Compose مستقر و بهروزرسانی میکنیم.

معماری Docker Swarm چگونه است؟
هر ماشین عضو کلاستر یک Node نام دارد. نودها یکی از دو نقش اصلی زیر را دارند:
- Manager: وضعیت کلاستر را نگه میدارد، درخواستهای مدیریتی را میپذیرد و وظایف سرویسها را میان نودها زمانبندی میکند.
- Worker: وظایفی را که Manager به آن اختصاص داده است اجرا میکند.
یک سرویس، تعریف مطلوب اجرای کانتینرهاست؛ برای نمونه میتوان مشخص کرد سرویس وب همیشه سه Replica داشته باشد. Swarm این وضعیت را کنترل میکند و اگر یکی از کانتینرها یا نودها از دسترس خارج شود، برای بازگرداندن تعداد Replicaها تلاش میکند.
در این راهنما از سه سرور با Ubuntu استفاده میکنیم:
- manager-1 با نشانی خصوصی 10.10.0.10
- worker-1 با نشانی خصوصی 10.10.0.11
- worker-2 با نشانی خصوصی 10.10.0.12
استفاده از IP خصوصی برای ارتباط داخلی کلاستر بهتر است؛ ترافیک مدیریتی و تبادل داده میان نودها نباید بدون نیاز از اینترنت عمومی عبور کند. فرمانها روی Ubuntu نوشته شدهاند، اما منطق کلی برای توزیعهای دیگر لینوکس نیز یکسان است.
پیشنیازها و پورتهای لازم
هر سرور باید نام میزبان یکتا، ساعت هماهنگ و ارتباط شبکه پایدار با سایر نودها داشته باشد. بهتر است پیش از شروع، نام میزبان را تنظیم کنید:
sudo hostnamectl set-hostname manager-1
این فرمان را روی هر نود با نام مناسب همان سرور اجرا کنید. سپس مطمئن شوید نودها از طریق IP خصوصی یکدیگر را میبینند:
ping -c 3 10.10.0.11
ping -c 3 10.10.0.12
Docker Swarm برای ارتباط داخلی به چند پورت مشخص نیاز دارد:
| پورت | پروتکل | کاربرد |
|---|---|---|
| 2377 | TCP | مدیریت کلاستر و اتصال نودها |
| 7946 | TCP و UDP | کشف نودها و ارتباط داخلی |
| 4789 | UDP | ترافیک شبکههای Overlay |
| پورت سرویس | TCP یا UDP | دسترسی کاربران به سرویس منتشرشده |
پورت 2377 معمولاً فقط باید میان نودهای کلاستر باز باشد. پورت UDP شماره 4789 نیز نباید بدون محدودیت در معرض اینترنت قرار گیرد. قوانین فایروال را به IP خصوصی اعضای کلاستر محدود کنید.
برای نمونه، در UFW میتوان دسترسی شبکه خصوصی را مجاز کرد:
sudo ufw allow from 10.10.0.0/24 to any port 2377 proto tcp
sudo ufw allow from 10.10.0.0/24 to any port 7946 proto tcp
sudo ufw allow from 10.10.0.0/24 to any port 7946 proto udp
sudo ufw allow from 10.10.0.0/24 to any port 4789 proto udp
اگر سرورها پشت NAT، فایروال ابری یا شبکههای متفاوت قرار دارند، مسیر رفتوبرگشت و قوانین Security Group را نیز بررسی کنید. باز بودن پورت در فایروال سیستمعامل بهتنهایی کافی نیست.
نصب Docker روی همه نودها
برای جلوگیری از تفاوت رفتاری، نسخه سازگار و ترجیحاً یکسان Docker Engine را روی تمام نودها نصب کنید. ابتدا بستههای قدیمی و متداخل را حذف کنید:
sudo apt-get remove -y docker.io docker-doc docker-compose podman-docker containerd runc
سپس مخزن رسمی Docker را اضافه کنید:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
اکنون Docker Engine و افزونه Compose را نصب کنید:
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
برای بررسی نصب، این دو فرمان را اجرا کنید:
sudo docker version
sudo docker run --rm hello-world
افزودن کاربر به گروه docker اختیاری است. عضویت در این گروه عملاً سطح دسترسی مدیریتی روی میزبان ایجاد میکند؛ بنابراین آن را فقط برای کاربران مورد اعتماد انجام دهید.
ساخت Manager و اتصال Workerها
روی manager-1، کلاستر را با IP خصوصی همان سرور ایجاد کنید:
sudo docker swarm init --advertise-addr 10.10.0.10
خروجی فرمان شامل دستور docker swarm join و یک Token برای Workerهاست. نمونه آن چنین ساختاری دارد:
sudo docker swarm join \
--token SWMTKN-1-REPLACE_WITH_REAL_TOKEN \
10.10.0.10:2377
این دستور را با Token واقعی روی worker-1 و worker-2 اجرا کنید. سپس روی Manager وضعیت اعضا را ببینید:
sudo docker node ls
هر سه نود باید در وضعیت Ready باشند و نود اول نقش Leader داشته باشد. اگر نودی متصل نمیشود، ابتدا پورت 2377/TCP، آدرس --advertise-addr و مسیر شبکه خصوصی را بررسی کنید.
Token عضویت یک داده حساس است. آن را داخل اسکریپت عمومی، مخزن Git یا فایل Compose قرار ندهید. در صورت افشا شدن Token، میتوان آن را چرخاند:
sudo docker swarm join-token --rotate worker
ایجاد شبکه Overlay
شبکه Bridge فقط کانتینرهای یک میزبان را به هم متصل میکند. برای ارتباط سرویسهایی که ممکن است روی نودهای متفاوت اجرا شوند، به شبکه Overlay نیاز داریم.
روی Manager شبکهای به نام app_net بسازید:
sudo docker network create \
--driver overlay \
--attachable \
app_net
گزینه --attachable اجازه میدهد کانتینرهای مستقلی که خارج از Stack اجرا شدهاند نیز در صورت نیاز به شبکه متصل شوند. برای اغلب Stackها ضروری نیست، اما در عیبیابی یا اجرای ابزارهای موقت مفید است.
جزئیات شبکه را بررسی کنید:
sudo docker network inspect app_net

شبکه Overlay روی VXLAN کار میکند؛ به همین دلیل ترافیک UDP پورت 4789 باید میان نودها برقرار باشد. اگر سرویسها ایجاد میشوند اما از نودهای متفاوت نمیتوانند با هم ارتباط بگیرند، این پورت و MTU شبکه از نخستین مواردی هستند که باید بررسی شوند.
استقرار Stack با فایل Compose
Docker Stack مجموعهای از سرویسها، شبکهها و تنظیمات مرتبط را از روی یک فایل YAML مستقر میکند. فایل زیر را با نام stack.yml روی Manager بسازید:
version: "3.8"
services:
web:
image: nginx:1.27-alpine
ports:
- target: 80
published: 8080
protocol: tcp
mode: ingress
networks:
- app_net
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
order: start-first
restart_policy:
condition: on-failure
placement:
constraints:
- node.platform.os == linux
api:
image: traefik/whoami:v1.10
networks:
- app_net
deploy:
replicas: 2
restart_policy:
condition: on-failure
networks:
app_net:
external: true
در حالت Swarm، بخش deploy معنا پیدا میکند. اجرای معمولی docker compose up این کلاستر را مدیریت نمیکند؛ برای استقرار باید از فرمان زیر استفاده شود:
sudo docker stack deploy -c stack.yml demo
وضعیت Stack و سرویسها را بررسی کنید:
sudo docker stack ls
sudo docker stack services demo
sudo docker service ps demo_web
نام سرویسها از ترکیب نام Stack و نام سرویس ساخته میشود. در این مثال، سرویس web با نام demo_web ثبت خواهد شد.
Swarm با Routing Mesh درخواست واردشده به پورت منتشرشده را به یکی از Taskهای فعال هدایت میکند؛ بنابراین پورت 8080 روی همه نودهای کلاستر قابل دسترسی است، حتی اگر کانتینر سرویس روی همان نود اجرا نشده باشد.
برای آزمایش:
curl http://10.10.0.10:8080
curl http://10.10.0.11:8080
curl http://10.10.0.12:8080
مدیریت Secret و دادههای پایدار
رمز پایگاه داده، کلید API و گواهی خصوصی را مستقیماً داخل فایل Compose ننویسید. Swarm برای این دادهها Secret دارد:
printf '%s' 'replace-with-a-strong-password' \
| sudo docker secret create db_password -
سپس Secret را در فایل Stack تعریف و به سرویس مورد نظر متصل کنید:
services:
app:
image: example/app:1.0
secrets:
- db_password
secrets:
db_password:
external: true
Secret داخل کانتینر معمولاً از مسیر /run/secrets/db_password خوانده میشود.
برای دادههای پایدار نیز باید محل اجرای سرویس را دقیق طراحی کنید. Volume محلی به نود وابسته است؛ اگر سرویس روی نود دیگری بازسازی شود، داده قبلی همراه آن جابهجا نمیشود. برای پایگاه داده میتوان از ذخیرهساز شبکهای سازگار، درایور Volume مناسب یا محدودیت Placement استفاده کرد. داشتن چند Replica از یک پایگاه داده بدون سازوکار تکثیر خود پایگاه داده، راهکار افزونگی محسوب نمیشود.
Rolling Update و بازگشت به نسخه قبلی
یکی از مزایای راهاندازی Docker Swarm، انتشار تدریجی نسخه جدید است. در فایل نمونه، parallelism: 1 باعث میشود هر بار فقط یک Task بهروزرسانی شود و delay: 10s میان مراحل فاصله ایجاد میکند.
برای تغییر Image سرویس:
sudo docker service update \
--image nginx:1.28-alpine \
demo_web
روند انتشار را ببینید:
sudo docker service ps demo_web
اگر نسخه جدید مشکل داشت، به تنظیم قبلی بازگردید:
sudo docker service rollback demo_web
گزینه order: start-first ابتدا Task جدید را اجرا میکند و بعد Task قدیمی را متوقف میسازد. این روش میتواند قطعی را کم کند، اما برای کارکرد درست به Health Check، ظرفیت کافی سرورها و سازگاری همزمان نسخههای قدیم و جدید نیاز دارد.
Quorum مدیرها و تحمل خرابی
Managerها برای نگهداری وضعیت کلاستر از الگوریتم اجماع Raft استفاده میکنند. برای تصمیمگیری، اکثریت Managerها باید در دسترس باشند. به این اکثریت Quorum گفته میشود.
| تعداد Manager | Quorum لازم | تحمل خرابی Manager |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 5 | 3 | 2 |
دو Manager نسبت به یک Manager تحمل خرابی بیشتری ایجاد نمیکنند؛ زیرا با خروج یکی، اکثریت از بین میرود. برای محیط عملیاتی معمولاً سه Manager انتخاب مناسبی است. تعداد فرد از Managerها نیز نسبت به تعداد زوج، استفاده بهتری از منابع دارد. برای ارتقای یک Worker به Manager:
sudo docker node promote worker-1
هر Manager را روی میزبان یا دامنه خرابی جدا قرار دهید. سه ماشین مجازی روی یک سرور فیزیکی، در برابر خرابی همان سرور محافظت ایجاد نمیکنند. از وضعیت Swarm و اطلاعات بازیابی Managerها نیز نسخه پشتیبان داشته باشید.
مقایسه Docker Swarm با Kubernetes
انتخاب میان Swarm و Kubernetes به اندازه تیم، پیچیدگی سرویسها و نیازهای عملیاتی بستگی دارد.
| معیار | Docker Swarm | Kubernetes |
|---|---|---|
| راهاندازی اولیه | سادهتر و سریعتر | پیچیدهتر |
| فایل استقرار | نزدیک به Docker Compose | Manifestها یا Helm Chart |
| شبکه داخلی | Overlay و Routing Mesh | مدل شبکه و CNI |
| اکوسیستم | محدودتر | گستردهتر |
| کنترل استقرار و زمانبندی | مناسب نیازهای متداول | گزینههای پیشرفتهتر |
| مناسب برای | کلاسترهای کوچک و تیمهای کمتعداد | سامانههای بزرگ و نیازهای پیچیده |
Swarm برای تیمی مناسب است که با Docker و Compose آشناست، تعداد سرویسهای محدودی دارد و میخواهد بدون اضافه کردن اجزای زیاد، استقرار چندمیزبانه و Rolling Update داشته باشد. Kubernetes زمانی انتخاب بهتری است که به کنترلگرهای سفارشی، سیاستهای شبکه پیشرفته، Auto Scaling گسترده یا اکوسیستم بزرگ ابزارهای ابری نیاز دارید. مهاجرت آینده را نیز در نظر بگیرید. فایل Compose میتواند تعریف سرویسها را خوانا نگه دارد، اما همه تنظیمات Swarm معادل مستقیم در Kubernetes ندارند.
پایش و عیبیابی کلاستر
برای مشاهده وضعیت کلی، از این فرمانها شروع کنید:
sudo docker node ls
sudo docker service ls
sudo docker service ps demo_web --no-trunc
sudo docker service logs --tail 100 demo_web
اگر Task مرتباً Restart میشود، خروجی docker service ps --no-trunc معمولاً خطای زمانبندی یا اجرای کانتینر را نشان میدهد. کمبود منابع، در دسترس نبودن Image، ناسازگاری معماری پردازنده و محدودیتهای Placement از علتهای متداول هستند.
برای سرویسهای مهم، Health Check تعریف کنید و مصرف CPU، حافظه، دیسک، نرخ خطا و زمان پاسخ را بیرون از Docker نیز پایش کنید. Swarm کانتینر ازکارافتاده را جایگزین میکند، اما تشخیص نمیدهد که پاسخ ظاهراً موفق یک برنامه از نظر کسبوکار درست است.
پس از پایان آزمایش، Stack را حذف کنید:
sudo docker stack rm demo
حذف Stack شبکه خارجی app_net را پاک نمیکند. اگر دیگر به آن نیاز ندارید، جداگانه حذفش کنید:
sudo docker network rm app_net
انتخاب زیرساخت برای کلاستر Swarm
برای آزمایش، سه سرور مجازی کوچک کافی است. در محیط عملیاتی باید CPU، حافظه، فضای دیسک، پهنای باند داخلی و دامنههای خرابی را بر اساس بار واقعی انتخاب کنید. سرویسهای بدون حالت را میتوان میان VPSها توزیع کرد، درحالیکه بارهای سنگین یا حساس به کارایی دیسک ممکن است روی سرور اختصاصی نتیجه قابلپیشبینیتری داشته باشند. اگر برای ساخت نودهای Manager و Worker به زیرساخت نیاز دارید، مشخصات سرور مجازی ابری آریانت را بررسی کنید. پیش از سفارش، تعداد نودها را بر اساس Quorum، ظرفیت لازم هنگام Rolling Update و میزان تحمل خرابی محاسبه کنید. راهاندازی Docker Swarm با چند فرمان انجام میشود، اما پایداری آن به طراحی شبکه، توزیع درست Managerها، مدیریت Secretها و ذخیرهسازی وابسته است. ابتدا کلاستر را با یک Stack آزمایشی بسازید، قطع یک Worker و سپس یک Manager را شبیهسازی کنید و رفتار سرویس را بسنجید. نتیجه این آزمایشها مشخص میکند که معماری انتخابشده در زمان خرابی واقعی چگونه عمل خواهد کرد.




