← สารบัญบทเรียน M14 · Containers (Podman)
M14 · บทปิดท้าย

Containers ด้วย Podman

บทสุดท้ายแล้ว! เราจะมารู้จัก “container” — กล่องที่ห่อแอปพร้อมทุกอย่างที่มันต้องใช้ แล้วเอาไปรันที่ไหนก็ได้ และจะปิดท้ายด้วยลูกเล่นเด็ด: ทำให้ container เปิดเองอัตโนมัติทุกครั้งที่บูตเครื่อง

🌱 อ่านต่อจาก M1–M13 ได้สบาย ไม่ต้องมีพื้นฐาน container มาก่อน

1Container คืออะไร

ลองนึกถึงปัญหาคลาสสิกของโปรแกรมเมอร์: เขียนแอปบนเครื่องตัวเองรันได้สวยงาม พอเอาไปลงเครื่องเพื่อนหรือเซิร์ฟเวอร์จริง — พังหมด! เพราะเวอร์ชัน library ไม่ตรง ขาดไฟล์โน่นนี่ ตั้งค่าคนละแบบ “แต่บนเครื่องผมรันได้นะ” คือประโยคในตำนาน

Container เกิดมาเพื่อแก้ปัญหานี้ — มันคือ กล่องที่ห่อแอปพร้อมทุกอย่างที่แอปต้องใช้ (โค้ด, library, ไฟล์ตั้งค่า, runtime) ไว้ด้วยกัน พอเอากล่องนี้ไปเปิดที่เครื่องไหนก็ตาม มันจะรันได้เหมือนกันเป๊ะ

💡 เปรียบเทียบให้เห็นภาพ

นึกถึง กล่องข้าวที่ห่อกับข้าวมาครบชุด — มีข้าว มีกับ มีช้อนส้อม มีน้ำจิ้ม ครบในกล่องเดียว เปิดที่ไหนก็กินได้เลย ไม่ต้องวิ่งหาเครื่องปรุงใหม่ ไม่ต้องกลัวว่า “บ้านนี้ไม่มีน้ำปลา”

หรืออีกภาพหนึ่ง: ตู้คอนเทนเนอร์ขนส่งสินค้า ที่มีขนาดมาตรฐานเดียวกันทั้งโลก เรือลำไหน รถบรรทุกคันไหน เครนตัวไหน ก็ยกได้หมด ข้างในจะเป็นรองเท้าหรือกล้วยก็ไม่สำคัญ — “กล่องข้างนอกมาตรฐานเดียวกัน” คือหัวใจ (คำว่า container ก็มาจากตู้ขนส่งนี่แหละ)

แล้วต่างจาก VM (Virtual Machine) ยังไง?

หลายคนเคยได้ยิน VM — เครื่องเสมือนที่จำลองคอมพิวเตอร์ทั้งเครื่องขึ้นมา ทั้งสองอย่างนี้ช่วย “แยกแอปออกจากกัน” ได้เหมือนกัน แต่หนักเบาต่างกันมาก

VMContainer
จำลองอะไรทั้งเครื่อง + ระบบปฏิบัติการเต็มตัวแค่แอป + ของที่แอปต้องใช้
ขนาดหนักเป็น GBเบา มักหลัก MB
เปิดเร็วแค่ไหนเป็นนาที (ต้องบูต OS)เป็นวินาที
ใช้ kernelของตัวเองใช้ของเครื่อง host ร่วมกัน
💡 เทียบกันแบบบ้านๆ

VM = สร้างบ้านใหม่ทั้งหลัง (มีฐานราก หลังคา ระบบไฟ ครบทุกอย่าง) ส่วน Container = เช่าห้องในคอนโด ที่ใช้โครงสร้างตึก (kernel) ร่วมกัน — แค่กั้นห้องส่วนตัวให้แต่ละแอปอยู่ จึงเบากว่าและเปิดเร็วกว่ามาก

2Podman คืออะไร — และ “rootless”

ในโลก container เครื่องมือที่ดังที่สุดคือ Docker แต่ บน RHEL 9 (และ Red Hat) เราใช้ Podman ไม่ใช่ Docker — ข้อสอบ RHCSA ก็ถาม Podman ดังนั้นบทนี้เราโฟกัสที่ Podman

ข่าวดีคือคำสั่ง Podman เกือบทั้งหมด พิมพ์เหมือน Docker เป๊ะ แค่เปลี่ยนคำว่า docker เป็น podman ใครเคยใช้ Docker มาก็ใช้ Podman ได้ทันที

