คอร์สพื้นฐาน Docker และ Kubernetes
คอร์สระดับกลางที่มีโครงสร้างครอบคลุม Docker image, คอนเทนเนอร์, วอลุ่ม, เครือข่าย, Compose และ Kubernetes workload, บริการ, พื้นที่จัดเก็บ และการแก้ไขปัญหา
สิ่งที่คุณจะได้เรียนรู้
- สร้างและปรับแต่ง Docker image ด้วย Dockerfile
- รันและตรวจสอบคอนเทนเนอร์และเก็บข้อมูลถาวรด้วยวอลุ่ม
- เชื่อมต่อคอนเทนเนอร์ด้วยเครือข่าย Docker และ Compose
- ปรับใช้ Kubernetes workload หลักด้วย ConfigMap และ Secret
- เปิดเผยแอปพลิเคชันและแก้ไขปัญหาคลัสเตอร์ Kubernetes
ก่อนเริ่มเรียน
- มีประสบการณ์พื้นฐานกับคำสั่ง Linux
- คุ้นเคยกับ HTTP พอร์ต และการติดตั้งแอปพลิเคชัน
- แบบฝึก Docker และ Kubernetes มีประโยชน์สำหรับการประเมินตนเอง
บทเรียน 1 Docker image และ Dockerfile
อิมเมจ Docker คือเทมเพลตแบบอ่านอย่างเดียวที่บรรจุแอปพลิเคชัน รันไทม์ ไลบรารี และการกำหนดค่าไว้ด้วยกัน อิมเมจถูกสร้างจาก Dockerfile โดยใช้เลเยอร์: คำสั่งแต่ละคำสั่ง เช่น FROM, COPY, RUN หรือ ENV จะสร้างเลเยอร์หนึ่งชั้น และเลเยอร์ที่ไม่มีการเปลี่ยนแปลงจะถูกแคชไว้เพื่อให้การสร้างใหม่เร็วขึ้น อิมเมจที่เล็กกว่าและปลอดภัยกว่าควรใช้เบสอิมเมจที่น้อยที่สุด รวมคำสั่ง RUN ที่เกี่ยวข้อง และคัดลอกเฉพาะไฟล์ที่แอปพลิเคชันต้องการ
คำสั่ง FROM ใช้เลือกเบสอิมเมจ COPY ย้ายไฟล์จาก build context เข้าไปในอิมเมจ ขณะที่ RUN ใช้รันคำสั่งระหว่างการสร้าง CMD ระบุคำสั่งและอาร์กิวเมนต์เริ่มต้นที่ใช้เมื่อคอนเทนเนอร์เริ่มทำงาน และ ENTRYPOINT กำหนดไฟล์ปฏิบัติการที่จะรันเสมอ เมื่อมีทั้งสองอย่าง เอ็นทรีพอยต์จะรับอาร์กิวเมนต์จากบรรทัดคำสั่งเป็นพารามิเตอร์ คุณสามารถเพิ่มการตรวจสุขภาพด้วย HEALTHCHECK หรือผู้ใช้ที่ไม่ใช่ root ด้วย USER ได้
ใช้คำสั่ง docker build -t myapp:latest . เพื่อสร้างอิมเมจ และใช้ docker image ls เพื่อแสดงรายการอิมเมจ ตั้งแท็กอิมเมจด้วยหมายเลขเวอร์ชันที่มีความหมาย และหลีกเลี่ยงการใช้ latest เพียงอย่างเดียวในระบบ production เป้าหมายคืออิมเมจที่กำหนดผลลัพธ์ได้ แน่นอน เล็ก และสามารถสร้างซ้ำได้จาก Dockerfile เพียงอย่างเดียว
เคล็ดลับฝึกฝน Docker image และ Dockerfile: ทบทวนบทเรียนนี้ในเวลาสั้น ๆ ทุกวัน หลังทำแบบฝึกหัดแต่ละข้อให้บอกกฎหรือขั้นตอนที่ใช้ ถ้าบอกไม่ได้ ให้ทบทวนหัวข้อนั้นก่อนไปต่อ ความสม่ำเสมอช่วยจำได้ดีกว่าการอ่านนาน ๆ ครั้งเดียว
ตัวอย่าง
แอปพลิเคชัน Node.js ต้องการเพียงไฟล์ package สำหรับติดตั้ง dependencies และซอร์สโค้ดสำหรับรัน Dockerfile เริ่มต้นด้วย FROM node:20-alpine คัดลอก package.json ก่อน รัน npm ci คัดลอกซอร์สโค้ด สลับไปใช้ผู้ใช้ที่ไม่ใช่ root และกำหนด CMD ["node", "server.js"] การคัดลอก dependencies ก่อนซอร์สโค้ดทำให้ Docker นำเลเยอร์ dependencies กลับมาใช้ใหม่ได้จนกว่าไฟล์ package จะเปลี่ยน
อ่านคำถามอีกครั้งก่อนจบ และตรวจสอบว่าคำตอบตรงกับสิ่งที่ถาม
บทเรียน 2 วงจรชีวิตคอนเทนเนอร์และพื้นที่จัดเก็บถาวร
คอนเทนเนอร์คืออินสแตนซ์ที่กำลังทำงานของอิมเมจ Docker สร้าง เริ่ม หยุด รีสตาร์ท และลบคอนเทนเนอร์ด้วยคำสั่ง เช่น docker create, docker start, docker stop และ docker rm คำสั่งลัดที่ใช้บ่อยคือ docker run ซึ่งสร้างและเริ่มคอนเทนเนอร์ในขั้นตอนเดียว ใช้ docker ps เพื่อดูคอนเทนเนอร์ที่กำลังทำงาน ใช้ docker ps -a เพื่อรวมคอนเทนเนอร์ที่หยุดแล้ว และใช้ docker logs เพื่อตรวจสอบเอาต์พุตของแอปพลิเคชัน
ระบบไฟล์ของคอนเทนเนอร์เป็นแบบชั่วคราว: เมื่อลบคอนเทนเนอร์ การเปลี่ยนแปลงที่เขียนไว้ภายในจะหายไป วอลุ่มและ bind mount ช่วยแก้ปัญหานี้ เนมวอลุ่มถูกจัดการโดย Docker และยังคงอยู่แม้ลบคอนเทนเนอร์ ส่วน bind mount จะแมปไดเรกทอรีจากโฮสต์เข้าไปในคอนเทนเนอร์ แฟล็ก -v และ --mount ใช้แนบพื้นที่จัดเก็บ และคอนเทนเนอร์หลายตัวสามารถแชร์วอลุ่มเดียวกันได้ การเมานต์แบบอ่านอย่างเดียวช่วยป้องกันการแก้ไขโดยไม่ตั้งใจ
สำหรับการดีบัก docker exec -it container bash จะเปิดเชลล์ภายในคอนเทนเนอร์ที่กำลังทำงาน และ docker inspect แสดงรายละเอียดการกำหนดค่าและสถานะ ควรแนบนโยบาย --restart เฉพาะเมื่อแอปพลิเคชันควรกู้คืนโดยอัตโนมัติ และเก็บล็อกกับข้อมูลไว้นอกคอนเทนเนอร์เมื่อตัวคอนเทนเนอร์สามารถแทนที่ได้
เคล็ดลับฝึกฝน วงจรชีวิตคอนเทนเนอร์และพื้นที่จัดเก็บถาวร: ทบทวนบทเรียนนี้ในเวลาสั้น ๆ ทุกวัน หลังทำแบบฝึกหัดแต่ละข้อให้บอกกฎหรือขั้นตอนที่ใช้ ถ้าบอกไม่ได้ ให้ทบทวนหัวข้อนั้นก่อนไปต่อ ความสม่ำเสมอช่วยจำได้ดีกว่าการอ่านนาน ๆ ครั้งเดียว
ตัวอย่าง
คอนเทนเนอร์ฐานข้อมูลเริ่มทำงานด้วยคำสั่ง docker run -d --name postgres -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret postgres:16 เนมวอลุ่ม pgdata จะเก็บไฟล์ฐานข้อมูลไว้แม้หลัง docker rm postgres ดังนั้นคอนเทนเนอร์ทดแทนที่ใช้วอลุ่มเดียวกันจะกู้คืนข้อมูลเดิมได้
อ่านคำถามอีกครั้งก่อนจบ และตรวจสอบว่าคำตอบตรงกับสิ่งที่ถาม
บทเรียน 3 เครือข่าย Docker และ Compose
เครือข่าย Docker ให้คอนเทนเนอร์สื่อสารกันด้วยชื่อหรือ IP ได้ เครือข่าย bridge เริ่มต้นให้ DNS อัตโนมัติระหว่างคอนเทนเนอร์ในเครือข่ายเดียวกัน ขณะที่ host network แชร์ network stack ของโฮสต์และตัดการแยกส่วนออกไป แนะนำให้ใช้เครือข่าย bridge ที่ผู้ใช้กำหนดเอง เพราะรองรับการ resolve ชื่อ DNS และสามารถเชื่อมต่อหรือยกเลิกการเชื่อมต่อได้โดยไม่ต้องสร้างคอนเทนเนอร์ใหม่ เผยแพร่พอร์ตของคอนเทนเนอร์ไปยังโฮสต์ด้วย -p 8080:80 ด้านซ้ายคือพอร์ตของโฮสต์ และด้านขวาคือพอร์ตของคอนเทนเนอร์
Docker Compose กำหนดแอปพลิเคชันแบบหลายคอนเทนเนอร์ในไฟล์ YAML บริการต่าง ๆ ประกาศอิมเมจ build context พอร์ต วอลุ่ม ตัวแปรสภาพแวดล้อม และเครือข่าย การรัน docker compose up -d จะสร้างเครือข่ายและเริ่มบริการทั้งหมดพร้อมกัน ส่วน docker compose down จะลบคอนเทนเนอร์และเครือข่ายเริ่มต้น แต่ยังคงวอลุ่มที่มีชื่อไว้ Compose ยังรองรับ dependencies การตรวจสุขภาพ และการปรับจำนวน replica ของบริการ
ดีบักการเชื่อมต่อด้วย docker network ls, docker network inspect และ docker exec ปัญหาที่พบบ่อยคือเว็บคอนเทนเนอร์ไม่สามารถเข้าถึงฐานข้อมูลได้ เพราะอยู่ในเครือข่ายต่างกัน หรือเพราะแอปพลิเคชันใช้ localhost แทนชื่อบริการ ใช้ชื่อบริการใน Compose เพื่อให้ DNS ในตัว resolve ไปยังคอนเทนเนอร์ที่ถูกต้อง
เคล็ดลับฝึกฝน เครือข่าย Docker และ Compose: ทบทวนบทเรียนนี้ในเวลาสั้น ๆ ทุกวัน หลังทำแบบฝึกหัดแต่ละข้อให้บอกกฎหรือขั้นตอนที่ใช้ ถ้าบอกไม่ได้ ให้ทบทวนหัวข้อนั้นก่อนไปต่อ ความสม่ำเสมอช่วยจำได้ดีกว่าการอ่านนาน ๆ ครั้งเดียว
ตัวอย่าง
ไฟล์ compose กำหนดบริการ web และ db บริการ web แมปพอร์ต "8080:3000" และเชื่อมต่อกับฐานข้อมูลโดยใช้โฮสต์เนม db และพอร์ต 5432 บริการฐานข้อมูลเมานต์วอลุ่มที่มีชื่อและตั้งค่าการตรวจสุขภาพเมื่อเริ่มต้น การรัน docker compose up -d จะเริ่มบริการทั้งสองบนเครือข่ายส่วนตัวเดียว และเบราว์เซอร์เข้าถึงแอปได้ที่ http://localhost:8080
อ่านคำถามอีกครั้งก่อนจบ และตรวจสอบว่าคำตอบตรงกับสิ่งที่ถาม
บทเรียน 4 Kubernetes Workload หลัก
Kubernetes รันแอปพลิเคชันแบบคอนเทนเนอร์บนคลัสเตอร์ของโหนด หน่วยที่เล็กที่สุดที่สามารถปรับใช้ได้คือ Pod ซึ่งครอบคลุมคอนเทนเนอร์หนึ่งตัวหรือมากกว่าด้วยพื้นที่จัดเก็บ เครือข่าย และวงจรชีวิตที่ใช้ร่วมกัน โดยทั่วไป Pod จะถูกสร้างโดยคอนโทรลเลอร์ Deployment จัดการ replica แบบไม่เก็บสถานะด้วยการอัปเดตแบบ rolling และการย้อนกลับ StatefulSet ให้เอกลักษณ์เครือข่ายที่เสถียรและการปรับขนาดแบบมีลำดับสำหรับแอปพลิเคชันที่เก็บสถานะ DaemonSet รัน Pod หนึ่งตัวบนทุกโหนดที่เลือก Job รันเวิร์กโหลดจนเสร็จ และ CronJob รัน Job ตามกำหนดเวลา
การกำหนดค่าถูกแยกออกจากโค้ดด้วย ConfigMap และ Secret ConfigMap เก็บข้อมูลที่ไม่ละเอียดอ่อน เช่น ตัวแปรสภาพแวดล้อมหรือไฟล์กำหนดค่า ส่วน Secret เก็บค่าที่ละเอียดอ่อน เช่น รหัสผ่านและโทเคน API ทั้งสองสามารถเมานต์เป็นวอลุ่มหรือฉีดเป็นตัวแปรสภาพแวดล้อมได้ Secret ถูกเข้ารหัส base64 ใน API แต่ยังควรป้องกันด้วย RBAC และการเข้ารหัสข้อมูลขณะจัดเก็บ
คอนโทรลเลอร์ปรับสถานะให้ตรงกับสถานะที่ต้องการ: คุณประกาศจำนวน replica ที่ต้องการ และ Kubernetes จะสร้างหรือลบ Pod จนกว่าสถานะจริงจะตรงกัน Label และ selector เชื่อมต่อคอนโทรลเลอร์กับ Pod ดังนั้นควรใช้ label ที่มีความหมาย เช่น app และ tier ใช้คำสั่ง kubectl apply -f เพื่อใช้งาน manifest และตรวจสอบสถานะเวิร์กโหลดด้วย kubectl get pods, kubectl describe deployment และ kubectl rollout status
เคล็ดลับฝึกฝน Kubernetes Workload หลัก: ทบทวนบทเรียนนี้ในเวลาสั้น ๆ ทุกวัน หลังทำแบบฝึกหัดแต่ละข้อให้บอกกฎหรือขั้นตอนที่ใช้ ถ้าบอกไม่ได้ ให้ทบทวนหัวข้อนั้นก่อนไปต่อ ความสม่ำเสมอช่วยจำได้ดีกว่าการอ่านนาน ๆ ครั้งเดียว
ตัวอย่าง
manifest ของ Deployment ประกาศ replica สามตัวของคอนเทนเนอร์ nginx พร้อม label app: web ConfigMap จ่ายค่า APP_MODE และ Secret จ่ายค่า DB_PASSWORD หากโหนดล้มเหลว คอนโทรลเลอร์จะสร้าง Pod ทดแทนบนโหนดที่ทำงานปกติ โดยคงจำนวนที่ต้องการไว้ที่สาม
อ่านคำถามอีกครั้งก่อนจบ และตรวจสอบว่าคำตอบตรงกับสิ่งที่ถาม
บทเรียน 5 Kubernetes บริการ พื้นที่จัดเก็บ และการแก้ไขปัญหา
Service ให้จุดสิ้นสุดเครือข่ายที่เสถียรสำหรับกลุ่ม Pod ClusterIP เผย Service ภายในคลัสเตอร์ NodePort เปิดพอร์ตบนทุกโหนด และ LoadBalancer เชื่อมต่อกับผู้ให้บริการคลาวด์สำหรับทราฟฟิกภายนอก Ingress จัดเส้นทางทราฟฟิก HTTP และ HTTPS ไปยัง Service โดยใช้โฮสต์เนมและเส้นทาง โดยทั่วไปผ่าน ingress controller Selector ใน Service ต้องตรงกับ label ของ Pod และ targetPort ของ Service ต้องตรงกับพอร์ตของคอนเทนเนอร์
พื้นที่จัดเก็บแบบถาวรใช้ PersistentVolumeClaim (PVC) เพื่อขอพื้นที่จัดเก็บ PersistentVolume (PV) เพื่อจัดหา และ StorageClass เพื่อกำหนดพฤติกรรมการจัดสรร PVC ที่ผูกกับ PV สามารถเมานต์เข้าไปใน Pod ได้ ReclaimPolicy ควบคุมว่าวอลุ่มจะถูกเก็บไว้หรือลบทิ้งเมื่อปล่อย PVC เวิร์กโหลดที่เก็บสถานะ เช่น ฐานข้อมูล ควรใช้พื้นที่จัดเก็บที่เสถียรและเข้าใจว่าการอ้างสิทธิ์วอลุ่มแมปไปยัง Pod อย่างไร
การแก้ไขปัญหาควรทำตามลำดับที่มีโครงสร้าง: ใช้ kubectl get pods เพื่อดูสถานะ ใช้ kubectl describe pod สำหรับอีเวนต์และเงื่อนไข ใช้ kubectl logs สำหรับเอาต์พุตของแอปพลิเคชัน และใช้ kubectl exec สำหรับการตรวจสอบแบบโต้ตอบ ตรวจสอบข้อผิดพลาดในการดึงอิมเมจ สาเหตุของ CrashLoopBackOff readiness probe selector ของ Service และนโยบายเครือข่าย ขั้นตอนการทบทวนที่ประกอบด้วยการสร้างอิมเมจ ทดสอบในเครื่อง ปรับใช้การเปลี่ยนแปลงเล็ก ๆ และย้อนกลับอย่างรวดเร็วจะเปลี่ยนการฝึก Kubernetes ให้เป็นทักษะที่ทำซ้ำได้
เคล็ดลับฝึกฝน Kubernetes บริการ พื้นที่จัดเก็บ และการแก้ไขปัญหา: ทบทวนบทเรียนนี้ในเวลาสั้น ๆ ทุกวัน หลังทำแบบฝึกหัดแต่ละข้อให้บอกกฎหรือขั้นตอนที่ใช้ ถ้าบอกไม่ได้ ให้ทบทวนหัวข้อนั้นก่อนไปต่อ ความสม่ำเสมอช่วยจำได้ดีกว่าการอ่านนาน ๆ ครั้งเดียว
ตัวอย่าง
Pod ยังคงอยู่ในสถานะ CrashLoopBackOff หลังจากการปรับใช้แท็กอิมเมจใหม่ kubectl describe pod แสดงรหัสออกของคอนเทนเนอร์ kubectl logs เผยตัวแปรสภาพแวดล้อมที่ขาดหาย และ Deployment อ้างอิง ConfigMap ที่ไม่มีอยู่ หลังจากสร้าง ConfigMap และปรับใช้ใหม่ Pod จะเข้าสู่สถานะ Running และ Service เริ่มส่งคืนทราฟฟิก
อ่านคำถามอีกครั้งก่อนจบ และตรวจสอบว่าคำตอบตรงกับสิ่งที่ถาม