โหมดมืด
บทที่ 1 — Linux + Shell
TL;DR: บทนี้ตอบ "ทำไม dev ทุกคนต้องรู้ Linux + shell" — filesystem (ระบบไฟล์), permission (สิทธิ์), process (โปรเซส), redirect/pipe (เปลี่ยนทาง/ต่อท่อ output), shell script, SSH (login เข้า server ระยะไกล), systemd (ตัวจัดการ service), cron (ตัวตั้งเวลา). ข้ามได้ถ้า: ใช้ Linux ในงานจริงมาแล้ว 1+ ปีและเขียน bash script ได้ (บทนี้ออกแบบมาสำหรับมือใหม่ที่ยังไม่เคยใช้ command line)
หลังจบบท คุณจะ:
- ใช้ command line คล่อง — file, process, network
- เข้าใจ permission + ownership (rwx + ทำไม
chmod 755) - เขียน shell script พื้นฐานที่ใช้ใน production ได้
- Debug + troubleshoot server จริงเป็น
- ใช้ vim/nano เพื่อแก้ไฟล์บน server
ทุก server ใน production = Linux (เกือบ) — รู้ Linux = พื้นฐาน DevOps
0. ก่อนเริ่ม — Prerequisites + Setup
คุณควรมี:
- ✅ เครื่องที่เปิด terminal ได้ (Mac, Linux, หรือ Windows + WSL2)
- ✅ ติด Ubuntu บน WSL2 ถ้าเป็น Windows (
wsl --install) - ✅ ไม่จำเป็นต้องเคยใช้ command line มาก่อน — เริ่มจากศูนย์ได้
💡 WSL2 = Windows Subsystem for Linux 2 — ระบบของ Microsoft ที่ให้รัน Linux kernel จริงบน Windows (ผ่าน virtual machine แบบเบา) ใช้ command line ของ Linux ได้ครบ โดยไม่ต้องลง dual-boot
สำหรับ Windows: ทำตามนี้ก่อน
powershell
# PowerShell as administrator (เปิด PowerShell แบบ run as admin)
wsl --install -d Ubuntu-24.04
# restart เครื่อง → เปิด Ubuntu จาก Start menu
# หมายเหตุ: ชื่อ distro เปลี่ยนตามปี — ดู `wsl --list --online` เพื่อเลือก LTS ล่าสุด⚠️ ถ้าเจอ error "WSL feature is not enabled" ให้รันคำสั่งนี้ก่อนใน PowerShell as administrator แล้ว restart เครื่อง แล้วรัน
wsl --installใหม่:powershelldism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestartหรือดูขั้นตอนแบบมีรูปได้ที่ https://docs.microsoft.com/en-us/windows/wsl/install
WSL2 = Linux จริง ๆ ที่ run อยู่บน Windows — ทุก command ในบทนี้ใช้ได้เหมือนกับ server จริง
0.2 Lab 0 — ทำมือก่อนทฤษฎี (5 นาที)
ถ้าคุณใช้ Windows + IDE มาตลอด และยังไม่เคยใช้ shell จริงจัง — ทำตามนี้ก่อนอ่านต่อ จะเข้าใจคำว่า "ทุกอย่างคือไฟล์" และวิธี "รวม error log + output log เข้าด้วยกัน" (ที่ shell เขียนสั้น ๆ ว่า 2>&1) ในข้อถัดไปง่ายขึ้นมาก
เปิด WSL2 Ubuntu (Windows) / Terminal (Mac/Linux) แล้วลอง:
bash
# 1. สร้างไฟล์ทดสอบ
echo "hello world" > test.txt
# 2. อ่านไฟล์ทดสอบ
cat test.txt
# → hello world
# 3. ลอง command ที่ "สำเร็จ" และ "ล้มเหลว"
ls test.txt # สำเร็จ — แสดง test.txt
ls notexist.txt # ล้มเหลว — ขึ้น "No such file or directory"
# 4. แยก output 2 ทาง: ปกติ (stdout) + error (stderr)
ls test.txt notexist.txt > out.txt 2> err.txt
# stdout (1) ไปไฟล์ out.txt
# stderr (2) ไปไฟล์ err.txt
cat out.txt # → test.txt (อันที่สำเร็จ)
cat err.txt # → ls: cannot access 'notexist.txt': No such file or directory
# 5. รวมทั้ง 2 ไปไฟล์เดียว
ls test.txt notexist.txt > all.txt 2>&1
cat all.txt # → ทั้ง 2 บรรทัดอยู่ในไฟล์เดียวกัน
# 6. เก็บกวาด
rm test.txt out.txt err.txt all.txtตอนนี้คุณ "เห็น" แล้วว่า:
>เปลี่ยน "ทางออก" ของ output ปกติไปยังไฟล์ (ไม่ขึ้นบนจอ)2>เปลี่ยน "ทางออก" ของ error ไปยังไฟล์2>&1= "ส่ง error ไปที่เดียวกับ output ปกติ"- เลข 1 และ 2 คือ "หมายเลขทางออก" — ศัพท์ทางการเรียกว่า "file descriptor" (fd) คือเลขประจำตัวที่ระบบใช้อ้างถึงไฟล์/ช่องทาง I/O ที่เปิดอยู่ (รายละเอียดในข้อ 0.5)
→ ทฤษฎีในข้อ 0.3 ข้างล่างจะเข้าใจง่ายขึ้นเพราะคุณเจอ pattern นี้แล้ว
0.3 Mental Model — "ทุกอย่างคือไฟล์"
ก่อนจำ command, ฝัง concept นี้ในหัว — มันเป็น ปรัชญาหลักของ Unix/Linux:
text
ใน Linux:
- ไฟล์ปกติ → ไฟล์
- โฟลเดอร์ (directory) → ไฟล์ (ที่ list ไฟล์ข้างใน)
- harddisk (ดิสก์เก็บข้อมูล) → ไฟล์ (/dev/sda)
- keyboard/mouse → ไฟล์ (/dev/input/...)
- process ที่กำลังรันอยู่ → ไฟล์ (/proc/1234/)
- network socket → file descriptor
- pipe ระหว่าง process → ไฟล์💡 คำศัพท์พื้นฐานของ Linux — เจอบ่อยตลอดบท:
- file descriptor (fd) = เลขที่ระบบใช้อ้างไฟล์/socket ที่เปิดอยู่ (เช่น fd 0=stdin, 1=stdout, 2=stderr) — คล้าย "หมายเลขล็อกเกอร์" สำหรับช่อง I/O ที่เปิดอยู่
- PID (Process ID) = เลขประจำตัวของ process ที่รันอยู่ (เช่น
kill 1234คือสั่งหยุด process หมายเลข 1234)- UID / GID (User ID / Group ID) = เลขประจำตัวของ user / group (root = UID 0)
- mode bits = bit ที่เก็บสิทธิ์ของไฟล์ (rwx — อ่าน/เขียน/รัน) เห็นในข้อ Permission
ทำไมสำคัญ: ถ้าทุกอย่างคือไฟล์ → ใช้ command เดียวกัน (cat, >, <) จัดการทุกอย่างได้
bash
# echo "hello" > /dev/tty1 # เขียนไปที่ terminal หมายเลข 1 (ต้องเป็น root + มี console จริง)
cat /proc/cpuinfo # อ่านข้อมูล CPU เหมือนอ่านไฟล์
cat /proc/meminfo # อ่านข้อมูลหน่วยความจำ (RAM)→ Linux ไม่มี "API พิเศษ" สำหรับ device — ใช้ file API กับทุกอย่าง
1. ทำไมต้อง Linux
- 99% server ใน cloud = Linux
- Docker container base = Linux
- Kubernetes node = Linux
- SSH เข้า server = ใช้ shell ของ Linux
→ ไม่รู้ Linux = ทำ DevOps ไม่ได้
2. Linux Distribution
text
Linux Kernel
├── Debian-based
│ ├── Ubuntu (popular, friendly)
│ └── Debian (stable, lean)
├── Red Hat-based
│ ├── RHEL (enterprise, paid)
│ ├── CentOS Stream (free)
│ ├── Rocky Linux (RHEL-compatible, free)
│ └── Fedora (cutting edge)
└── Alpine (ใช้ libc เล็กชื่อ musl, minimal, นิยมเป็น base ของ Docker image)💡 musl (อ่าน "มัสเซิล") = ไลบรารี C พื้นฐาน (libc) เวอร์ชันเล็ก/เบา ที่ Alpine ใช้แทนตัวมาตรฐาน (glibc — GNU C Library, libc ที่ distro ส่วนใหญ่ใช้) — ทำให้ image เล็กมาก เหมาะกับ Docker แต่บางโปรแกรมที่ผูกกับ glibc อาจมีปัญหา
มือใหม่ — เริ่มด้วย Ubuntu 24.04 LTS (Noble Numbat — Ubuntu ตั้งชื่อรุ่นเป็นคู่คำคล้องจอง+ชื่อสัตว์ เรียงตามตัวอักษร ไม่ต้องจำก็ได้ ใช้เลขเวอร์ชัน 24.04 พอ, release เมษา 2024 — support ถึง 2029 free, 2034 ESM)
⚠️ ณ เวลาอ่านหนังสือเล่มนี้อาจมี LTS รุ่นใหม่กว่าออกมาแล้ว เช็ครุ่นล่าสุดที่ ubuntu.com/about/release-cycle ก่อนติดตั้งจริง — ตัวอย่างในบทนี้ใช้ 24.04 ณ เวลาที่เขียน
💡 LTS (Long Term Support) = version ที่ Ubuntu สัญญาจะปล่อย security update นานหลายปี — ใช้ใน production ทุกที่. release ปกติ (เช่น 23.10, 24.10) ออกทุก 6 เดือนแต่ support แค่ 9 เดือน — ห้ามใช้ใน server
3. Filesystem
Linux จัดทุกอย่างเป็น "ต้นไม้" เดียวที่เริ่มจาก / (root) — ไม่มี drive C:/D: แบบ Windows การรู้ว่าโฟลเดอร์มาตรฐานแต่ละตัวเก็บอะไร (เช่น config อยู่ /etc, log อยู่ /var/log) ช่วยให้หาไฟล์และ debug ระบบได้เร็วขึ้นมาก:
text
/ ← root (รากของระบบ)
├── bin/ ← โปรแกรมพื้นฐานที่ผู้ใช้ทั่วไปใช้ได้ (ls, cat)
├── boot/ ← kernel + bootloader (ไฟล์ที่ใช้ตอน boot)
├── dev/ ← device file (ไฟล์อ้างถึงอุปกรณ์ เช่น /dev/sda)
├── etc/ ← config ของระบบ (เช่น nginx.conf, hosts)
├── home/ ← home directory ของแต่ละ user
│ └── alice/ ← home ของ user "alice" (เรียกย่อว่า ~)
├── lib/ ← library (ไลบรารีที่โปรแกรมใน /bin, /sbin ใช้)
├── media/ ← จุด mount ของสื่อภายนอก (USB, CD)
├── mnt/ ← จุด mount ชั่วคราว (admin ใช้ mount เอง)
├── opt/ ← software เสริมจาก 3rd party (เช่น Chrome, Slack)
├── proc/ ← ข้อมูล process (virtual = ไม่ใช่ไฟล์จริงบนดิสก์ แต่ kernel สร้างให้อ่านเหมือนไฟล์)
├── root/ ← home ของ user "root" (admin สูงสุด)
├── sbin/ ← โปรแกรมระบบสำหรับ admin (ใช้ sudo)
├── srv/ ← ข้อมูลของ service (เช่น web, ftp)
├── sys/ ← ข้อมูล kernel + อุปกรณ์ (virtual เช่นเดียวกับ /proc)
├── tmp/ ← ไฟล์ชั่วคราว (ล้างเมื่อ reboot)
├── usr/ ← โปรแกรม + ข้อมูลของ user ทั่วไป
│ ├── bin/ ← โปรแกรมส่วนใหญ่อยู่ตรงนี้
│ ├── local/ ← ของที่ติดตั้งเอง (ไม่ใช่ผ่าน package manager)
│ └── share/ ← ข้อมูลที่ใช้ร่วม (manual, icon)
└── var/ ← ข้อมูลที่เปลี่ยนแปลงตลอด (variable)
├── log/ ← log ของระบบและ service
├── lib/ ← state ถาวร (เช่น database)
└── www/ ← ข้อมูล web server4. Navigation
ทักษะพื้นฐานที่สุดบน terminal คือ "เดิน" ไปมาในระบบไฟล์และ "หา" ของให้เจอ — กลุ่มคำสั่งนี้ (cd/ls สำหรับเดินดู, find/grep สำหรับค้นหาไฟล์และเนื้อหา) คือเครื่องมือที่คุณจะใช้บ่อยที่สุดทุกวัน:
bash
pwd # แสดง directory ปัจจุบัน
cd /var/log # เปลี่ยน directory
cd .. # ขึ้นไป directory แม่
cd ~ # ไป home
cd - # กลับ directory ก่อนหน้า
ls # list ไฟล์
ls -la # ทุกไฟล์ + รายละเอียด
ls -la /etc/ # ระบุ path
ls -lh # ขนาดอ่านง่าย (KB/MB)
ls -ltr # เรียงตามเวลา ย้อนกลับ (เก่าสุดขึ้นก่อน)
# ค้นหาไฟล์
find / -name "*.log" 2>/dev/null # หาไฟล์ตามชื่อ
# (2>/dev/null = ซ่อน error ที่เกิดจาก folder ที่เราไม่มีสิทธิ์เข้าถึง
# ถ้าไม่ใส่จะเห็น "Permission denied" เต็มหน้าจอจนผลลัพธ์หาย)
find / -xdev -name "*.log" 2>/dev/null # -xdev = ไม่ข้าม filesystem (ไม่ลง /proc, /sys, mount ภายนอก)
find /var/log -mtime -7 # แก้ไขภายใน < 7 วัน
find /var -size +100M # ใหญ่กว่า 100 MB
find . -type f -name "*.txt" # เฉพาะไฟล์
find . -type d -name "src" # เฉพาะ directory (โฟลเดอร์)
# ค้นหาในเนื้อหาไฟล์ — app.log ด้านล่างคือชื่อไฟล์ตัวอย่าง สลับเป็นไฟล์จริงที่คุณมี
# (ยังไม่มีไฟล์ทดสอบ ลองสร้างจาก Lab 0 ด้านบน หรือ echo "ERROR test" > app.log ก่อนก็ได้)
grep "ERROR" app.log
grep -r "TODO" . # ค้นทุก subfolder (recursive = ลึกลงทุกชั้น)
grep -i "error" app.log # ไม่สนตัวพิมพ์เล็ก/ใหญ่
grep -v "INFO" app.log # กลับเงื่อนไข (ตัดบรรทัดที่มี INFO ออก)
grep -A 3 "error" app.log # โชว์ 3 บรรทัดหลังที่เจอ (After)
grep -B 3 "error" app.log # 3 บรรทัดก่อนหน้า (Before)
grep -C 3 "error" app.log # บริบท ก่อน+หลัง (Context)
grep -E "ERROR|WARN" app.log # ใช้ regex แบบ extended
# ทางเลือกรุ่นใหม่ (ต้อง install ก่อน)
# sudo apt install ripgrep fd-find
rg "error" . # ripgrep — เร็วกว่า grep มาก
fd "\.log$" # fd — ใช้ regex (ไม่ใช่ glob เหมือน find)
# ⚠️ บน Debian/Ubuntu: คำสั่งจริงคือ `fdfind` (ชื่อ `fd` ชนกับ package เดิม)
# ตั้ง alias ให้สะดวก: alias fd=fdfind
fdfind -e log # หาไฟล์ extension .log (เขียนสั้นกว่า)5. File Operations
ถัดจากการเดินดูคือการ "จัดการ" ไฟล์จริง ๆ — อ่าน (cat/less/tail -f), คัดลอก/ย้าย/ลบ (cp/mv/rm), สร้าง และแก้ไขด้วย editor บน terminal (nano/vim) กลุ่มคำสั่งนี้คือพื้นฐานที่ใช้ตอน deploy และดูแลเซิร์ฟเวอร์จริง:
bash
# อ่านไฟล์
cat file.txt
less file.txt # ดูทีละหน้า (เลื่อนได้)
head file.txt # 10 บรรทัดแรก
head -n 50 file.txt
tail file.txt # 10 บรรทัดท้าย
tail -n 100 file.txt
tail -f file.log # ตามดูแบบ real-time (เห็น log เพิ่มสด ๆ)
tail -F file.log # -F ตามต่อแม้ไฟล์ถูก rotate (logrotate สร้างไฟล์ใหม่)
# คัดลอก / ย้าย / ลบ
cp src.txt dest.txt
cp -r src/ dest/ # recursive (ทั้ง directory)
mv old.txt new.txt # เปลี่ยนชื่อหรือย้าย
rm file.txt
rm -rf directory/ # ลบทั้ง directory แบบบังคับ (⚠️ ระวัง!)
# สร้าง
touch newfile.txt
mkdir newdir
mkdir -p a/b/c # สร้าง directory แม่ให้ด้วย
# เขียน
echo "hello" > file.txt # เขียนทับ
echo "hello" >> file.txt # ต่อท้าย
# แก้ไข
nano file.txt # ง่าย
vim file.txt # ทรงพลัง (เรียนรู้ยากกว่า)⚠️ Vim เริ่มต้นในโหมด Normal (ไม่ใช่โหมดพิมพ์) — เมื่อเปิดไฟล์ด้วย vim ครั้งแรก ยังพิมพ์ข้อความไม่ได้ ต้องกด
iก่อนถึงจะพิมพ์ได้
- ถ้ายังไม่ได้กด
iแล้วพิมพ์ ตัวอักษรจะไม่ขึ้น (หรือทำ action แปลก ๆ)- ถ้าติดอยู่ใน Vim และออกไม่ได้: กด
ESCแล้วพิมพ์:q!แล้วกด Enter (ออกโดยไม่บันทึก)
bash
# คำสั่ง Vim พื้นฐาน
i # เข้าโหมดพิมพ์ (insert mode = โหมดแก้ไขข้อความ)
ESC # กลับโหมดปกติ
:w # บันทึก
:q # ออก
:wq # บันทึก + ออก
:q! # ออกโดยไม่บันทึก
/text # ค้นหา
n # ไปตัวที่เจอถัดไป
dd # ลบบรรทัด
yy # คัดลอกบรรทัด
p # วาง
u # undo
Ctrl+r # redo
gg # ไปบนสุด
G # ไปล่างสุด6. Permissions
อ่าน output ของ ls -l
bash
ls -l file.txt
# -rw-r--r-- 1 alice users 1024 May 18 10:00 file.txt
# ↑ ↑ ↑ ↑
# │ │ │ │
# │ │ │ └── others permission (คนอื่น ๆ ที่เข้ามาในระบบ)
# │ │ └───── group permission (สมาชิกของ group "users")
# │ └──────── owner permission (alice)
# └──────────── type (- file, d directory, l link)Permission ใน Linux มีแค่ 3 อย่าง
text
r = read → อ่านไฟล์ได้ / list ไฟล์ใน folder ได้
w = write → แก้ไฟล์ได้ / สร้าง+ลบไฟล์ใน folder ได้
x = execute → run ไฟล์ได้ (script/binary) / เข้า cd folder ได้ตัวเลข rwx มาจากไหน — Binary System
ทุก permission = bit (เปิด/ปิด) → 3 bits = ค่า 0-7 ในเลขฐาน 8 (octal):
text
r w x binary octal
0 0 0 → 000 → 0 (---)
0 0 1 → 001 → 1 (--x)
0 1 0 → 010 → 2 (-w-)
0 1 1 → 011 → 3 (-wx)
1 0 0 → 100 → 4 (r--)
1 0 1 → 101 → 5 (r-x)
1 1 0 → 110 → 6 (rw-)
1 1 1 → 111 → 7 (rwx)→ ที่มาของ "r=4, w=2, x=1" — ไม่ใช่เลขมั่ว, มาจาก binary bit value → บวกกัน: rwx = 4+2+1 = 7, rw- = 4+2 = 6, r-x = 4+1 = 5
chmod — 3 ตัวเลข = owner / group / others
bash
chmod 755 file # rwxr-xr-x (owner: รวมหมด, อื่น ๆ: อ่าน+run)
chmod 644 file # rw-r--r-- (owner: rw, อื่น ๆ: r เท่านั้น) — default ของไฟล์
chmod 600 secret # rw------- (เฉพาะ owner) — สำหรับ SSH key
chmod 700 dir # rwx------ (เฉพาะ owner เข้าได้) — folder ส่วนตัว
chmod 777 file # rwxrwxrwx ⚠️ NEVER ทำกับ production!
# Symbolic (เขียนแบบตัวอักษรแทนตัวเลข)
chmod u+x file # u=user(owner) เพิ่มสิทธิ์ execute
chmod g-w file # g=group ถอนสิทธิ์ write
chmod o=r file # o=others ตั้งให้เหลือแค่ read
chmod a+r file # a=all (user+group+others) เพิ่ม read ให้ทุกคน
# Recursive (ทำซ้ำลงทุก subfolder)
chmod -R 755 dir/Special bit — setuid / setgid / sticky (chmod 4 หลัก)
💡 มือใหม่ข้ามส่วนนี้ได้ก่อน — นอกจาก 3 หลักปกติ (owner/group/others) Linux มีหลักแรก (special bits) ที่ใช้สำหรับ setuid, setgid, sticky ซึ่งใช้ในสถานการณ์เฉพาะเจาะจง กลับมาอ่านเมื่อจำเป็นจริง ๆ
นอกจาก rwx ปกติ Linux ยังมี bit พิเศษอีก 3 ตัว ที่ทำให้ chmod กลายเป็น 4 หลัก (หลักแรกคือ special):
bash
chmod 4755 binary # setuid — รันแล้ว process ได้สิทธิ์ของ owner (เช่น /usr/bin/passwd)
chmod 2755 dir # setgid บน directory — ไฟล์ใหม่ใน dir ได้ group เดียวกับ dir
chmod 1777 dir # sticky bit — ลบไฟล์ได้เฉพาะเจ้าของไฟล์ (เช่น /tmp)
ls -ld /tmp # → drwxrwxrwt ตัว t ท้าย = sticky⚠️ setuid บน script เป็นช่องโหว่ความปลอดภัย — Linux ส่วนใหญ่ ignore setuid บน shell script. ใช้กับ binary เท่านั้นและด้วยความระมัดระวัง
ACL — สิทธิ์ละเอียดกว่า rwx (เมื่อ owner/group/others ไม่พอ)
bash
getfacl file.txt # ดู ACL ของไฟล์
setfacl -m u:bob:rw file.txt # ให้ user "bob" อ่าน+เขียนได้ (นอกเหนือจาก owner/group)
setfacl -x u:bob file.txt # ถอน ACL ของ bobACL = Access Control List — ให้สิทธิ์ user/group ทีละคนได้ ไม่จำกัดแค่ owner/group/others. systemd-tmpfiles และ container runtime จริงใช้กันบ่อย
chown
bash
chown alice file # เปลี่ยน owner เป็น alice
chown alice:users file # เปลี่ยน owner + group
chown -R alice:users dir/ # ทำซ้ำลงทุกชั้นsudo
bash
sudo command # รันแบบ root
sudo -u other_user command # รันในนามของ user อื่น
sudo -i # เปิด shell แบบ root
sudo !! # รันคำสั่งก่อนหน้าใหม่ในแบบ root
# ⚠️ !! ใช้ได้ใน bash/zsh ที่เปิด history expansion
# บางสภาพแวดล้อม (script, sh ล้วน) จะไม่รู้จัก7. Process
ทุกโปรแกรมที่รันอยู่คือ "process" — การดูว่ามีอะไรรันอยู่ (ps/top/htop), สั่งหยุด (kill), รันเบื้องหลัง (&/nohup) และเช็คทรัพยากร(free/df) คือสิ่งจำเป็นเวลาแอปค้าง กิน CPU/RAM เกิน หรือต้องรีสตาร์ต service บนเซิร์ฟเวอร์:
bash
# ดูรายการ process
ps aux # ทุก process
ps -ef # แบบ tree (เห็นพ่อ-ลูก)
ps aux | grep java # หา process ของ java
# Top — ดูแบบ real-time
top
# ก่อนใช้ htop ครั้งแรกต้องลงก่อน: sudo apt install htop
htop # ดีกว่า top (เลื่อน/sort/kill ได้ด้วยปุ่ม)
# สั่งหยุด process (kill)
kill 1234 # SIGTERM (สัญญาณ 15) — ขอให้ปิดอย่างนุ่มนวล (default)
kill -9 1234 # SIGKILL (สัญญาณ 9) — บังคับฆ่าทันที ⚠️ ใช้เป็นทางสุดท้าย
# SIGKILL ไม่ให้โอกาส process cleanup:
# - ไฟล์ที่เปิดอยู่อาจเสีย / เขียนไม่ครบ
# - DB transaction ค้างกลางคัน
# - lock file ไม่ถูกลบ → restart ไม่ขึ้น
# ลำดับที่ถูก: kill (TERM) → รอ 5-10 วิ → kill -9 ถ้ายังไม่ตาย
killall java # ฆ่า process ชื่อ java ทั้งหมด (TERM)
pkill -f "node server.js" # ฆ่าตาม pattern ของชื่อคำสั่งเต็ม (TERM)
# รันเบื้องหลัง (background)
./script.sh & # รันเบื้องหลัง
nohup ./script.sh & # รันต่อแม้ logout ออกไป
disown # ตัดขาดจาก shell
# สลับ foreground / background
jobs # ดู job ที่รันเบื้องหลัง
fg %1 # ดึง job 1 มาทำงานเบื้องหน้า
bg %1 # ให้ job ทำงานต่อเบื้องหลัง
Ctrl+Z # พัก process ปัจจุบัน
Ctrl+C # หยุด process ปัจจุบัน
# ดูการใช้ทรัพยากร
free -h # หน่วยความจำ (RAM)
df -h # พื้นที่ดิสก์
du -sh /var/log/* # ขนาดต่อ directory
uptime # ค่าเฉลี่ยภาระงาน (load average)🚀 ขั้นสูง — ข้ามได้ cgroup v2 เป็นกลไกระดับ kernel ที่ใช้เบื้องหลังใน Docker/Kubernetes — มือใหม่ยังไม่ต้องใช้ กลับมาอ่านเมื่อเรียนถึงบท Container
bash
# cgroup v2 — กลไกของ kernel ที่จำกัด/วัดทรัพยากรต่อกลุ่ม process
# (เป็นรากฐานของ Docker, Podman, systemd resource limits — Ubuntu 22+/RHEL 9 ใช้ unified hierarchy
# แปลว่า "จัดกลุ่ม resource ทุกชนิด (CPU/RAM/IO) ไว้ในต้นไม้เดียว" แทนที่จะแยกคนละต้นไม้แบบ cgroup v1)
systemd-cgls # แสดง process จัดกลุ่มตาม cgroup (สวยกว่า ps tree)
systemd-cgtop # top แต่จัดกลุ่มตาม cgroup
cat /sys/fs/cgroup/cgroup.controllers # ดูว่า kernel เปิด controller อะไรบ้าง8. I/O Redirection + Pipes
พลังที่แท้จริงของ shell คือการต่อคำสั่งเล็ก ๆ เข้าด้วยกัน — "redirect" (>/>>/2>) ส่ง output ไปเก็บในไฟล์, "pipe" (|) ส่ง output ของคำสั่งหนึ่งเป็น input ของอีกคำสั่ง ทำให้สร้าง one-liner ทรงพลังได้ เช่นกรอง log แบบ real-time นี่คือหัวใจของปรัชญา Unix "ทำอย่างเดียวให้ดี แล้วต่อกัน":
💡 เข้าใจ
2>&1ก่อน: ทุกโปรแกรมมีช่องส่งออก 2 ช่อง — 1 = stdout (output ปกติ) และ 2 = stderr (ข้อความ error)2>&1แปลว่า "เอา stderr (2) ไปรวมกับ stdout (1)" → ทั้ง output ปกติและ error ไปที่เดียวกัน (เลข 1, 2 นี้คือ file descriptor ที่กางไว้ตอนต้นบท)
bash
# Redirect
command > file # stdout (1) → file (เขียนทับ)
command >> file # append (ต่อท้าย)
command 2> error.log # stderr (2) → ไฟล์ error
command > out.log 2>&1 # ทั้ง stdout + stderr → ไฟล์เดียว (2>&1 = รวม stderr เข้า stdout)
command &> out.log # เหมือนข้างบน (shell รุ่นใหม่)
command < input.txt # stdin จากไฟล์
# Pipe (ส่ง output ของคำสั่งซ้ายเป็น input ของคำสั่งขวา)
ps aux | grep java | wc -l # นับจำนวน process java
cat file | sort | uniq | head # ต่อกันเป็นทอด ๆ
tail -f app.log | grep ERROR # กรอง log แบบ real-time
# /dev/null = ถังขยะ (ทิ้ง output ที่ไม่อยากเห็น)
command > /dev/null 2>&1 # เงียบทั้ง output + error
command &>/dev/null # เหมือนกัน9. Useful Commands
รวมคำสั่งที่ใช้บ่อยในงาน DevOps จริง แยกเป็นหมวด — เริ่มจากกลุ่ม network ที่ใช้ตอน debug การเชื่อมต่อ: ทดสอบเข้าถึงได้ไหม (ping/curl), เช็คว่ามีอะไรเปิด port อยู่ (ss/lsof) และตรวจ DNS (dig/nslookup):
Network
bash
ping google.com
curl https://example.com
curl -X POST -d '{"key":"val"}' -H "Content-Type: application/json" https://api.example.com
curl -I https://example.com # headers only
wget https://example.com/file.zip # download
# Check ports — ดูว่ามีโปรแกรมไหนเปิด port อะไรค้างอยู่
ss -tlnp # ⭐ มาตรฐานปัจจุบัน (ติดมาทุก distro)
# -t = TCP, -l = listening only,
# -n = ไม่ resolve ชื่อ (เร็วกว่า), -p = แสดง process ที่เปิด
ss -tulnp # เพิ่ม -u = UDP ด้วย
# netstat -tlnp # ⚠️ legacy — ไม่ติดมา default บน Ubuntu 18+/RHEL 8+
# ต้อง `sudo apt install net-tools` ก่อน
lsof -i :8080 # ใครเปิด port 8080 อยู่ (lsof = list open files)
# DNS — ระบบแปลงชื่อโดเมน (example.com) เป็น IP address (93.184.215.14)
dig example.com # ⭐ ทันสมัยและละเอียดสุด
nslookup example.com # legacy แต่ยังใช้ได้
host example.com # สั้นที่สุด
# Network interfaces — ดู IP/MAC ของการ์ดเครือข่ายแต่ละใบ
ip addr # ⭐ มาตรฐานปัจจุบัน (ย่อ: `ip a`)
ip link # สถานะ link layer (up/down, MAC)
# ifconfig # ⚠️ legacy — ไม่ติดมา default บน Ubuntu 18+
# ต้อง `sudo apt install net-tools` ก่อน
# Routes — ดูเส้นทางออกของ packet
ip route # ⭐ มาตรฐานปัจจุบัน (ย่อ: `ip r`)
traceroute example.com # ไล่ดู hop ระหว่างทางText Processing
🚀 โซนขั้นสูง — ข้ามได้
awkและsedเป็นภาษาเล็ก ๆ ในตัวเองที่ทรงพลังแต่ syntax งง มือใหม่ยังไม่ต้องท่อง — รู้แค่ว่า "ใช้แยกคอลัมน์ / แทนที่ข้อความใน text ได้" ก็พอ แล้วกลับมาเปิดดูเป็นสูตรเมื่อต้องใช้จริง
bash
# sort + uniq
sort file.txt
sort -r # reverse — เรียงจากมากไปน้อย
sort -n # numeric — เรียงแบบตัวเลข (ไม่งั้น 10 มาก่อน 2)
sort -u # unique = sort แล้วตัดบรรทัดซ้ำ (เทียบเท่า sort | uniq)
sort file | uniq -c # นับจำนวนซ้ำของแต่ละบรรทัด (count)
# cut — ตัดคอลัมน์ออกจากไฟล์ที่มี delimiter
cut -d',' -f1,3 file.csv # delimiter=, → เอาเฉพาะ field 1 และ 3
cut -c1-10 file # ตัดตัวอักษรที่ 1-10 ของแต่ละบรรทัด
# awk — จัดการคอลัมน์ (column manipulation)
awk '{print $1}' file # พิมพ์คอลัมน์แรก
awk -F',' '{print $2}' file.csv # ใช้ , เป็น delimiter แล้วเอา column 2
awk '$3 > 100 {print $1}' file # filter — เอาเฉพาะแถวที่ column 3 > 100
# sed — แทนที่ข้อความ (replace/substitute)
sed 's/old/new/g' file # แทนทุกครั้งที่เจอ (g = global)
sed -i 's/old/new/g' file # in-place = แก้ในไฟล์เลย (ไม่ต้อง redirect)
sed -i.bak 's/old/new/g' file # in-place แต่สำรองไฟล์เดิมเป็น file.bak
# wc — word count (นับ)
wc -l file # นับจำนวนบรรทัด (line count)
wc -w file # นับจำนวนคำ (word count)
# diff — เทียบไฟล์ 2 ไฟล์
diff file1 file2
diff -u file1 file2 # unified format (อ่านง่าย เหมือน git diff)Archive
bash
# tar — สร้าง/แตก archive (ไฟล์รวม)
tar czf archive.tar.gz folder/ # สร้าง archive แบบ gzip (c=create, z=gzip, f=file)
tar xzf archive.tar.gz # แตก archive (x=extract)
tar czf archive.tar.gz -C / etc/ # -C = เปลี่ยน directory ก่อน archive
# (ตัวอย่างนี้: cd ไป / แล้ว archive etc/ → path ใน tar เริ่มที่ etc/)
tar tf archive.tar.gz # list — ดูรายชื่อไฟล์ใน archive (t=table)
# zip
zip -r archive.zip folder/ # -r = ทั้ง subfolder
unzip archive.zip
# Modern (เลือกใช้ถ้ามี — `sudo apt install p7zip-full` ก่อน)
7z a archive.7z folder/ # บีบอัดได้แน่นกว่า .tar.gzDisk
bash
df -h # disk free
du -sh /var/log # size of dir
du -h --max-depth=1 /var # 1 level deep10. Environment Variables
environment variable คือค่าตั้งค่าที่ส่งให้โปรแกรมผ่าน "สิ่งแวดล้อม" ของ shell แทนการ hardcode (เขียนค่าตายตัว) ลงในโค้ด ใช้เก็บ config ที่ต่างกันตาม environment (เช่น DATABASE_URL, PATH) — เพราะถ้า hardcode DB ของ production ไว้ในโค้ด พอ deploy ขึ้น server จริงจะต่อ DB ผิดตัวหรือรั่วรหัสผ่านออกไปกับ source code
นี่คือวิธีมาตรฐานของ 12-factor app (12-factor app = แนวทางมาตรฐานการออกแบบ app สำหรับ cloud ที่บอกว่า "แยก config ออกจาก code" เป็นหนึ่งใน 12 ข้อ) และจำเป็นมากเวลา deploy จริง:
bash
# Set
export PATH=$PATH:/opt/myapp/bin
export DATABASE_URL="postgresql://..."
# Read
echo $PATH
env # all env
printenv DATABASE_URL
# Inline
DATABASE_URL=postgres://... ./myapp
# Persist (Ubuntu)
echo 'export PATH=$PATH:/opt/myapp/bin' >> ~/.bashrc
source ~/.bashrc # reloadCommon variables
text
$HOME # /home/alice
$USER # alice
$PWD # current dir
$PATH # executable search path
$SHELL # /bin/bash
$? # exit code of last command (0 = success)
$$ # current process pid
$0 # script name
$1, $2 ... # script arguments11. Shell Scripting
เมื่อคุณทำคำสั่งเดิมซ้ำ ๆ ก็ถึงเวลารวมมันเป็น "script" — shell scripting ให้คุณเขียนหลายคำสั่งไว้ในไฟล์เดียวแล้วรันรวดเดียว เช่น backup หรือ deploy นี่คือก้าวแรกจากการพิมพ์คำสั่งทีละบรรทัดสู่การ automate (ทำงานอัตโนมัติ) จริง โครงสร้างหลักที่ใช้บ่อยคือตัวแปร, เงื่อนไข (if), ลูป (for/while) และฟังก์ชัน — โค้ดด้านล่างมีตัวอย่างของแต่ละอย่างพร้อมคอมเมนต์กำกับ:
bash
#!/bin/bash
# script.sh
# Variables
NAME="World"
echo "Hello, $NAME"
# Read input (-r = ไม่ตีความ backslash, ใส่ทุกครั้งให้ติดนิสัย — shellcheck แนะนำ)
read -rp "Enter name: " USER_NAME
echo "Hi $USER_NAME"
# Conditional — if/elif/else
if [ -f /etc/passwd ]; then
echo "File exists"
elif [ -d /var/log ]; then
echo "Dir"
else
echo "Neither"
fi
# Tests — เงื่อนไขที่ใช้ใน [ ... ]
[ -f file ] # ไฟล์มีอยู่ (file exists)
[ -d dir ] # เป็น directory
[ -z "$var" ] # ตัวแปรว่าง (empty)
[ -n "$var" ] # ตัวแปรไม่ว่าง (non-empty)
[ "$a" = "$b" ] # string เท่ากัน
[ "$a" != "$b" ] # string ไม่เท่ากัน
[ "$a" -eq "$b" ] # numeric equal (ตัวเลข)
[ "$a" -lt "$b" ] # less than (น้อยกว่า)
[ "$a" -gt "$b" ] # greater than (มากกว่า)
# Loops — for/while
for i in 1 2 3; do
echo $i
done
# ⚠️ for loop บน glob (*.txt) — ถ้า "ไม่มีไฟล์ที่ตรง pattern" loop จะรัน 1 รอบ
# ด้วยค่า literal "*.txt" (Bash default behavior) → script ทำงานผิด
# ทางออก 2 แบบ:
shopt -s nullglob # ตั้งให้ glob ที่ไม่ match → คืน list ว่าง (ไม่รัน loop)
for file in *.txt; do
[[ -e $file ]] || continue # หรือเช็คทีละไฟล์ในกรณีไม่ได้ตั้ง nullglob
echo "Processing $file"
done
for i in $(seq 1 10); do
echo $i
done
# While
count=0
while [ $count -lt 5 ]; do
echo $count
((count++))
done
# Functions
greet() {
local name=$1
echo "Hello, $name"
}
greet "World"
# Exit code — ตรวจว่าโปรแกรมมีอยู่ในระบบไหม
if ! command -v git &> /dev/null; then
echo "git not installed"
exit 1
fiBest practices
bash
#!/bin/bash
set -e # หยุดทันทีเมื่อคำสั่งใดล้มเหลว (exit on error)
set -u # error เมื่อใช้ตัวแปรที่ยังไม่ตั้งค่า (undefined variable)
set -o pipefail # ถ้าคำสั่งใน pipe ใดล้มเหลว → ถือว่าทั้ง pipe ล้มเหลว
# รวมเป็นบรรทัดเดียว
set -euo pipefail
IFS=$'\n\t' # ตั้ง field separator เป็น newline+tab — จัดการชื่อไฟล์ที่มีช่องว่างได้ถูก
# (default ของ bash คือ space+tab+newline → ตัดคำที่มีช่องว่างผิด)
# Trap — ดักจับ error/exit เพื่อ cleanup
trap 'echo "Error at line $LINENO"; exit 1' ERR
trap 'rm -f /tmp/myapp.lock' EXIT # ลบ lock file ทุกกรณีก่อนจบ (สำเร็จ/ล้มเหลว/ถูก Ctrl+C)12. Practical Examples
ทีนี้มาดูว่า concept ทั้งหมดประกอบกันเป็น script ใช้งานจริงยังไง — ตัวอย่างต่อไปนี้เป็น script ที่ DevOps เขียนกันจริง เช่น backup ฐานข้อมูลอัตโนมัติ สังเกตการใช้ set -euo pipefail และตัวแปร date เพื่อความปลอดภัยและตั้งชื่อไฟล์ตามเวลา:
Backup script
bash
#!/bin/bash
# Prerequisite (ติดตั้ง + ตั้งค่าก่อนใช้):
# - PostgreSQL client: sudo apt install postgresql-client
# (pg_dump = คำสั่ง backup ฐานข้อมูล PostgreSQL — เรียนเพิ่มเติมใน Database section)
# - AWS CLI v2: curl + install (ดู docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
# (aws s3 cp = คำสั่ง AWS CLI สำหรับอัปโหลดไฟล์ขึ้น S3 — เรียนเพิ่มเติมในบทที่ 6 Cloud Platforms)
# - Credential ของ AWS: แนะนำ IAM role (ติด instance/role) > access key
# ถ้าจำเป็นต้องใช้ key ให้รัน `aws configure` หรือ set env
# - Credential ของ PostgreSQL: ใช้ ~/.pgpass (chmod 600) หรือ PGPASSWORD
# (ห้าม hardcode password ใน script)
set -euo pipefail
IFS=$'\n\t'
BACKUP_DIR=/var/backups/myapp
DATE=$(date +%Y%m%d-%H%M)
BACKUP_FILE="$BACKUP_DIR/db-$DATE.sql.gz"
S3_BUCKET="s3://my-backups/db/"
mkdir -p "$BACKUP_DIR"
# pg_dump — ใช้ ~/.pgpass (vault credential ฝั่ง postgres) แทนใส่ password ตรง ๆ
# format ของ ~/.pgpass: hostname:port:database:username:password (chmod 600)
pg_dump -h localhost -U backup_user -d mydb | gzip > "$BACKUP_FILE"
echo "สร้าง backup แล้ว: $BACKUP_FILE"
# เก็บไว้เฉพาะของ 7 วันล่าสุด (ลบไฟล์ที่เก่ากว่า 7 วัน)
find "$BACKUP_DIR" -name "db-*.sql.gz" -mtime +7 -delete
# Upload ขึ้น S3 พร้อม server-side encryption (SSE-KMS) — ปลอดภัยกว่า default
# แนะนำให้ EC2/host ใช้ IAM role แทน access key เพื่อไม่ต้องเก็บ secret ไว้บนเครื่อง
aws s3 cp "$BACKUP_FILE" "$S3_BUCKET" \
--sse aws:kms \
--storage-class STANDARD_IA💡 ทำไมต้องเข้ารหัส + ใช้ IAM role: backup database คือ "ทรัพย์สินค่าสูง" ของบริษัท — ใส่ขึ้น S3 แบบ plain เท่ากับเสี่ยงข้อมูลรั่ว. SSE (
--sse aws:kms) ให้ AWS เข้ารหัสฝั่ง server, IAM role ทำให้ไม่ต้องเก็บ access key บน server (โดน leak ยากกว่า)
Log analyzer
bash
#!/bin/bash
# สมมุติ log เป็น nginx access log (Combined Log Format):
# $1 = IP ของ client, $7 = URL/endpoint ที่ขอ
# ถ้า log มี format อื่น (เช่น JSON) ต้องเปลี่ยนวิธี parse — ใช้ jq แทน awk
LOG=/var/log/app.log
echo "Total requests: $(wc -l < "$LOG")"
echo "Errors: $(grep -c ERROR "$LOG")"
echo ""
echo "Top 10 IPs:"
awk '{print $1}' "$LOG" | sort | uniq -c | sort -rn | head -10
echo ""
echo "Top 10 endpoints:"
awk '{print $7}' "$LOG" | sort | uniq -c | sort -rn | head -10Health check
bash
#!/bin/bash
# Prerequisite: ตั้งค่า SLACK_WEBHOOK ก่อนใช้ — เช่น
# export SLACK_WEBHOOK="https://hooks.slack.com/services/XXX/YYY/ZZZ"
# (เก็บใน secret manager หรือ ~/.bashrc — ห้าม hardcode ใน script)
set -euo pipefail
ENDPOINT="https://api.example.com/health"
ALERT_STATE_FILE="/tmp/healthcheck.down" # flag กันแจ้งเตือนซ้ำ
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$ENDPOINT")
if [ "$STATUS" -ne 200 ]; then
# Alert dedup — แจ้งครั้งเดียวต่อช่วง down (ไม่ flood Slack ทุก 5 นาที)
if [ ! -f "$ALERT_STATE_FILE" ]; then
echo "Service ล่ม! Status: $STATUS"
curl -X POST -H "Content-Type: application/json" \
-d "{\"text\":\"🚨 API ล่ม: status $STATUS\"}" \
"$SLACK_WEBHOOK"
touch "$ALERT_STATE_FILE"
fi
exit 1
fi
# Service กลับมาแล้ว — แจ้ง recover + ลบ flag
if [ -f "$ALERT_STATE_FILE" ]; then
curl -X POST -H "Content-Type: application/json" \
-d '{"text":"✅ API กลับมาแล้ว"}' \
"$SLACK_WEBHOOK"
rm -f "$ALERT_STATE_FILE"
fi
echo "Service ปกติ (OK)"13. SSH
SSH (Secure Shell) คือวิธีที่คุณ login เข้าเซิร์ฟเวอร์ระยะไกลอย่างปลอดภัยผ่าน encrypted connection — DevOps ใช้ SSH แทบทุกวันในการเข้าไปดูแลเซิร์ฟเวอร์ การใช้ key (แทน password), ตั้ง ~/.ssh/config ให้ alias สั้น ๆ และ port forwarding คือทักษะที่ต้องคล่อง:
bash
# Connect — login เข้า server
ssh user@server.com
ssh -p 2222 user@server.com # ระบุ port (default 22)
ssh -i key.pem user@server.com # ใช้ private key เฉพาะ (with key file)
# Generate key — สร้างคู่ key (private + public)
ssh-keygen -t ed25519 -C "your@email.com" # ⭐ มาตรฐานปัจจุบัน (2026) — เล็ก เร็ว ปลอดภัย
# ssh-keygen -t rsa -b 4096 # legacy — เลี่ยงถ้าไม่จำเป็น
# (NIST/GitHub แนะนำ ed25519 แล้ว)
# คัดลอก public key ไปฝากที่ server (วางใน ~/.ssh/authorized_keys ของฝั่งโน้น)
ssh-copy-id user@server.comไฟล์ใน ~/.ssh/
text
~/.ssh/
├── id_ed25519 ← private key (chmod 600! — ห้ามให้คนอื่นอ่าน)
├── id_ed25519.pub ← public key (เปิดเผยได้)
├── known_hosts ← server ที่เคยเชื่อมต่อมาแล้ว
├── authorized_keys ← public key ที่อนุญาตให้ login เข้าเครื่องนี้
└── config ← SSH client config — alias ของ hostตัวอย่าง ~/.ssh/config
sshconfig
# ตั้ง alias สั้น ๆ → พิมพ์แค่ `ssh myserver`
Host myserver
Hostname server.com
User alice
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes # ใช้เฉพาะ key ที่ระบุ — กัน "many keys offered" ที่ทำให้ GitHub block
HashKnownHosts yes # hash hostname ใน known_hosts (privacy: ไม่เห็น list server เป็น plain)
# ค่า default ที่ใช้ทุก host (วางท้ายไฟล์ — config แบบ first-match)
Host *
ServerAliveInterval 60 # ส่ง keepalive ทุก 60 วิ (กันหลุดจาก NAT)
HashKnownHosts yesbash
# จากนั้นเรียกสั้น ๆ
ssh myserverSCP / rsync — File transfer
bash
# scp
scp local.txt user@server:/path/
scp user@server:/path/file.txt ./
scp -r local-dir/ user@server:/path/
# rsync (better — resume, sync)
rsync -avz src/ user@server:/path/dest/
rsync -avz --delete src/ user@server:/path/dest/ # mirrorPort forwarding
bash
# Local forward — เปิด port ฝั่ง local ที่ map ไปยัง service ฝั่ง remote
# (ใช้บ่อย: เข้าถึง DB ของ server โดยไม่ต้องเปิด port public)
ssh -L 5432:localhost:5432 user@server
# ตอนนี้ localhost:5432 ของเครื่องเรา = DB ของ server แล้ว
# Remote forward — เปิด port ฝั่ง server ที่ map กลับมาที่ local
ssh -R 8080:localhost:3000 user@server
# port 8080 ของ server → เข้าถึงเครื่องเรา port 300014. System Service (systemd)
systemd คืออะไร — ทำไมต้องมี
ก่อน Ubuntu 16.04 / RHEL 7 — Linux ใช้ init.d (script ใน /etc/init.d/) start service. ปัญหา:
- Start ทีละตัวเรียงกัน → boot ช้า
- ไม่รู้ว่า service พังแล้วต้อง restart ไหม
- Log กระจัดกระจาย ไม่มีกลาง
- Dependency ระหว่าง service เขียนยาก
systemd (ปี 2010 โดย Lennart Poettering / Red Hat) แก้ปัญหานี้ — ปัจจุบันใช้ใน Ubuntu, Debian, RHEL, Fedora, Arch ทุกที่:
| systemd แก้อะไร | ของเดิม | systemd |
|---|---|---|
| Parallel boot (boot พร้อมกันหลาย service) | sequential — ทีละตัว, ช้า | parallel ตาม dependency |
| Auto-restart (รีสตาร์ตเองเมื่อ crash) | ต้องเขียน script เอง | Restart=on-failure |
| Logging (เก็บ log) | กระจัดกระจาย หลายไฟล์ | journalctl รวมที่เดียว |
| Resource limit (จำกัด RAM/CPU) | ทำยาก ต้องใช้ cgroup เอง | MemoryMax, CPUQuota built-in |
| Timer (ตัวตั้งเวลา แทน cron) | cron + grep log | systemd-timer + journal |
Concept หลัก: ทุกอย่างคือ unit — service, timer, socket, mount = unit แบบต่าง ๆ
bash
# Status
systemctl status nginx
systemctl status postgresql
# Start/Stop/Restart
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx # graceful — reload config โดยไม่ทิ้ง connection ที่ค้างอยู่
# Auto-start on boot
sudo systemctl enable nginx
sudo systemctl disable nginx
# Logs
journalctl -u nginx
journalctl -u nginx -f # follow
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since todayCreate service
Prerequisite: สร้าง user + directory ก่อน (service จะรันในนาม user นี้)
bash
sudo useradd --system --no-create-home --shell /usr/sbin/nologin alice
sudo mkdir -p /opt/myapp
sudo chown -R alice:alice /opt/myappUnit file (เก็บที่ /etc/systemd/system/myapp.service):
ini
# 3 section หลักของ unit file:
# [Unit] — metadata + dependency (boot order)
# [Service] — บอกว่าโปรแกรมรันยังไง, restart อย่างไร, security limit
# [Install] — บอกว่าจะ enable ตอน boot ในระดับไหน
[Unit]
Description=My App
After=network.target # รันหลังจาก network พร้อม
[Service]
# Type=simple — บอก systemd ว่า process หลักคือ ExecStart โดยตรง (start แล้วถือว่าเสร็จทันที)
# ⚠️ ปัญหา: systemd ถือว่า "started" ก่อนที่แอปจะพร้อมรับ traffic จริง
# ทางเลือกที่ดีกว่าใน 2026:
# Type=notify — แอปยิง sd_notify(READY=1) เมื่อพร้อม → systemd รู้สถานะจริง (แนะนำ)
# Type=exec — รอ exec() สำเร็จก่อน (ดีกว่า simple แต่ยังไม่รู้ว่าแอป ready)
Type=notify
NotifyAccess=main
User=alice
Group=alice
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start.sh
Restart=on-failure # restart อัตโนมัติเมื่อ crash
RestartSec=5 # รอ 5 วิ ก่อน restart
# Security hardening (มาตรฐาน 2026 — copy ใส่ทุก service จริง)
NoNewPrivileges=true # ห้าม process gain สิทธิ์เพิ่ม (block setuid escalation)
ProtectSystem=strict # /usr, /boot, /etc → read-only สำหรับ process นี้
ProtectHome=true # /home, /root → invisible
PrivateTmp=true # /tmp แยกของตัวเอง (ไม่ปนกับ service อื่น)
ProtectKernelTunables=true # block เขียน /proc/sys, /sys
ProtectKernelModules=true # block load/unload kernel module
RestrictSUIDSGID=true # ห้าม set suid/sgid bit ในไฟล์
LockPersonality=true # ห้ามเปลี่ยน execution domain
# Resource limit (กันแอปกิน RAM/CPU จนเครื่องล่ม)
MemoryMax=512M
CPUQuota=50%
[Install]
WantedBy=multi-user.target # enable ตอน boot ในระดับ multi-user (ปกติ)bash
sudo systemctl daemon-reload # โหลด unit file ใหม่หลังแก้
sudo systemctl enable myapp # ตั้งให้ start ตอน boot
sudo systemctl start myapp # start เลย15. Package Manager
แทนที่จะ download ติดตั้งซอฟต์แวร์ทีละตัวเอง Linux ใช้ "package manager" จัดการให้ — มันดาวน์โหลด ติดตั้ง อัปเดต และลบโปรแกรมพร้อม dependency ให้อัตโนมัติ แต่ละ distro มีตัวต่างกัน (apt บน Ubuntu/Debian, dnf บน RHEL, apk บน Alpine ที่ใช้ใน Docker บ่อย):
bash
# Ubuntu/Debian
sudo apt update # โหลด list package ใหม่ (refresh)
sudo apt upgrade # upgrade ทุก package
sudo apt full-upgrade # upgrade รวมถึง kernel + remove ของเก่าที่ขัดกัน
sudo apt install nginx # ติดตั้ง
sudo apt remove nginx
sudo apt search docker # ค้นหา package
apt list --installed # ดูที่ติดตั้งไว้
# ⚠️ ใน script ที่ต้อง stable output → ใช้ `apt-get` แทน `apt`
# เพราะ apt warns ว่า "CLI ไม่ stable" และเปลี่ยน format ได้ในเวอร์ชันใหม่
# เช่น: sudo apt-get -y install nginx
# แต่ถ้าต้อง parse ผลลัพธ์แบบ machine-readable จริงจัง (เช่นดึงรายชื่อ package)
# อย่า parse text output เลย ใช้ `dpkg-query --show` หรือ python3-apt แทน
# RHEL/CentOS/Rocky
sudo dnf update
sudo dnf install nginx
# Alpine (Docker base — บนหลายๆ image)
apk add nginx
apk update && apk upgradeSnap / Flatpak
Modern Ubuntu — desktop apps:
bash
sudo snap install --classic code # VS Code ผ่าน snap
# ⚠️ snap classic ในวงการ dev มีเสียงบ่นเรื่อง start ช้า + mount loop เยอะ
# ทางเลือก: ติดตั้ง .deb จาก repo ของ Microsoft โดยตรง (ดู docs ของ VS Code)
flatpak install flathub org.mozilla.firefox # ต้องระบุ remote (flathub) + namespace เต็ม16. Cron — Schedule
cron คือ scheduler ในตัวของ Linux ที่สั่งให้คำสั่งรันตามเวลาที่กำหนดเอง — ใช้ทำงานประจำเช่น backup ทุกคืน, healthcheck ทุก 5 นาที, ล้าง log ทุกสัปดาห์ จุดที่มือใหม่งงคือ format 5 ช่อง (นาที ชั่วโมง วัน เดือน วันในสัปดาห์) ตัวอย่างด้านล่างอ่านทีละบรรทัดจะเข้าใจ:
bash
crontab -e # แก้ไข cron ของ user (เปิด editor)
crontab -l # ดูรายการ cron ที่ตั้งไว้
# Format: นาที ชั่วโมง วันที่ เดือน วันในสัปดาห์ command
# min hour day month weekday(0=Sun)
0 3 * * * /opt/backup.sh # ทุกวัน เวลา 03:00 น.
*/5 * * * * /opt/healthcheck.sh # ทุก ๆ 5 นาที
0 0 * * 0 /opt/weekly.sh # ทุกเที่ยงคืนวันอาทิตย์
# ตัวอย่างถัดไป: ทุกชั่วโมงตรง (นาที=0) ระหว่าง 9:00–17:00 (รวม 17:00 ด้วย)
# เฉพาะวันจันทร์–ศุกร์ (1–5)
0 9-17 * * 1-5 /opt/work.sh # เวลาทำงานปกติของวันธรรมดา
# ตัวแปร (ใส่ด้านบนของ crontab — มีผลกับทุกบรรทัด)
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com # ส่ง output ของ cron ที่ไม่ silent ไป email นี้
# Shortcut แบบ predefined (เขียนสั้นลง)
@reboot /opt/start.sh # ⚠️ @reboot ไม่ใช่ทุก cron implementation รองรับ
# (เช่น systemd-cron อาจไม่มี) — ทดสอบในระบบจริงก่อน
@daily /opt/backup.sh
@weekly /opt/cleanup.sh
@monthly /opt/report.sh💡 ทางเลือกใหม่ —
systemd-timer(แนะนำสำหรับ production จริง): log ผ่าน journalctl ครบ, retry/dependency ดีกว่า, จับ lock ป้องกัน job ซ้อนได้ — cron เหมาะกับงานเล็ก ๆ ส่วนตัว/dev, timer เหมาะกับ production ที่ต้องการ observability
17. ⚠️ Dangerous Commands
บางคำสั่งทำลายระบบได้ในพริบตาและกู้คืนไม่ได้ — โดยเฉพาะ rm -rf กับ path ผิด หรือ dd ใส่ disk ผิด มือใหม่ควรรู้จักหน้าตาของมันเพื่อ "ไม่เผลอพิมพ์" และฝึกนิสัยป้องกัน (เช็คก่อนกด, ใช้ rm -i, ระวังทุกครั้งที่มี sudo):
bash
# ⚠️ ตรวจ 3 ครั้งก่อนกด Enter — คำสั่งกลุ่มนี้กู้คืนยาก/กู้ไม่ได้
rm -rf / # 🔥 พยายามลบทุกอย่าง
# (coreutils ใหม่บล็อกด้วย --preserve-root โดย default
# ตั้งแต่ปี 2006 → จะแจ้ง error แทนการลบจริง
# แต่ rm -rf /* ยังลบได้ — อย่าหลงคิดว่าปลอดภัย)
rm -rf ~/ # ลบ home directory ตัวเองทั้งหมด
sudo rm -rf / # 🔥🔥 ระดับ super (ถ้าใส่ --no-preserve-root)
dd if=/dev/zero of=/dev/sda # เขียน 0 ทับดิสก์ — wipe disk (ข้อมูลหาย)
# :(){ :|:& };: # fork bomb — สร้าง process ซ้อนกันจนเครื่องค้าง
# (comment ไว้กันคุณ copy ทั้งบรรทัด → ตั้ง ulimit -u ป้องกัน)
chmod -R 777 / # ทำลายระบบ permission ทั้งระบบ (break permissions)
> file # ตัดไฟล์ให้ว่าง (truncate) — ไม่มี warning ใด ๆ
# นิสัยป้องกันตัว (defensive habits):
# - alias rm='rm -i' # interactive — ถามก่อนลบทุกไฟล์
# - ls ก่อน rm เสมอ (ตรวจว่า pattern ถูกจริง)
# - ใช้ tab completion ช่วย (ไม่พิมพ์ path เอง)
# - ตรวจคำสั่งที่มี sudo อย่างน้อย 3 ครั้ง
# - ทดสอบ rm pattern ด้วย ls / echo ก่อน: ls *.log → rm *.log18. Productivity Tips
คนที่ทำงานบน terminal คล่องจะเร็วกว่าหลายเท่าเพราะรู้ "ทางลัด" — การค้นประวัติคำสั่ง (Ctrl+R), แป้นแก้บรรทัด, การตั้ง alias สั้น ๆ และ tmux (แบ่งหน้าจอ + รัน session ที่ไม่ตายตอน disconnect) เทคนิคกลุ่มนี้ลงทุนเรียนครั้งเดียวแต่คุ้มไปตลอด:
bash
# History — ประวัติคำสั่งที่เคยพิมพ์
history # ดูทั้งหมด
!42 # รันคำสั่งหมายเลข 42 ใน history
!! # รันคำสั่งล่าสุดอีกครั้ง
Ctrl+R # ค้นหาย้อนกลับ (reverse search) — กดแล้วพิมพ์ทีละตัว
# Edit cursor — ลัดบนบรรทัดคำสั่ง
Ctrl+A # ไปต้นบรรทัด (start of line)
Ctrl+E # ไปท้ายบรรทัด (end)
Ctrl+K # ลบจาก cursor ไปท้าย
Ctrl+U # ลบจาก cursor ไปต้นบรรทัด
Ctrl+W # ลบ word ก่อนหน้า
Alt+B # เลื่อน cursor ถอยหลังทีละ word
Alt+F # เลื่อน cursor ไปข้างหน้าทีละ word
# Multi-line — ใส่ \ ท้ายบรรทัด = ขึ้นบรรทัดใหม่แต่ยังเป็นคำสั่งเดียวกัน
# Tab completion — เติมชื่อให้อัตโนมัติ (ใช้บ่อยที่สุด!)
git che<TAB> # → git checkout
# Aliases (ใส่ใน ~/.bashrc) — ตั้งคำสั่งสั้น
alias ll='ls -la'
alias gs='git status'
alias k='kubectl'
alias dc='docker compose'
# tmux — terminal multiplexer (ตัวแบ่งหน้าจอ + เก็บ session ที่ไม่ตายเวลา disconnect)
tmux # เปิด session ใหม่
Ctrl+B c # สร้าง window ใหม่
Ctrl+B n # ไป window ถัดไป (next)
Ctrl+B d # ออก (detach) แต่ session ยังรันอยู่
tmux attach # กลับเข้า session เดิม (reattach)19. Modern Tools to Consider
เครื่องมือคลาสสิก (cat/ls/grep/find) ใช้ได้ดีและมีอยู่ทุกเครื่อง แต่บนเครื่องที่คุณคุมเองมีเวอร์ชันใหม่ที่เร็วกว่า สวยกว่า ใช้ง่ายกว่า — กลุ่มนี้ติดตั้งเสริมได้ ไม่บังคับ แต่ช่วยให้ทำงานประจำวันลื่นขึ้นมาก (เช่น bat, fzf, ripgrep):
bash
# ทดแทนเครื่องมือ classic ด้วยตัวที่ทันสมัยกว่า (ติดตั้งเสริม)
bat # cat ที่มี syntax highlight (เน้นสี code)
eza / lsd # ls ที่มีสี + icon (eza = fork ของ exa, exa หยุดพัฒนาตั้งแต่ปี 2023)
fd / fdfind # ทดแทน find (ใช้ regex, syntax สั้น) — บน Ubuntu/Debian = fdfind
rg (ripgrep) # ทดแทน grep — เร็วกว่า, default ignore .gitignore
fzf # fuzzy finder — ค้นหาแบบพิมพ์ผิดก็เจอ
zoxide # ทดแทน cd — จำ directory ที่เคยไปบ่อย (`z foo`)
btop # ทางเลือกของ htop — UI ดีกว่า, ดู GPU/network ได้
delta # ทำให้ git diff สวยขึ้น
direnv # โหลด env variable ตาม directory อัตโนมัติ20. Troubleshooting Workflow
เวลาแอปบน production มีปัญหา อย่าสุ่มลองมั่ว — มี "ลำดับการตรวจ" ที่ช่วยให้หาสาเหตุได้เร็วและเป็นระบบ ไล่จากเช็คสถานะ service → ดู log → เช็คทรัพยากร → network → process → config การทำตามลำดับนี้รวมคำสั่งทั้งบทมาใช้จริงในสถานการณ์ฉุกเฉิน:
Production issue → ทำตามนี้:
text
1. เช็คสถานะ service (Check status)
systemctl status myapp
curl localhost:8080/health
2. ดู log ล่าสุด + ไหลตามสด (last + tail)
journalctl -u myapp -n 100
tail -f /var/log/myapp.log
3. เช็คทรัพยากร (CPU/RAM/disk)
top / htop
df -h
free -h
4. เช็ค network (port เปิดไหม, เรียกได้ไหม)
ss -tlnp
curl localhost:8080
5. เช็ค process (process รันอยู่จริงไหม)
ps aux | grep myapp
6. ตรวจ config (Inspect config)
cat /etc/myapp/config.yml
7. ถ้าตันจริง ๆ:
strace -p <PID> # ดู system call ที่ process กำลังเรียก (process ค้างที่อะไร?)
restart # restart เป็นทางสุดท้าย — ทำให้หลักฐานหาย, debug ต่อยาก21. Checkpoint
🛠️ Checkpoint 1.1 — Basic Navigation
ลองทำเองบน Linux:
- ค้นหาไฟล์
.logขนาดเกิน 10MB ใน/var/logทั้งหมด - นับจำนวนบรรทัด ERROR ในแต่ละไฟล์
- จาก access.log — แสดง 3 อันดับ IP ที่เรียกเข้ามาบ่อยที่สุด
💡 ถ้า
/var/logว่างเปล่าบน WSL2 (ปกติมาก) ให้ลองหาใน/var/log/apt/แทน หรือสร้างไฟล์ทดสอบขนาดใหญ่เองด้วย:dd if=/dev/urandom of=/tmp/test.log bs=1M count=15
🛠️ Checkpoint 1.2 — Permissions
- สร้าง (Create)
secret.txtที่อ่านเฉพาะ owner - สร้าง (Create)
shared/ที่ group user share เขียนได้ - ทดสอบ (Test) ด้วย user อื่น
🛠️ Checkpoint 1.3 — Shell Script
เขียน script:
- รับ argument ที่ 1 เป็น directory
- ค้นหาไฟล์ PDF ทั้งหมดใน directory นั้น
- เรียงตามขนาดจากมากไปน้อย (Sort by size descending)
- แสดง 10 อันดับแรก + รวมขนาดทั้งหมด (Print top 10 + total size)
🛠️ Checkpoint 1.4 — SSH Setup
- สร้าง (Generate) key แบบ ed25519
- คัดลอก key ไปยัง remote VPS (หรือ Docker
ubuntucontainer บนเครื่อง) - ตั้งค่า alias ใน
~/.ssh/config - ล็อกอินโดยไม่ต้องใส่รหัสผ่าน (Login without password)
🛠️ Checkpoint 1.5 — Cron + systemd
- Cron: backup database daily 3 AM, keep 7 days
- systemd: create service for your app (auto-restart)
- Verify journalctl logs
21.5 ต่อยอด — Linux ขั้นสูง
หลังจบบทนี้ ถ้าอยากลึกขึ้น:
| หัวข้อ | เริ่มที่ |
|---|---|
| เข้าใจ kernel (แกนกลาง OS) | man syscalls, strace (ดู system call ที่โปรแกรมเรียก), หนังสือ The Linux Programming Interface (Kerrisk) |
| Performance tuning (ปรับจูนประสิทธิภาพ) | perf, bpftrace, eBPF (extended Berkeley Packet Filter — รัน sandboxed program ใน kernel ใช้เก็บ metric/trace แบบ live โดยไม่ต้องแก้ kernel) — มาตรฐานของ observability + security ใน 2026 |
| Networking ลึก | ip, tc (traffic control), iptables/nftables (firewall), network namespace |
| Container internals | namespace + cgroup (รากฐานของ Docker) → ดูบท Docker |
| Security hardening (เสริมความปลอดภัย) | SELinux (Security-Enhanced Linux, MAC ของ Red Hat), AppArmor (MAC ของ Ubuntu), auditd, CIS Benchmark (มาตรฐาน hardening จาก Center for Internet Security) |
| shell scripting ขั้นสูง | bash complete reference, fish/zsh, นิยมเปลี่ยนไป Python/Go เมื่อ script เกิน 100 บรรทัด |
หนังสือแนะนำ:
- The Linux Command Line (William Shotts) — ฟรี, ดีที่สุดสำหรับมือใหม่
- How Linux Works (Brian Ward) — เข้าใจว่า OS ทำงานยังไง
- Linux Performance (Brendan Gregg) — สำหรับ production debugging
22. สรุปบท
ทบทวนสิ่งที่ได้เรียนในบทนี้ — ทักษะ Linux และ shell พื้นฐานทั้งหมดที่ DevOps ต้องใช้ ตั้งแต่เดินดูระบบไฟล์ จัดการ process จนถึงเขียน script และ SSH เข้าเซิร์ฟเวอร์:
✅ โครงสร้างไฟล์ของ Linux (filesystem hierarchy): /etc = config, /var/log = log, /home = user
✅ จัดการไฟล์ (File ops): cp/mv/rm (คัดลอก/ย้าย/ลบ), find (หาไฟล์), grep (ค้นเนื้อหา), tail -f (ดู log สด)
✅ Permission (สิทธิ์): rwx + chmod + chown — แบ่งเป็น owner/group/others
✅ Process (โปรเซส): ps, top/htop, kill, &, nohup, jobs
✅ Redirection (เปลี่ยนทาง output): >, >>, <, |, 2>&1
✅ ประมวลผลข้อความ (text processing): sort, uniq, cut, awk, sed
✅ เครือข่าย (network): curl, ss, dig, ssh, scp, rsync
✅ Environment variables + dotfiles (~/.bashrc)
✅ Shell scripting: #!/bin/bash, set -euo pipefail, functions
✅ SSH key-based auth + config file + port forwarding
✅ systemd service + journalctl + cron
✅ เครื่องมือใหม่ (bat, rg, fd, fzf) — เพิ่มความเร็วการทำงาน