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

مرور سریع لینوکس برای داکر

توی این درس یاد می‌گیری برای شروع داکر دقیقاً چه چیزهایی از لینوکس لازم داری و چه چیزهایی لازم نیست. با پنج دستور اصلی (ls -la، cd، sudo، ps aux و ss -tulpn) از چهار جنبه‌ی ترمینال، فایل‌ها و مسیرها، دسترسی‌ها، و پروسه‌ها و پورت‌ها آشنا می‌شوی. در آخر هم یک چک‌لیست خودارزیابی داری که می‌فهمی آماده‌ی ادامه‌ای یا نه.

چرا داکر به لینوکس نیاز دارد؟

Section titled “چرا داکر به لینوکس نیاز دارد؟”

داکر روی لینوکس ساخته شده؛ کانتینرها از ویژگی‌های هسته‌ی لینوکس استفاده می‌کنند. داخل هر کانتینر هم تقریباً همیشه یک لینوکس کوچک است (Ubuntu، Debian یا Alpine). پس وقتی با داکر کار می‌کنی:

  • برای دیدن داخل یک کانتینر، دستور لینوکس می‌زنی.
  • در Dockerfile و فایل‌های Compose مسیر فایل‌ها و دسترسی‌ها را لینوکسی می‌نویسی.
  • خطاهای رایج داکر (مثل Permission denied یا port is already allocated) در واقع خطاهای لینوکس هستند.

بخش مهمی از «ترسناک بودن داکر» در واقع همین ناآشنایی با لینوکس است.

مهارت لینوکس دستورهای اصلی این درس کجای داکر لازم می‌شود؟
ترمینال و shell whoami، pwd همه‌جا؛ هر دستور داکر در ترمینال زده می‌شود
فایل‌ها و مسیرها cd، ls -la COPY در Dockerfile، volume و bind mount
دسترسی‌ها و sudo chmod، sudo خطای Permission denied، گروه docker، کاربر داخل کانتینر
پروسه‌ها ps aux، kill کانتینر یک پروسه است؛ docker top، docker stop
پورت‌ها ss -tulpn -p 8080:80 و خطای «پورت اشغال است»

ساختار پوشه‌ها (برای دانستن جای چیزها)

Section titled “ساختار پوشه‌ها (برای دانستن جای چیزها)”

در لینوکس همه‌چیز زیر یک ریشه‌ی واحد به اسم / است (نه درایو C: و D: مثل ویندوز). پوشه‌های اصلی هر کدام کاری دارند، و چند مسیر داکری را در نمودار علامت زده‌ام:

درخت پوشه‌های لینوکس. جاهای مربوط به داکر: سوکت daemon در /var/run، داده‌ها در /var/lib/docker و تنظیمات در /etc/docker.

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

همه‌ی دستورها را روی یک Ubuntu 24.04 واقعی اجرا کرده‌ام. نام کاربری در مثال‌ها ali است؛ برای تو نام خودت می‌آید. تاریخ‌ها و شماره‌ی پروسه‌ها فرق می‌کنند.

مثال ۱: من کیستم و کجا هستم؟

Section titled “مثال ۱: من کیستم و کجا هستم؟”
Terminal window
whoami
hostname
pwd
head -2 /etc/os-release
خروجی
ali
pc
/home/ali
PRETTY_NAME="Ubuntu 24.04.5 LTS"
NAME="Ubuntu"
  • whoami: کاربر فعلی.
  • hostname: اسم کامپیوتر (داخل کانتینر داکر، این اسم شناسه‌ی کانتینر است).
  • pwd: پوشه‌ای که الان در آن هستی. ترمینال همیشه از پوشه‌ی home شروع می‌شود (~).
  • /etc/os-release: اطلاعات توزیع. داخل کانتینرها هم همین فایل را می‌خوانی تا بفهمی image چه سیستمی دارد.

برای جزئیات: ترمینال و shell.

مثال ۲: ساختن پوشه و حرکت بین پوشه‌ها

Section titled “مثال ۲: ساختن پوشه و حرکت بین پوشه‌ها”

دستورهای این مثال: mkdir، cd و ls -la.

Terminal window
mkdir -p ~/projects/shop/{src,config}
cd ~/projects/shop
touch src/app.py config/app.env .gitignore
ls -la
خروجی
total 16
drwxr-xr-x 4 ali ali 4096 Oct 3 08:08 .
drwxr-xr-x 3 ali ali 4096 Oct 3 08:08 ..
-rw-r--r-- 1 ali ali 0 Oct 3 08:08 .gitignore
drwxr-xr-x 2 ali ali 4096 Oct 3 08:08 config
drwxr-xr-x 2 ali ali 4096 Oct 3 08:08 src