📌 จุดเด่นที่สุดของ Podman: rootless

Podman รันได้โดย user ธรรมดา (ไม่ต้องเป็น root!) — เราเรียกว่า rootless container

ทำไมถึงสำคัญ? เพราะถ้า container โดนเจาะ คนร้ายก็ได้แค่สิทธิ์ของ user ธรรมดาคนนั้น ไม่ได้สิทธิ์ root ของทั้งเครื่อง — ปลอดภัยกว่าแบบที่ต้องรันเป็น root มาก นี่คือเหตุผลใหญ่ที่ Red Hat เลือก Podman

💡 ทำไม rootless ปลอดภัยกว่า

เหมือนให้พนักงานคนหนึ่ง กุญแจห้องตัวเองดอกเดียว แทนที่จะให้ กุญแจมาสเตอร์ที่เปิดได้ทุกห้อง — ถ้ากุญแจหลุดมือไป ความเสียหายก็จำกัดอยู่แค่ห้องเดียว ไม่ลามทั้งตึก

💡 อีกข้อดี: ไม่มี daemon

Docker ต้องมีโปรเซสตัวกลางชื่อ daemon รันค้างเป็น root ตลอดเวลา แต่ Podman ไม่มี daemon — สั่ง podman run ทีไรมันก็รัน container ขึ้นมาตรงๆ จึงเรียบง่ายและปลอดภัยกว่า

3หา & ดึง image มาเก็บไว้

ก่อนจะรัน container ได้ เราต้องมี image ก่อน — image คือ “แม่พิมพ์” หรือ “พิมพ์เขียว” ของ container ส่วน container คือตัวที่ถูกปั๊มออกมาจากแม่พิมพ์นั้นแล้วกำลังทำงานอยู่

💡 image กับ container ต่างกันยังไง

image = สูตรขนม + วัตถุดิบที่บรรจุไว้ (อ่านอย่างเดียว เปลี่ยนไม่ได้) ส่วน container = ขนมที่อบเสร็จออกมาจากสูตรนั้น — จาก image เดียวจะปั๊ม container ออกมากี่ตัวก็ได้ เหมือนสูตรเดียวอบขนมได้หลายถาด

podman search — ค้นหา image

⌨️ ลองดู
[student@server1 ~]$ podman search nginx
NAME                              DESCRIPTION
registry.access.redhat.com/...   Nginx web server ...
docker.io/library/nginx          Official build of Nginx

ค้นหา image ชื่อ nginx จาก registry ที่เครื่องเรารู้จัก คอลัมน์ NAME คือชื่อเต็มที่เอาไปใช้ pull ต่อได้

podman pull — ดึง image ลงมาเก็บในเครื่อง

⌨️ ลองดู
[student@server1 ~]$ podman pull registry.access.redhat.com/ubi9/httpd-24
Trying to pull registry.access.redhat.com/ubi9/httpd-24:latest...
Getting image source signatures
Writing manifest to image destination
Storing signatures

รูปแบบชื่อ image เต็มๆ คือ registry/ชื่อ:tag

registry...ที่อยู่ของคลัง image (เช่น registry.access.redhat.com)
ubi9/httpd-24ชื่อ image (UBI = Universal Base Image ของ Red Hat)
:tagเวอร์ชัน เช่น :latest ถ้าไม่ใส่จะเดาเป็น :latest ให้

podman images — ดูว่ามี image อะไรในเครื่องบ้าง

⌨️ ลองดู
[student@server1 ~]$ podman images
REPOSITORY                                  TAG      IMAGE ID      SIZE
registry.access.redhat.com/ubi9/httpd-24    latest   3f2a1b...     461 MB

แสดงรายการ image ที่ดึงมาเก็บไว้แล้ว (เหมือน ls แต่สำหรับ image)

4Registry มาจากไหน

เวลาเราพิมพ์ podman search nginx เฉยๆ ไม่ได้ระบุที่อยู่เต็ม Podman จะรู้ได้ยังไงว่าควรไปค้นที่คลังไหน? คำตอบอยู่ในไฟล์ตั้งค่า

Registry
คลังเก็บ image บนอินเทอร์เน็ต (หรือในองค์กร) ที่เราดึง image ลงมาใช้ เช่น registry.access.redhat.com, docker.io

ไฟล์ที่กำหนดว่า registry ไหนเชื่อถือได้และค้นเรียงตามลำดับไหน คือ:

