توی این درس یاد میگیری برای شروع داکر دقیقاً چه چیزهایی از لینوکس لازم داری و چه چیزهایی لازم نیست. با پنج دستور اصلی (ls -la، cd، sudo، ps aux و ss -tulpn) از چهار جنبهی ترمینال، فایلها و مسیرها، دسترسیها، و پروسهها و پورتها آشنا میشوی. در آخر هم یک چکلیست خودارزیابی داری که میفهمی آمادهی ادامهای یا نه.
چرا داکر به لینوکس نیاز دارد؟
Section titled “چرا داکر به لینوکس نیاز دارد؟”داکر روی لینوکس ساخته شده؛ کانتینرها از ویژگیهای هستهی لینوکس استفاده میکنند. داخل هر کانتینر هم تقریباً همیشه یک لینوکس کوچک است (Ubuntu، Debian یا Alpine). پس وقتی با داکر کار میکنی:
- برای دیدن داخل یک کانتینر، دستور لینوکس میزنی.
- در Dockerfile و فایلهای Compose مسیر فایلها و دسترسیها را لینوکسی مینویسی.
- خطاهای رایج داکر (مثل
Permission deniedیاport is already allocated) در واقع خطاهای لینوکس هستند.
بخش مهمی از «ترسناک بودن داکر» در واقع همین ناآشنایی با لینوکس است.
نقشهی مهارتها
Section titled “نقشهی مهارتها”| مهارت لینوکس | دستورهای اصلی این درس | کجای داکر لازم میشود؟ |
|---|---|---|
| ترمینال و 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: مثل ویندوز). پوشههای اصلی هر کدام کاری دارند، و چند مسیر داکری را در نمودار علامت زدهام:
دربارهی هر پوشه در درس ساختار پوشههای لینوکس بیشتر میگوییم.
مثالهای عملی
Section titled “مثالهای عملی”همهی دستورها را روی یک Ubuntu 24.04 واقعی اجرا کردهام. نام کاربری در مثالها ali است؛ برای تو نام خودت میآید. تاریخها و شمارهی پروسهها فرق میکنند.
مثال ۱: من کیستم و کجا هستم؟
Section titled “مثال ۱: من کیستم و کجا هستم؟”whoamihostnamepwdhead -2 /etc/os-releasealipc/home/aliPRETTY_NAME="Ubuntu 24.04.5 LTS"NAME="Ubuntu"whoami: کاربر فعلی.hostname: اسم کامپیوتر (داخل کانتینر داکر، این اسم شناسهی کانتینر است).pwd: پوشهای که الان در آن هستی. ترمینال همیشه از پوشهی home شروع میشود (~)./etc/os-release: اطلاعات توزیع. داخل کانتینرها هم همین فایل را میخوانی تا بفهمی image چه سیستمی دارد.
برای جزئیات: ترمینال و shell.
مثال ۲: ساختن پوشه و حرکت بین پوشهها
Section titled “مثال ۲: ساختن پوشه و حرکت بین پوشهها”دستورهای این مثال: mkdir، cd و ls -la.
mkdir -p ~/projects/shop/{src,config}cd ~/projects/shoptouch src/app.py config/app.env .gitignorels -latotal 16drwxr-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 .gitignoredrwxr-xr-x 2 ali ali 4096 Oct 3 08:08 configdrwxr-xr-x 2 ali ali 4096 Oct 3 08:08 srcmkdir -p همهی پوشههای بین راه را میسازد، و {src,config} یعنی «هم src و هم config». دستور ls -la دو گزینه دارد: -l (فهرست بلند با دسترسی و اندازه) و -a (همهی فایلها، حتی مخفیها). فایل .gitignore با نقطه شروع میشود، پس بدون -a دیده نمیشود. دو ردیف اول (. و ..) خود پوشه و پوشهی بالاتر هستند.
حرکت بین پوشهها:
cd srcpwdcd ..pwdcd ~pwdcd -/home/ali/projects/shop/src/home/ali/projects/shop/home/ali/home/ali/projects/shopcd .. یک پوشه بالا، cd ~ به home، و cd - به پوشهی قبلی (و مسیرش را هم چاپ میکند). برای جزئیات: حرکت بین پوشهها.
مثال ۳: دسترسیها، چرا اسکریپت اجرا نمیشود؟
Section titled “مثال ۳: دسترسیها، چرا اسکریپت اجرا نمیشود؟”printf '#!/bin/bash\necho "deploy ok"\n' > deploy.shls -l deploy.sh./deploy.sh-rw-r--r-- 1 ali ali 29 Oct 3 08:08 deploy.shbash: ./deploy.sh: Permission deniedفایل ساخته شد ولی در دسترسیهایش هیچ x ای نیست. اجرای آن را فعال میکنیم:
chmod +x deploy.shls -l deploy.sh./deploy.sh-rwxr-xr-x 1 ali ali 29 Oct 3 08:08 deploy.shdeploy okو برای فایل محرمانه، مثلاً فایل تنظیمات:
chmod 600 config/app.envls -l config/app.env-rw------- 1 ali ali 0 Oct 3 08:08 config/app.envبرای جزئیات: دسترسیها.
دستور ./deploy.sh خطای Permission denied میدهد ولی فایل وجود دارد. اول چه چیزی را بررسی میکنی؟
اگر x نیست، با chmod +x فایل را اجرایی کن.
مثال ۴: sudo، وقتی دسترسی مدیر لازم است
Section titled “مثال ۴: sudo، وقتی دسترسی مدیر لازم است”whoamisudo whoamialirootsudo یک دستور را با اختیارات مدیر (root) اجرا میکند. (روی سیستم تو اولین بار رمز خودت را میپرسد: [sudo] password for ali:. موقع تایپ چیزی دیده نمیشود، و این عادی است.) جایی که لازم میشود، پوشههای سیستمی است:
touch /etc/lx-demo.txtsudo touch /etc/lx-demo.txtls -l /etc/lx-demo.txtsudo rm /etc/lx-demo.txttouch: 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.
مثال ۵: پروسهها
Section titled “مثال ۵: پروسهها”دستورهای این مثال: ps aux و kill. هر برنامهی در حال اجرا یک پروسه است و یک شمارهی PID دارد. یک پروسهی تمرینی در پسزمینه بساز (& آخر دستور آن را در پسزمینه میگذارد):
sleep 600 &ps aux | grep "[s]leep 600"[1] 2864ali 2864 0.0 0.0 2280 1284 ? S 08:08 0:00 sleep 600ps aux همهی پروسهها را نشان میدهد. ستونهای مهمش: کاربر (ali)، شمارهی PID (2864)، و دستور (sleep 600). حالا ببندیمش:
kill 2864ps aux | grep "[s]leep 600"دستور دوم دیگر چیزی چاپ نمیکند، یعنی پروسه بسته شد. (عدد 2864 را با PID خودت عوض کن.) یادت باشد: هر کانتینر داکر در واقع یک پروسه است. برای جزئیات: پروسهها.
مثال ۶: پورتها
Section titled “مثال ۶: پورتها”دستور اصلی این مثال: ss -tulpn. یک وبسرور ساده با Python روی پورت ۸۰۰۰ در پسزمینه بالا بیاور و ببین چه کسی کدام پورت را گرفته:
python3 -m http.server 8000 > /dev/null 2>&1 &ss -tulpnNetid State Recv-Q Send-Q Local Address:Port Peer Address:Port Processtcp 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 (عدد بهجای اسم). تست اینکه واقعاً جواب میدهد:
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8000HTTP 200بعد از تمرین، پروسه را ببند: pkill -f http.server. برای جزئیات: پورتها و سرویسهای شبکه.
در خروجی ss -tulpn ستون Process چه چیزی را نشان میدهد؟
گزینهی -p اسم پروسه و PID را اضافه میکند.
پشت پرده: لینوکس چطور فکر میکند؟
Section titled “پشت پرده: لینوکس چطور فکر میکند؟”همهچیز فایل است
Section titled “همهچیز فایل است”یکی از ایدههای بنیادی یونیکس: فایلها، دستگاهها و حتی پروسهها همه مثل فایل دیده میشوند. پوشهی /proc پر از «فایلهای مجازی» است که حالت زندهی پروسهها را نشان میدهند، و اسم هر زیرپوشهاش شمارهی PID یک پروسه است:
cat /proc/$$/commreadlink /proc/$$/cwdls -l /proc/$$/exebash/home/ali/projects/shoplrwxrwxrwx 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 میتوانی همین را ببینی:
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 “جدولهای مرجع”گزینههای مهم دستورهای این درس
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 |
اجرایی کردن، حالتهای عددی |
جدول دسترسیهای عددی
Section titled “جدول دسترسیهای عددی”| عدد | نماد | یعنی |
|---|---|---|
7 |
rwx |
خواندن، نوشتن، اجرا |
6 |
rw- |
خواندن و نوشتن |
5 |
r-x |
خواندن و اجرا |
4 |
r-- |
فقط خواندن |
0 |
--- |
هیچ |
سه رقم برای: مالک، گروه، بقیه. مثلاً 755 برای اسکریپتها و 600 برای فایلهای محرمانه.
اشتباهات رایج
Section titled “اشتباهات رایج”۱) «مسیر پیدا نشد»
Section titled “۱) «مسیر پیدا نشد»”cd /nopebash: cd: /nope: No such file or directoryمسیر وجود ندارد یا غلط تایپ شده. راهحل: با pwd ببین کجایی، با ls ببین چه چیزی آنجاست، و برای تایپ از Tab استفاده کن.
۲) «دستور پیدا نشد»
Section titled “۲) «دستور پیدا نشد»”lssbash: lss: command not foundغلط تایپی یا برنامه نصب نیست. راهحل: املا را بررسی کن؛ برای برنامهای که نصب نیست، باید نصبش کنی (درسهای بعد).
۳) «اجازه نداری» برای اجرا
Section titled “۳) «اجازه نداری» برای اجرا”echo hi > noexec.sh./noexec.shbash: ./noexec.sh: Permission deniedفایل بیت اجرا ندارد. راهحل: chmod +x noexec.sh (یا bash noexec.sh برای اجرای یکباره). بهجای chmod 777 همان دسترسی لازم را بده.
۴) «باید root باشی»
Section titled “۴) «باید root باشی»”apt-get install -y treeE: 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 کامل میبینی.)
۵) «پورت اشغال است»
Section titled “۵) «پورت اشغال است»”با سروری که هنوز روی ۸۰۰۰ روشن است، یک سرور دیگر روی همان پورت:
python3 -m http.server 8000OSError: [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 دیده نمیشود.
دیدن جواب
mkdir -p ~/lab/docker-prereq && cd ~/lab/docker-prereqtouch a.txt b.txt .hiddenls -lalstotal 8drwxr-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.txta.txtb.txtls -la فایل مخفی را نشان داد و ls بهتنهایی نه.
یک اسکریپت job.sh بنویس که secret job را چاپ کند. طوری دسترسی بده که فقط خودت بتوانی آن را بخوانی، بنویسی و اجرا کنی. با ls -l ثابت کن و اجرایش کن.
دیدن جواب
printf '#!/bin/bash\necho secret job\n' > job.shchmod 700 job.shls -l job.sh./job.sh-rwx------ 1 ali ali 28 Oct 3 08:08 job.shsecret job700 یعنی مالک rwx (۷) و گروه و بقیه هیچ (۰).
یک وبسرور Python روی پورت 9000 در پسزمینه بالا بیاور. با ss -tulpn ثابت کن این پورت گرفته شده و PID سرور را از خروجی همان دستور (نه حدسی) بیرون بکش. با همان PID سرور را ببند و ثابت کن پورت آزاد شد.
دیدن جواب
python3 -m http.server 9000 > /dev/null 2>&1 &ss -tulpn | grep 9000pid=$(ss -tulpn | grep ':9000' | sed -E 's/.*pid=([0-9]+).*/\1/')kill "$pid"ss -tulpn | grep -c 9000tcp LISTEN 0 5 0.0.0.0:9000 0.0.0.0:* users:(("python3",pid=2912,fd=3))0sed عدد بعد از pid= را از خط بیرون میکشد. بعد از kill، شمارندهی آخر 0 است یعنی دیگر کسی روی ۹۰۰۰ گوش نمیدهد. (PID تو عدد دیگری است.)
چکلیست پیشنیاز: آمادهای؟
Section titled “چکلیست پیشنیاز: آمادهای؟”هر مورد را فقط وقتی تیک بزن که بدون نگاه کردن به درس بتوانی انجامش بدهی. تیکها در همین مرورگر ذخیره میشوند.
آزمونک
Section titled “آزمونک”دستور «ls -la» چه چیزی بیشتر از «ls» نشان میدهد؟
-l فهرست بلند میدهد و -a فایلهای مخفی (که با نقطه شروع میشوند) را هم نشان میدهد.
اسکریپتی را اجرا میکنی و «Permission denied» میگیرد، ولی فایل وجود دارد. محتملترین علت چیست؟
ls -l را بزن؛ اگر x نیست، با chmod +x آن را اجرایی کن.
در «chmod 640 file» گروه چه دسترسیای دارد؟
6 = rw- برای مالک، 4 = r-- برای گروه و 0 = --- برای بقیه. پس گروه فقط میخواند.
چرا کانتینر داکر را «یک پروسه» میگوییم؟
کانتینر یک (یا چند) پروسهی معمولی روی هستهی لینوکس است که با namespace و cgroup جدا شده است.
خطای «Address already in use» یعنی چه؟
هر پورت را فقط یک برنامه میتواند بگیرد. با ss -tulpn پیدا کن چه کسی آن را دارد.
جمعبندی
Section titled “جمعبندی”- داکر روی لینوکس است و خطاهای رایجش در اصل خطاهای لینوکساند؛ پس پایهی لینوکس لازم است.
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) روی سیستم راه میاندازیم.