mkdir -p همه‌ی پوشه‌های بین راه را می‌سازد، و {src,config} یعنی «هم src و هم config». دستور ls -la دو گزینه دارد: -l (فهرست بلند با دسترسی و اندازه) و -a (همه‌ی فایل‌ها، حتی مخفی‌ها). فایل .gitignore با نقطه شروع می‌شود، پس بدون -a دیده نمی‌شود. دو ردیف اول (. و ..) خود پوشه و پوشه‌ی بالاتر هستند.

حرکت بین پوشه‌ها:

Terminal window
cd src
pwd
cd ..
pwd
cd ~
pwd
cd -
خروجی
/home/ali/projects/shop/src
/home/ali/projects/shop
/home/ali
/home/ali/projects/shop

cd .. یک پوشه بالا، cd ~ به home، و cd - به پوشه‌ی قبلی (و مسیرش را هم چاپ می‌کند). برای جزئیات: حرکت بین پوشه‌ها.

مثال ۳: دسترسی‌ها، چرا اسکریپت اجرا نمی‌شود؟

Section titled “مثال ۳: دسترسی‌ها، چرا اسکریپت اجرا نمی‌شود؟”
Terminal window
printf '#!/bin/bash\necho "deploy ok"\n' > deploy.sh
ls -l deploy.sh
./deploy.sh
خروجی
-rw-r--r-- 1 ali ali 29 Oct 3 08:08 deploy.sh
bash: ./deploy.sh: Permission denied

فایل ساخته شد ولی در دسترسی‌هایش هیچ x ای نیست. اجرای آن را فعال می‌کنیم:

Terminal window
chmod +x deploy.sh
ls -l deploy.sh
./deploy.sh
خروجی
-rwxr-xr-x 1 ali ali 29 Oct 3 08:08 deploy.sh
deploy ok

و برای فایل محرمانه، مثلاً فایل تنظیمات:

Terminal window
chmod 600 config/app.env
ls -l config/app.env
خروجی
-rw------- 1 ali ali 0 Oct 3 08:08 config/app.env
کالبدشکافی دسترسی‌ها: نوع فایل، سه گروه rwx (مالک، گروه، بقیه) و مجموع عددی هر کدام.

برای جزئیات: دسترسی‌ها.

⚡ بررسی سریع

دستور ./deploy.sh خطای Permission denied می‌دهد ولی فایل وجود دارد. اول چه چیزی را بررسی می‌کنی؟

مثال ۴: sudo، وقتی دسترسی مدیر لازم است

Section titled “مثال ۴: sudo، وقتی دسترسی مدیر لازم است”
Terminal window
whoami
sudo whoami
خروجی
ali
root

sudo یک دستور را با اختیارات مدیر (root) اجرا می‌کند. (روی سیستم تو اولین بار رمز خودت را می‌پرسد: [sudo] password for ali:. موقع تایپ چیزی دیده نمی‌شود، و این عادی است.) جایی که لازم می‌شود، پوشه‌های سیستمی است:

Terminal window
touch /etc/lx-demo.txt
sudo touch /etc/lx-demo.txt
ls -l /etc/lx-demo.txt
sudo rm /etc/lx-demo.txt
خروجی
touch: cannot touch '/etc/lx-demo.txt': Permission denied
-rw-r--r-- 1 root root 0 Oct 3 08:08 /etc/lx-demo.txt

بدون sudo رد شد؛ با sudo ساخته شد و مالکش root است. (آخرین دستور هم آن را پاک کرد.) داکر هم همین‌طور است: روی لینوکس باید یا sudo docker ... بزنی یا کاربرت را به گروه docker اضافه کنی، که در درس نصب داکر می‌گوییم. برای جزئیات: root و sudo.

دستورهای این مثال: ps aux و kill. هر برنامه‌ی در حال اجرا یک پروسه است و یک شماره‌ی PID دارد. یک پروسه‌ی تمرینی در پس‌زمینه بساز (& آخر دستور آن را در پس‌زمینه می‌گذارد):

Terminal window
sleep 600 &
ps aux | grep "[s]leep 600"
خروجی
[1] 2864
ali 2864 0.0 0.0 2280 1284 ? S 08:08 0:00 sleep 600