📄 /etc/containers/registries.conf
# รายชื่อ registry ที่จะค้นหา เรียงตามลำดับ
unqualified-search-registries = ["registry.access.redhat.com", "docker.io"]

บรรทัด unqualified-search-registries บอกว่า ถ้าเราพิมพ์ชื่อ image แบบไม่เต็ม (เช่น แค่ nginx) ให้ไปค้นที่ registry ในลิสต์นี้ เรียงทีละตัว

📌 จำพอเป็นแนว

ไฟล์ตั้งค่าระดับเครื่องอยู่ที่ /etc/containers/registries.conf ส่วนของ user แต่ละคนอยู่ที่ ~/.config/containers/registries.conf — ในห้องสอบมักไม่ต้องแก้ไฟล์นี้ลึก แต่ควร รู้ว่ามันอยู่ไหนและมีไว้ทำอะไร

5รัน container: podman run

คำสั่งหัวใจของบทนี้ มี option เยอะแต่ค่อยๆ ทำความเข้าใจทีละตัว มาดูตัวอย่างจริงที่ใช้ option สำคัญครบ

⌨️ รัน web server ตัวอย่าง
[student@server1 ~]$ podman run -d --name web1 \
  -p 8080:80 \
  -v ~/webdata:/var/www/html:Z \
  -e MY_VAR=hello \
  registry.access.redhat.com/ubi9/httpd-24
a1b2c3d4e5f6...  ← container ID ที่ได้คืนมา

แปล option ทีละตัว — เครื่องหมาย \ ท้ายบรรทัดแปลว่า “ยังไม่จบ บรรทัดถัดไปคือคำสั่งเดียวกัน” (ช่วยให้อ่านง่าย):

-ddetached = รันค้างอยู่ เบื้องหลัง ไม่ยึดหน้าจอเรา (ถ้าไม่ใส่ มันจะค้างที่หน้าจอจนกว่าจะกด Ctrl+C)
--name web1ตั้งชื่อ container ว่า web1 เพื่อให้เรียกใช้ง่าย ถ้าไม่ตั้ง Podman จะสุ่มชื่อแปลกๆ ให้
-p 8080:80map port host:container = ใครเข้า port 8080 ของเครื่อง host จะถูกส่งต่อไป port 80 ในตัว container
-v ~/webdata:/var/www/html:Zmap โฟลเดอร์ host:container — ดูข้อ 7 และอย่าลืม :Z สำหรับ SELinux!
-e MY_VAR=helloส่ง environment variable เข้าไปใน container (ดูข้อ 8)
💡 เรื่อง map port (-p)

นึกถึง ตู้ ปณ. หน้าบ้าน — container ซ่อนอยู่ในบ้าน ไม่มีใครเข้าถึงได้ตรงๆ -p 8080:80 ก็เหมือนติดป้ายว่า “จดหมายที่ส่งมาที่ตู้เลข 8080 หน้าบ้าน ให้เอาไปส่งห้องเลข 80 ข้างใน” — โลกภายนอกเคาะที่ 8080 ของ host ของจริงทำงานที่ 80 ข้างใน container

6จัดการ container ที่รันอยู่

พอมี container แล้ว เราต้องดูแลมันเป็น — ดูว่ามีตัวไหนรันอยู่ หยุด เปิดใหม่ ลบ ดู log และมุดเข้าไปข้างใน

⌨️ คำสั่งดูแล container ที่ใช้บ่อย
[student@server1 ~]$ podman ps
CONTAINER ID  IMAGE          STATUS         NAMES
a1b2c3d4e5f6  .../httpd-24   Up 2 minutes   web1

[student@server1 ~]$ podman ps -a
(แสดงทั้งหมด รวมตัวที่หยุดไปแล้วด้วย)

[student@server1 ~]$ podman stop web1
[student@server1 ~]$ podman start web1
[student@server1 ~]$ podman logs web1
[student@server1 ~]$ podman rm web1
podman psดู container ที่ กำลังรันอยู่ (เทียบได้กับ ls ของ container)
podman ps -aดู ทั้งหมด รวมตัวที่หยุดไปแล้ว (-a = all)
podman stop web1หยุด container (มันยังอยู่ แค่ไม่ทำงาน)
podman start web1เปิด container ที่หยุดไว้ให้กลับมาทำงาน
podman logs web1ดู log / ข้อความที่ container พ่นออกมา — ใช้เวลามันพัง อยากรู้ว่าเกิดอะไรขึ้น
podman rm web1ลบ container ทิ้ง (ต้อง stop ก่อน หรือใช้ rm -f บังคับ)

