สำหรับ Week มองว่าการทบทวนเรื่อง Container ของตัวผมเอง ใช้งานมาระดับนึง มีเรื่องที่รู้ และไม่รู้ด้วย ตาม Style การเรียนของผม แบบลักจำมาจากงาน Meetup ครับ มาลองดูสรุปสำหรับสัปดาห์นี้กันครับ
1. Why Container?
ก่อนที่เราจะรู้ว่าทำไมถึงต้องใช้ Container ต้องมา Recap กันก่อน ว่าเมื่อก่อนเอา Software ไปติดตั้งที่อื่นกันยังไงครับ จาก Code > Build > Executable File เจ้าตัว Executable File มาห่อเป็น Software Package เอาติดตั้ง
ยุคต่างๆของการติดตั้ง Software Package เล่าไว้หน่อยเผื่อน้องๆจบใหม่อ่าน โผล่เข้ามายุค Container เลย โดยมี 3 ยุค
- Bare Metal - กว่าจะมาลง Software Package ได้ ต้องมาสนใจพวก OS / Runtime / Network / Permission / Dependency ต่างๆ (Package อาจจะ Require เช่น Lib สำหรับต่อ DB) เป็นต้น
- ถ้าอะไรพังตัวใคร ตัวมัน ลงใหม่ - Virtual Machine - รวมตัว Bare Metal ห่อไว้เป็นไฟล์ เวลาจะทำอะไร จะได้สะดวกขึ้น ไม่ต้องกังวลว่าแก้แล้วจะพัง Rollback ได้
- การใข้ VM ใช้ตัว Resource ได้ไม่เต็มที่นัก - Container - หาดูจากภาพแล้วจะพบว่า Layer ของ Virtual Machine ยังมี overhead ในส่วนการใช้ Resource จากตัว Hypervisor ตัว Container เลยเข้ามาเติมเต็มใช้ Resource ให้คุ้มๆ
Note: Magic ที่ช่วยให้ Container มีอิสระ (Isolation) โดย key ที่ทำให้ Container เกิดขึ้นมา เนื่องจากตัว Linux Kernel มีตัว C-Group / Namespace ขึ้น
Ref:
- What Are Namespaces and cgroups, and How Do They Work? - NGINX
- Understanding Linux Namespace Types | by Luis Soares | Medium
2. Containers Basics
- Docker Architecture
รูปแบบการทำงานของ Docker จะเป็นตัว Client-Server โดยมีส่วนประกอบที่สำคัญ ดังนี้
- docker Client (docker cli) - program ที่ให้ผู้ใช้ป้อน docker command เพื่อจัดการ Docker Deamon
- Docker Host (เครื่องที่ลง docker)
- Docker Deamon (dockerd) - เป็น Process ที่จัดการ Request มาจาก docker cli เช่น
1. ดึง Image จาก Container Registry ถ้าไม่มี
2. สั่งให้ Image ทำงานเป็น Container เป็นต้น
- Image - พื้นที่ Local ที่เก็บ Image
Note: Image Software Package ที่รวม OS / Runtime / App ที่เบากว่า VM
- Container - Image ที่ถูกใช้งานแล้ว - Container Registry - ที่เก็บ Image / Plugins / Extensions ส่วนกลาง ที่มาแชร์ใช้งานร่วมกัน ปกติจะเป็น hub.docker.com
- พวก Image / Plugins / Extensions Explore Docker's Container Image Repository | Docker Hub
- Docker Command
- docker run - สั่งให้ Image ทำงานเป็น Container ตาม Config ที่กำหนด
- d ให้ทำงานแบบ background mode
- p <host>:<container port> กำหนด port ที่ใช้เชื่อมต่อจากภายนอก
docker run -d -p 8090:80 inv-api-image
- docker stop - หยุดการทำงานของ Container โดยที่ตัว App ทำงานจัดการ State เรียบร้อย (Graceful shutdown)
- docker kill - force shutdown container / data ระหว่างนั้นหาย ใช้กรณีที่เกิด Infinite Loop
- docker pause / docker unpause - หยุดการทำงาน / และให้ทำงานต่อ โดยที่ตัว Container ยัง Hold Resource อยู่
แบบลึกๆดูจากนี้เลย restart - pause vs stop in docker - Stack Overflow - docker start - เปิด Container ทำงาน
- docker images - ตรวจสอบ imageที่อยู่ใน Docker Host
- docker ps / docker ps -a : แสดง Container ที่มี ถ้า -a แสดงทั้งหมด
- docker rm <<container id / container name>> : ลบ Container
- docker rmi <<image id / image name>> : ลบ Image
- docker exec -it <<container id / container name>> <<shell type>> : เข้าไปใน Container จัดการ
docker exec -it inv-api sh docker exec -it inv-api bash
สำหรับคำสั่งอื่นๆดูเพิ่มได้จาก https://docs.docker.com/engine/reference/run/
3. Build Containers
Dockerfile - ไฟล์ที่เก็บ Step การสร้าง Container Image ขึ้นมา ไม่ว่าจะ Run กี่รอบจะได้ผลลัพธ์เหมือนเดิม โดยใน Dockerfile แยกออกเป็น 2 ส่วน
- BUILD TIME - มี Keyword ยังนี้
- FROM บอกว่าจะเอา Base Image มาจากไหน
- WORKDIR กำหนด Directory ปัจจบุัน เพื่อทำงาน อารมร์แบบ CD
- COPY - เอาไฟล์จาก Context มาใส่ที่ Image
- ADD - เอาไฟล์จาก Context มาใส่ที่ Image เหมือนกัน แต่ไม่แนะนำ เพราะมี issue security ถ้ามี zip มันจะแตกออกมาเลย
- RUN - Run Linux Command ตามแต่ละ Distro เลย
- LABEL <KEY>:<VALUE> ใส่ Information ของ Image - RUN TIME - มี Keyword ยังนี้
- EXPOSE บอก port ที่จะให้เปิดออก
- ENTRYPOINT
- CMD
เมื่อได้ Dockerfile ไฟล์มาแล้ว การแปลงาก Dockerfile เป็น Container Image จะใช้คำสั่ง docker build มี Pattern ประมาณนี้
docker build -t <Container_name:Tag_version> --no-cache <context>
- -t บอกชื่อ Image มี 2 แบบ Container_name หรือ Container_name : Tag_version
- Context บอกว่า File สำหรับที่ใช้ Build (พวก Dockerfile) อยู่ที่ไหน ปกติใส่ . หรือ ถ้า Custom File -f <Your_DockerFile>
docker build -t inv-api:1.0.0 . docker build -t inv-api:1.0.0 -f abc.DockerFile docker build -t inv-api:1.0.0 --no-cache -f abc.DockerFile
- --no-cache บอกว่าระหว่าง build ไม่ต้องให้ใช้ cache มันจะช่วยแก้ปัญหาตอน build แล้ว App ยังทำงานเหมือนเดิมได้ ปกติถ้าไม่ใส่ --no-cache ตอนสั่ง build ติดกันถี่ๆ มันจะขึ้นคำว่า CACHE
นอกจาก docker build แล้วมีตัวใหม่อย่าง docker buildx
- ถ้าไม่ต้องการไฟล์อะไรใช้เข้าไปใน Container ให้ใช้ตัว .dockerignore
4. Publish Container
จากข้อ 3 ตอนนี้ image ของเราจะอยู่ในเครื่องของเราเท่านั้น หากจะเอาไปให้คนอื่น หรือคนในทีมใช้งาน ต้องให้ Container Registry มาใช้ จะเป็นของ docker / aws / azure / gcp หรือ ทำ local ใช้เองก็ได้ โดยคำสั่งที่เกี่ยวข้องกับการ Push จะมี
- docker login - เข้า Container Registry
docker login -u <your_username>
- docker tag - กำหนดเวอร์ชันของ image ที่คนอ่านเข้าใจ ปกติ image มันจะมี hash ของมันอยู่แล้ว
ปล. ถ้าใช้ docker build มันจะ tag มาให้อยู่แล้ว - docker push - เอา Container Image ขึ้นไป Public Registry
docker pull <<docker_username>>/inv-api //เจ้าอื่นๆ docker tag inv-api <<YourRegisry>>.azurecr.io/<<YourNameSpace>>/inv-api docker pull dsregistry.azurecr.io/dsnamespace/inv-api
5. Base Image
ใน docker มี image หลายแบบ โดยแบบที่เราควรรู้จัก มีดังนี้
- scratch - Base Image ตัวแรกเลย
- Official Image - Image ที่มาจากผู้ผลิตที่น่าเชื่อถือ มี Best Practice มาระดับนึง โดยจะมี Official Doc ชัดเจน และรูปแบบการ Support ชัดเจน
- Long Term Support
- Extended Long Term Support
โดยถ้าเราดูใน docker hub จะมีหลายชื่อเลย มีตัวที่ต้องสนใจ
- debian - Project แม่ของ Ubuntu โดยมี Codename ให้จดจำ เช่น bookworm / bulleye
- -slim - docker image ที่ตัด lib บางตัวให้เล็กลง debian > debian-slim
- -alpine - OS ขนาดเล็ก สำหรับ Container
- windowsservercore - สำหรับ Deploy Legacy App อย่าง .NET Framework ที่ไป Linux ไม่ได้
เราจะเลือก Base Image ยังไง ?
- size - deploy ไว
- debian มี apt เป็น package manager
- alpine ใช้ musl libc จะมี apk เป็น package manager - Official Image
- ระยะเวลา Support ควรเป็น Long Term Support
- Update ล่าสุดของ Image
- ในแง่ Security อาจจะต้องเข้าไปดูแต่ละ Layer ว่ายัดอะไรมาบ้าง
6. single stage vs multi-stage
จากหัวข้อที่ 5 ตอนนี้ เราจะทำ Image เป็น Single Stage Build แต่ทว่า มันอาจจะมีขนาดที่ใหญ่เกิดไป เลยต้องแยกออกมาเป็น Multi-Stage แทน เพื่อตัดของที่ไม่จำเป็นไป อยากเข้าตอน Build App เราอยากได้แค่ผลลัพธ์ ส่วน Temp / Dependency สำหรับ Build เราไม่ได้ใช้
อันนี้มี Blog ส่วนตัวผมที่เขียนเรื่อง Multi-Stage และการลดขนาดของ Container ลองมาดูได้เลยครับ
7. Container Security
การทำงานของ Docker มันจะให้ Kernel ร่วมกับ Host น่าจะเรียกว่าเป็น Userspace ถ้าคุมสิทธิได้ไม่ดี อาจจะเกิดการแก้ไข Container B จาก A หรือ กระโดดไปใช้สิทธิของ Host
- privilege escalation - ยกระดับสิทธิ
- ป้องกัน ใน Container ให้ใช้ non-root user ในการทำงานแทน Container
- ป้องกัน rootless จากใน Container และยังให้ non-root user start container ที่ host - surface attack - Image ที่อยู่ใน Public Registry อาจจะมีผู้ไม่ประสงค์ดี ยัด malicious software ลงไป เพื่อให้คนเข้าไปใช้งาน
- ป้องกัน distroless image - โดย Google ไม่มี shell ก็ลำบาก มีตัว Runtime / App ถ้าจะ shell ใช้ sidecar มาช่วย
- ป้องกัน UBI image - ของ RedHat Shell ยังมีอยู่นะ แต่ทว่าบางคำสั่งตัดออกไป เช่น พวก yum
4C Container Security ที่ต้องสนใจ
- Code
- Container
- Cluster ตัว Container Runtime / App
- Cloud
Ref: Overview of Cloud Native Security | Kubernetes
8. Container Orchestration Fundamental
ตอนนี้มีเรื่อง Container แต่พอมันมีเยอะๆเข้า เราต้องมามีประเด็นที่ต้องมาติดกันต่อ ดังนี้
- สามารถจัดการ Resource พวก CPU / Memory / Network ที่ Container แต่ละตัวต้องการได้
- กำหนดให้ Container ใช้ประสิทธิภาพได้สูงสุด
- ดูแลให้ตัว Container มีความพร้อมใช้งาน (availability)
- ถ้าตัว Container ตายขึ้นมา ต้องสร้างขึ้นมาทดแทนได้ แต่ต้อง Design ให้ Container เป็น Stateless ด้วย
- ถ้า Load เข้ามาเยอะๆ พร้อม Scale - จัดการ Network ถ้าให้ Manual ทำไม่น่าจะไหว
- จัดการ Storage ของ Container เพราะแยก Stateless แล้วต้องมาเผื่อที่จัดเก็บ
จากประเด็นข้างต้น ตัว Container Orchestration มีตัว
- control plane - management of the containers
- worker nodes - ตัวที่ให้ containers มัน deploy และทำงาน
Container Orchestration ที่ดังๆ K8S / Docker Swarm
9. Networking
- มีมาตรฐานการอย่าง containernetworking/cni: Container Network Interface - networking for Linux containers (github.com) ดังนั้นไม่ว่าจะใช้ Network แบบไหน easy to swap out different plugins
- ปกติ Network ของ Container docker จะ
- None Network - ไม่ต่อกับใครเลย / Host เข้าไม่ได้
- Host Network - ใช้ Network ของ Host เลย
- Bridge Network - มีตัว Bridge Driver มาครอบอีกที ช่วยให้ Container คุยกันเองได้ (intercontainer) ถ้าอยู่เครื่องเดียวกัน
- Overlay Network - Bridge ขนาดใหญ่ ใช้ Docker Engine หลายตัว Overlay network driver | Docker Docs
10. Service Discovery & DNS
เวลา Container จะให้มาคุยกัน ด้วย IP ใครจะไปจำไหว มีหลาย DC / Region ดังนั้นเลยต้องเอา Automation ช่วย
- Service Registry - ลงทะเบียนตอน Container เกิดใหม้ เข้าระบบ
- Service Discovery - มาหาตามที่ลงทะเบียนไว้
แนวคิดที่ช่วยให้ Service Discovery / Service Registry สำเร็จมี 2 วิธี
- DNS
- Key-Value Store พวก etcd/ Consul / Apache Zookeeper / Raft
11. Service Mesh
Service Mesh - เป็น Layer อีกอันนึงที่ช่วยครอบ Container ในรูปแบบของ Side Car Proxy ที่เข้ามาช่วยจัดการการสื่อสารของแต่ละ Container โดยเข้า Filter Traffic / Load Balancing เป็นต้น
และพอใช้ Side Car บาง Pattern อย่าง Timeout / Retry / Circuit Breakers ไม่ต้องมาเขียน Code เพิ่มคุมจาก Proxy ตัว Tools nginx, HAProxy, Envoy, Istio
12. Storage
จำได้ว่า Container เป็น Stateless ได้ใช่ปะ ดังนั้นตัว Container ต้องมี Storage แยกอีก Layer ออกมา เพื่อเก็บข้อมูล มี 2 แบบ
- mount
- volume
สำหรับกิจกรรม Onsite วันนี้สนุกมาก ได้คิดเยอะด้วย ทำให้ปลอดภัย มันง่ายกว่าทำให้เล็กลง 555 นั่งคิดนานมาก สุดท้ายได้ Hint Multi-Stage เลยไปนึกจาก Blog ทำให้ตัว ICONV support TIS-620 ที่ Build เตรียมไว้ แล้วเอามาแปะใส่ (กลับไปยังคาใจเลยไปโมเพิ่มมา 55) และตอนเย็นมีจับกลุ่มเตรียมทำ Senior Project ผมคงต้องไปรื้่อ Skill Coding เหมือนกัน จับ C# Logic มานานน
Reference
- 9 Docker Extensions Every Developer Must Try - DEV Community
- Azure File Storage as a Docker Plugin (jmaitrehenry.ca)
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.