ps aux همه‌ی پروسه‌ها را نشان می‌دهد. ستون‌های مهمش: کاربر (ali)، شماره‌ی PID (2864)، و دستور (sleep 600). حالا ببندیمش:

Terminal window
kill 2864
ps aux | grep "[s]leep 600"

دستور دوم دیگر چیزی چاپ نمی‌کند، یعنی پروسه بسته شد. (عدد 2864 را با PID خودت عوض کن.) یادت باشد: هر کانتینر داکر در واقع یک پروسه است. برای جزئیات: پروسه‌ها.

دستور اصلی این مثال: ss -tulpn. یک وب‌سرور ساده با Python روی پورت ۸۰۰۰ در پس‌زمینه بالا بیاور و ببین چه کسی کدام پورت را گرفته:

Terminal window
python3 -m http.server 8000 > /dev/null 2>&1 &
ss -tulpn
خروجی
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 5 0.0.0.0:8000 0.0.0.0:* users:(("python3",pid=2875,fd=3))

ستون Local Address:Port یعنی روی 0.0.0.0 (همه‌ی آدرس‌ها) و پورت 8000 منتظر مشتری است، و ستون Process نشان می‌دهد برنامه python3 با PID مشخص است. گزینه‌های -tulpn: -t (TCP)، -u (UDP)، -l (فقط listen)، -p (اسم پروسه)، -n (عدد به‌جای اسم). تست اینکه واقعاً جواب می‌دهد:

Terminal window
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8000
خروجی
HTTP 200

بعد از تمرین، پروسه را ببند: pkill -f http.server. برای جزئیات: پورت‌ها و سرویس‌های شبکه.

⚡ بررسی سریع

در خروجی ss -tulpn ستون Process چه چیزی را نشان می‌دهد؟

پشت پرده: لینوکس چطور فکر می‌کند؟

Section titled “پشت پرده: لینوکس چطور فکر می‌کند؟”

یکی از ایده‌های بنیادی یونیکس: فایل‌ها، دستگاه‌ها و حتی پروسه‌ها همه مثل فایل دیده می‌شوند. پوشه‌ی /proc پر از «فایل‌های مجازی» است که حالت زنده‌ی پروسه‌ها را نشان می‌دهند، و اسم هر زیرپوشه‌اش شماره‌ی PID یک پروسه است:

Terminal window
cat /proc/$$/comm
readlink /proc/$$/cwd
ls -l /proc/$$/exe
خروجی
bash
/home/ali/projects/shop
lrwxrwxrwx 1 ali ali 0 Oct 3 08:08 /proc/2829/exe -> /usr/bin/bash

$$ شماره‌ی پروسه‌ی shell فعلی است. دیدی که لینوکس بدون هیچ ابزار ویژه‌ای می‌گوید این پروسه کدام برنامه است (bash) و در کدام پوشه‌ای کار می‌کند. همین‌طور docker top و docker stats هم اطلاعاتشان را از همین ساز و کار می‌گیرند.

دسترسی‌ها فقط چند بیت کنار هر فایل‌اند

Section titled “دسترسی‌ها فقط چند بیت کنار هر فایل‌اند”

لینوکس برای هر فایل یک مالک (user)، یک گروه و ۹ بیت دسترسی ذخیره می‌کند. نام‌ها در حقیقت به شماره تبدیل می‌شوند (UID و GID). با stat می‌توانی همین را ببینی:

Terminal window
stat -c '%A %a %U %G %n' deploy.sh
خروجی
-rwxr-xr-x 755 ali ali deploy.sh

همان rwxr-xr-x و عدد 755. این برای داکر مهم است: وقتی یک پوشه‌ی سیستم خودت را داخل کانتینر وصل می‌کنی، کانتینر فقط شماره‌ی کاربر را می‌بیند، نه اسم را؛ و بسیاری از خطاهای Permission denied در داکر از همین اختلاف شماره‌ها می‌آید.

پورت یعنی یک «در» که فقط یک برنامه پشتش می‌ایستد

Section titled “پورت یعنی یک «در» که فقط یک برنامه پشتش می‌ایستد”

وقتی یک برنامه روی یک پورت listen می‌کند، هسته آن شماره را به همان پروسه می‌سپارد. دومین برنامه‌ای که همان پورت (روی همان آدرس) را بخواهد، خطا می‌گیرد. در داکر -p 8080:80 یعنی «پورت ۸۰۸۰ سیستم من را به پورت ۸۰ داخل کانتینر وصل کن»؛ پس اگر پورت ۸۰۸۰ سیستم قبلاً گرفته شده باشد، همین خطا را می‌بینی.