podman exec — มุดเข้าไปข้างใน container

บางทีเราอยากเข้าไป “ข้างในกล่อง” เพื่อดูไฟล์หรือแก้อะไรสักอย่าง ใช้ exec -it ... bash

⌨️ ลองดู
[student@server1 ~]$ podman exec -it web1 bash
bash-5.1$ ls /var/www/html
index.html
bash-5.1$ exit   ← พิมพ์ exit เพื่อออกกลับมาที่เครื่อง host
execสั่งให้รันคำสั่งหนึ่ง ภายใน container ที่กำลังรันอยู่
-it-i interactive + -t terminal = ขอ shell แบบโต้ตอบได้ (พิมพ์–เห็นผลทันที)
bashคำสั่งที่อยากรันข้างใน — ในที่นี้คือเปิด shell bash เพื่อพิมพ์คำสั่งต่อ

7เก็บข้อมูลไม่ให้หาย (Persistent Storage)

นี่คือเรื่องสำคัญที่มือใหม่มักสะดุด: container เป็นของชั่วคราว — พอลบ container ทิ้ง ข้อมูลที่อยู่ ข้างใน มันก็หายไปด้วยทั้งหมด!

💡 ทำไมข้อมูลหาย

container เหมือน ห้องพักโรงแรม — เช็คเอาท์ (ลบ container) เมื่อไหร่ ของที่วางไว้ในห้องก็ถูกเก็บกวาดหมด ถ้าอยากเก็บของไว้ ต้อง ฝากไว้ในเซฟของโรงแรมที่อยู่นอกห้อง (= โฟลเดอร์บนเครื่อง host) ของในเซฟจะอยู่ต่อแม้คุณเช็คเอาท์ไปแล้ว

วิธีฝากข้อมูลไว้นอก container คือ bind mount ด้วย option -v — เอาโฟลเดอร์จากเครื่อง host ไป “ผูก” กับโฟลเดอร์ใน container เมื่อ container เขียนข้อมูล มันจะไปลงที่โฟลเดอร์ host จริงๆ ลบ container ทิ้งข้อมูลก็ยังอยู่

⌨️ ผูกโฟลเดอร์ host เข้ากับ container
[student@server1 ~]$ mkdir ~/webdata
[student@server1 ~]$ podman run -d --name web1 \
  -p 8080:80 \
  -v ~/webdata:/var/www/html:Z \
  registry.access.redhat.com/ubi9/httpd-24

อ่านค่า -v เป็น 3 ส่วน คั่นด้วย :โฟลเดอร์host : โฟลเดอร์ในcontainer : ตัวเลือก

~/webdataโฟลเดอร์จริงบนเครื่อง host (ข้อมูลตัวจริงเก็บที่นี่)
/var/www/htmlจุดที่ container จะเห็นโฟลเดอร์นั้น
:Zสำคัญมาก! สั่งให้ Podman ปรับ SELinux label ให้ container เข้าถึงโฟลเดอร์นี้ได้
🎯 อย่าลืม :Z เด็ดขาด (โยงกับ M12 เรื่อง SELinux)

จำได้ไหมว่า RHEL เปิด SELinux ไว้เป็นยาม ถ้าเราเอาโฟลเดอร์ host ใส่เข้า container โดยไม่เติม :Z SELinux จะมอง label ไม่ตรงแล้ว บล็อกไม่ให้ container อ่าน/เขียน ผลคือเว็บขึ้น “Permission denied” ทั้งที่สิทธิ์ไฟล์ดูปกติดี

เติม :Z ต่อท้าย แล้ว Podman จะ relabel โฟลเดอร์นั้นให้อัตโนมัติ — นี่คือกับดักยอดฮิตในห้องสอบ

💡 z เล็ก กับ Z ใหญ่

:Z (ใหญ่) = label แบบ เฉพาะ container นี้ตัวเดียว ใช้ตัวนี้เป็นค่ามาตรฐาน ส่วน :z (เล็ก) = แชร์ให้หลาย container ใช้ร่วมกันได้ ตอนเริ่มต้นจำแค่ :Z ใหญ่ก็พอ

8ส่งค่าตั้งต้นด้วย Environment Variables

หลาย image ต้องการค่าตั้งต้นตอนเปิด เช่น image ฐานข้อมูลอาจอยากได้ชื่อ database หรือรหัสผ่าน admin เราป้อนค่าพวกนี้ผ่าน option -e (environment)

