The Cloud Camp Week#03 (Container 101)

สำหรับ 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
Ref: Volumes | Docker Docs

สำหรับกิจกรรม Onsite วันนี้สนุกมาก ได้คิดเยอะด้วย ทำให้ปลอดภัย มันง่ายกว่าทำให้เล็กลง 555 นั่งคิดนานมาก สุดท้ายได้ Hint Multi-Stage เลยไปนึกจาก Blog ทำให้ตัว ICONV support TIS-620 ที่ Build เตรียมไว้ แล้วเอามาแปะใส่ (กลับไปยังคาใจเลยไปโมเพิ่มมา 55) และตอนเย็นมีจับกลุ่มเตรียมทำ Senior Project ผมคงต้องไปรื้่อ Skill Coding เหมือนกัน จับ C# Logic มานานน

Reference


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts to your email.