گزینه‌های مهم دستورهای این درس

Section titled “گزینه‌های مهم دستورهای این درس”
دستور گزینه معنی
ls -l فهرست بلند (دسترسی، مالک، اندازه، زمان)
ls -a نمایش فایل‌های مخفی (با نقطه)
ls -h اندازه‌ها خوانا (KB، MB) همراه -l
cd .. ، ~ ، - پوشه‌ی بالا، پوشه‌ی home، پوشه‌ی قبلی
mkdir -p ساختن همه‌ی پوشه‌های بین راه
ps aux همه‌ی پروسه‌ها با جزئیات
kill -9 بستن اجباری (آخرین راه‌حل)
ss -tulpn پورت‌های در حال listen همراه پروسه
chmod +x ، 755 ، 600 اجرایی کردن، حالت‌های عددی
عدد نماد یعنی
7 rwx خواندن، نوشتن، اجرا
6 rw- خواندن و نوشتن
5 r-x خواندن و اجرا
4 r-- فقط خواندن
0 --- هیچ

سه رقم برای: مالک، گروه، بقیه. مثلاً 755 برای اسکریپت‌ها و 600 برای فایل‌های محرمانه.

Terminal window
cd /nope
خطا
bash: cd: /nope: No such file or directory

مسیر وجود ندارد یا غلط تایپ شده. راه‌حل: با pwd ببین کجایی، با ls ببین چه چیزی آنجاست، و برای تایپ از Tab استفاده کن.

Terminal window
lss
خطا
bash: lss: command not found

غلط تایپی یا برنامه نصب نیست. راه‌حل: املا را بررسی کن؛ برای برنامه‌ای که نصب نیست، باید نصبش کنی (درس‌های بعد).

۳) «اجازه نداری» برای اجرا

Section titled “۳) «اجازه نداری» برای اجرا”
Terminal window
echo hi > noexec.sh
./noexec.sh
خطا
bash: ./noexec.sh: Permission denied

فایل بیت اجرا ندارد. راه‌حل: chmod +x noexec.sh (یا bash noexec.sh برای اجرای یک‌باره). به‌جای chmod 777 همان دسترسی لازم را بده.

Terminal window
apt-get install -y tree
خطا
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?

نصب برنامه فقط با مدیر ممکن است. راه‌حل: sudo apt-get install -y tree. (چند دستور از جمله apt را در دوره‌ی لینوکس نصب برنامه با apt کامل می‌بینی.)

با سروری که هنوز روی ۸۰۰۰ روشن است، یک سرور دیگر روی همان پورت:

Terminal window
python3 -m http.server 8000
خطا (انتهای آن)
OSError: [Errno 98] Address already in use

پورت را یک پروسه‌ی دیگر گرفته. راه‌حل: با ss -tulpn | grep 8000 پیدا کن چه کسی است و ببندش (kill PID)، یا از پورت دیگری استفاده کن. در داکر همین خطا با متن port is already allocated برمی‌گردد.

✎ تمرینآسان

داخل پوشه‌ی home یک پوشه‌ی lab/docker-prereq با یک دستور بساز. داخلش سه فایل a.txt، b.txt و .hidden بساز. با یک دستور هم فایل مخفی را ببین و هم با دستور ساده‌تر، ثابت کن بدون -a دیده نمی‌شود.

دیدن جواب
Terminal window
mkdir -p ~/lab/docker-prereq && cd ~/lab/docker-prereq
touch a.txt b.txt .hidden
ls -la
ls
خروجی
total 8
drwxr-xr-x 2 ali ali 4096 Oct 3 08:08 .
drwxr-xr-x 3 ali ali 4096 Oct 3 08:08 ..
-rw-r--r-- 1 ali ali 0 Oct 3 08:08 .hidden
-rw-r--r-- 1 ali ali 0 Oct 3 08:08 a.txt
-rw-r--r-- 1 ali ali 0 Oct 3 08:08 b.txt
a.txt
b.txt

ls -la فایل مخفی را نشان داد و ls به‌تنهایی نه.

✎ تمرینمتوسط

یک اسکریپت job.sh بنویس که secret job را چاپ کند. طوری دسترسی بده که فقط خودت بتوانی آن را بخوانی، بنویسی و اجرا کنی. با ls -l ثابت کن و اجرایش کن.