⌨️ ส่งหลายค่าด้วย -e ซ้ำได้
[student@server1 ~]$ podman run -d --name db1 \
  -e POSTGRESQL_USER=appuser \
  -e POSTGRESQL_PASSWORD=secret123 \
  -e POSTGRESQL_DATABASE=appdb \
  registry.redhat.io/rhel9/postgresql-15

แต่ละ -e ชื่อ=ค่า คือตัวแปร 1 ตัวที่ถูกส่งเข้าไปใน container อยากใส่กี่ตัวก็เติม -e ซ้ำได้ — แอปข้างใน container จะอ่านค่าพวกนี้ไปตั้งค่าตัวเองตอนเริ่มทำงาน

💡 environment variable คืออะไร

เหมือน โพสต์อิทแปะหน้ากล่อง ก่อนส่งกล่องเข้าไปทำงาน เช่น “ผู้ใช้ชื่อ appuser, รหัส secret123” — พอ container เปิดขึ้นมา มันอ่านโพสต์อิทพวกนี้แล้วเซ็ตตัวเองตามนั้น โดยที่เราไม่ต้องเข้าไปแก้ไฟล์ข้างในเลย

💡 อยากดูค่าที่ส่งไปแล้ว

มุดเข้าไปด้วย podman exec -it db1 env จะเห็นรายการ environment variable ทั้งหมดที่ container ตัวนั้นมองเห็น

9⭐ ให้ container เปิดเองทุกครั้งที่บูต

นี่คือ หัวใจของบทนี้และออกสอบแน่นอน — ปัญหาคือ ถ้าเซิร์ฟเวอร์รีบูต container ที่เราเปิดไว้จะ ไม่เด้งกลับมาเอง เราต้องสั่งให้ระบบเปิดมันให้อัตโนมัติ วิธีของ RHEL 9 คือผูก container เข้ากับ systemd (ตัวจัดการ service ที่เราเรียนมาแล้วใน M9)

เนื่องจาก Podman เรารันแบบ rootless (user ธรรมดา) เราจึงใช้ systemd ระดับ user คือ systemctl --user ทำตาม 4 ขั้นนี้

ขั้น 1 — สร้างไฟล์ .service จาก container ที่มีอยู่

⌨️ generate ไฟล์ service
[student@server1 ~]$ mkdir -p ~/.config/systemd/user
[student@server1 ~]$ cd ~/.config/systemd/user
[student@server1 user]$ podman generate systemd --name web1 --files --new
/home/student/.config/systemd/user/container-web1.service
generate systemdให้ Podman เขียนไฟล์ systemd service ให้เราอัตโนมัติ ไม่ต้องเขียนเอง
--name web1อ้างถึง container ชื่อ web1 ที่เราสร้างไว้
--filesให้เขียนออกมาเป็น ไฟล์ (ในโฟลเดอร์ปัจจุบัน) แทนที่จะพ่นบนจอเฉยๆ
--newให้ service สร้าง container ใหม่ ทุกครั้งที่เริ่ม (แนะนำ — ทำให้ย้ายเครื่อง/ทำซ้ำได้ง่าย)
📌 ไฟล์ user service อยู่ที่ไหน

service ระดับ user เก็บที่ ~/.config/systemd/user/ — ถ้า generate จากที่อื่น ให้ คัดลอกไฟล์ .service มาไว้ในโฟลเดอร์นี้ systemd ถึงจะมองเห็น

ขั้น 2 — โหลดค่าใหม่ แล้ว enable ให้เริ่มอัตโนมัติ

⌨️ daemon-reload & enable
[student@server1 ~]$ systemctl --user daemon-reload
[student@server1 ~]$ systemctl --user enable --now container-web1.service
Created symlink .../container-web1.service ...
--userสั่งกับ systemd ระดับ user ของเรา (ไม่ใช่ระดับทั้งระบบ — ห้ามลืม!)
daemon-reloadบอก systemd ว่า “มีไฟล์ service ใหม่นะ ไปอ่านซะ”
enable --nowenable = เปิดเองทุกครั้งที่บูต + --now = เริ่มรันเดี๋ยวนี้เลยด้วย

ขั้น 3 — ⭐ เปิด linger ให้ user (ขั้นที่คนลืมบ่อยที่สุด!)

⌨️ enable-linger
[student@server1 ~]$ loginctl enable-linger student
[student@server1 ~]$ loginctl show-user student | grep Linger
Linger=yes

โดยปกติ service ระดับ user จะรัน ก็ต่อเมื่อ user คนนั้นล็อกอินอยู่ เท่านั้น พอ logout ออก service (และ container) ก็ดับตามไปด้วย — แปลว่าหลังรีบูตที่ยังไม่มีใคร login เข้ามา container จะ ไม่ขึ้น!

loginctl enable-linger student สั่งให้ระบบ ยอมให้ service ของ user คนนี้รันต่อแม้ไม่ได้ login — นี่แหละที่ทำให้ container เด้งขึ้นเองหลังบูต

🎯 ลืม enable-linger = สอบตกข้อนี้

ทำครบทุกอย่างแต่ ลืม loginctl enable-linger คือกับดักอันดับหนึ่งของข้อนี้! เพราะตอนทดสอบมือ (ขณะ login อยู่) มันทำงานปกติ ดูเหมือนถูกหมด — แต่พอ รีบูต เครื่องตรวจคำตอบ container กลับไม่ขึ้น เพราะไม่มีใคร login → คะแนนหาย

กฎจำง่าย: “rootless container เปิดตอนบูต ต้องคู่กับ enable-linger เสมอ”

ขั้น 4 — รีบูตทดสอบให้ชัวร์

⌨️ ทดสอบของจริง
[student@server1 ~]$ sudo reboot
(รอเครื่องบูตเสร็จ แล้ว login ใหม่)
[student@server1 ~]$ podman ps
CONTAINER ID  IMAGE         STATUS        NAMES
a1b2c3d4e5f6  .../httpd-24  Up 30 seconds web1  ← ขึ้นเองแล้ว!

ถ้า podman ps หลังรีบูตเห็น container ขึ้นเอง = สำเร็จ! ในห้องสอบ ควรรีบูตทดสอบจริง อย่าเชื่อแค่ว่า “ตอนนี้รันอยู่” เพราะข้อสอบจะตรวจหลังรีบูต

10ข้อผิดพลาดที่เจอบ่อย

11สรุปคำสั่งบทนี้ (Cheat Sheet)

คำสั่งทำอะไร
podman search ชื่อค้นหา image จาก registry
podman pull registry/image:tagดึง image ลงมาเก็บในเครื่อง
podman imagesดู image ที่มีในเครื่อง
podman run -d --name x imageรัน container เบื้องหลัง พร้อมตั้งชื่อ
-p 8080:80map port host:container
-v /host:/ctr:Zmap โฟลเดอร์ (อย่าลืม :Z เรื่อง SELinux)
-e VAR=ค่าส่ง environment variable เข้า container
podman ps / ps -aดู container ที่รันอยู่ / ทั้งหมด
podman stop x / start xหยุด / เปิด container
podman rm xลบ container ทิ้ง
podman logs xดู log ของ container
podman exec -it x bashมุดเข้าไปใน container เปิด shell
podman generate systemd --name x --files --newสร้างไฟล์ .service ของ container
systemctl --user daemon-reloadให้ systemd อ่านไฟล์ service ใหม่
systemctl --user enable --now container-x.serviceเปิดอัตโนมัติตอนบูต + เริ่มเดี๋ยวนี้
loginctl enable-linger user⭐ ให้ user service รันแม้ไม่ได้ login
✅ จบบทนี้คุณควรทำได้

ดึง image ลงมา (pull) → รัน container พร้อม map port/volume/env (run) → ดูแลมัน (ps/stop/logs/exec) → เก็บข้อมูลไม่ให้หายด้วย volume + :Z → และทำให้ container เปิดเองหลังบูต ด้วย systemd user service + enable-linger ครบสูตรออกสอบ!

🎓 ยินดีด้วย — คุณเรียนครบทุกบทแล้ว!

จาก M1 ที่ยัง “กลัวหน้าจอดำๆ” มาจนถึง M14 ที่ทำ container เปิดเองตอนบูตได้ — คุณเดินทางมาไกลมาก! ตอนนี้คุณมีพื้นฐาน RHCSA ครบทั้งหลักสูตรแล้ว

ก้าวต่อไป: ลงมือทำ lab จริงซ้ำๆ ให้มือจำคำสั่งได้เอง แล้วลอง mock exam จับเวลา 3 ชั่วโมงเหมือนสอบจริง ยิ่งฝึกบนเครื่องจริงมากเท่าไหร่ วันสอบยิ่งสบายเท่านั้น โชคดีนะ! 🚀