دیدن جواب
Terminal window
printf '#!/bin/bash\necho secret job\n' > job.sh
chmod 700 job.sh
ls -l job.sh
./job.sh
خروجی
-rwx------ 1 ali ali 28 Oct 3 08:08 job.sh
secret job

700 یعنی مالک rwx (۷) و گروه و بقیه هیچ (۰).

✎ تمرینسخت

یک وب‌سرور Python روی پورت 9000 در پس‌زمینه بالا بیاور. با ss -tulpn ثابت کن این پورت گرفته شده و PID سرور را از خروجی همان دستور (نه حدسی) بیرون بکش. با همان PID سرور را ببند و ثابت کن پورت آزاد شد.

دیدن جواب
Terminal window
python3 -m http.server 9000 > /dev/null 2>&1 &
ss -tulpn | grep 9000
pid=$(ss -tulpn | grep ':9000' | sed -E 's/.*pid=([0-9]+).*/\1/')
kill "$pid"
ss -tulpn | grep -c 9000
خروجی
tcp LISTEN 0 5 0.0.0.0:9000 0.0.0.0:* users:(("python3",pid=2912,fd=3))
0

sed عدد بعد از pid= را از خط بیرون می‌کشد. بعد از kill، شمارنده‌ی آخر 0 است یعنی دیگر کسی روی ۹۰۰۰ گوش نمی‌دهد. (PID تو عدد دیگری است.)

چک‌لیست پیش‌نیاز: آماده‌ای؟

Section titled “چک‌لیست پیش‌نیاز: آماده‌ای؟”

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

✓ چک‌لیست پیش‌نیاز داکر
؟ آزمونک
  1. دستور «ls -la» چه چیزی بیشتر از «ls» نشان می‌دهد؟

  2. اسکریپتی را اجرا می‌کنی و «Permission denied» می‌گیرد، ولی فایل وجود دارد. محتمل‌ترین علت چیست؟

  3. در «chmod 640 file» گروه چه دسترسی‌ای دارد؟

  4. چرا کانتینر داکر را «یک پروسه» می‌گوییم؟

  5. خطای «Address already in use» یعنی چه؟

  • داکر روی لینوکس است و خطاهای رایجش در اصل خطاهای لینوکس‌اند؛ پس پایه‌ی لینوکس لازم است.
  • ls -la فایل‌ها (همراه مخفی‌ها و دسترسی‌ها) را نشان می‌دهد و cd (با ..، ~ و -) در پوشه‌ها حرکت می‌دهد.
  • دسترسی هر فایل: rwx برای مالک، گروه و بقیه؛ chmod +x اجرایی می‌کند و chmod 755 / 600 حالت‌های متداول‌اند.
  • sudo فقط برای کارهایی که واقعاً دسترسی مدیر لازم دارند؛ بقیه را بدون آن بزن.
  • هر برنامه‌ی در حال اجرا یک پروسه با PID است (ps aux، kill)؛ کانتینر هم یک پروسه است.
  • هر پورت را فقط یک پروسه می‌گیرد؛ ss -tulpn نشان می‌دهد کدام.
  • اگر چک‌لیست را کامل نکردی، دوره‌ی کامل لینوکس را بخوان و بعد برگرد.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
whoami · hostname · pwdکاربر، اسم کامپیوتر و پوشه‌ی فعلی
head -2 /etc/os-releaseاسم و نسخه‌ی توزیع
ls -laفهرست بلند همه‌ی فایل‌ها (با مخفی‌ها)
mkdir -p a/b/cساختن پوشه‌ها همراه مسیر بین‌راه
cd .. · cd ~ · cd -یک پوشه بالا · home · پوشه‌ی قبلی
chmod +x fileاجازه‌ی اجرا
chmod 600 fileفقط مالک می‌خواند و می‌نویسد
stat -c "%A %a %U %G %n" fileدسترسی (نمادین و عددی)، مالک و گروه
sudo commandاجرا با اختیارات مدیر
ps auxهمه‌ی پروسه‌ها
kill PIDدرخواست بستن پروسه
ss -tulpnپورت‌های listen و پروسه‌ی هر کدام
curl -s -o /dev/null -w "%{http_code}\n" URLفقط کد HTTP یک آدرس

در درس بعد برای کاربران ویندوز، یک لینوکس واقعی (WSL2) روی سیستم راه می‌اندازیم.