LFS253: Containers Fundamentals

peepeepopapapeepeepo

Sawit M.

Posted on January 7, 2020

LFS253: Containers Fundamentals

Index


Chapter 1: What's Containers?

What are Containers ?

Containers is an application-centric way to deliver high-performance, scalable application in the infrastructure of your choices

ปัญหาที่กวนใจข้อสำคัญของทั้ง developer และ operation ในการทำงานร่วมกันก็คือ dependencies

แล้ว dependencies คืออะไรเหรอ? มันคือ ส่วนอื่นๆ ที่ไม่ใช่ code หลัก แต่ code หลักต้องเรียกใช้เพื่อให้ application สามารถทำงานได้ นั่นก็คือพวก libraries, configuration หรือ แม้กระทั่ง OS เป็นต้น

เรามักพบปัญหาว่า developers develop application ขึ้นมาทำการและทำการ test บน laptop ของตัวเองเรียบร้อยแล้ว แต่พอเอามาขึ้นที่ production กลับใช้งานไม่ได้

ทำไมใช้ไม่ได้ล่ะ 🤬!@#@$!#%

อาจเป็นไปได้ทั้งใช้ interpreter คนละ version กัน มี library ไม่ครบหรือ version ไม่ตรงกัน หรือ แม้กระทั้ง developers develop พบ Mac แต่ production เป็น Linux

ปัญหาเหล่านี้ pain-in-the-ass ของทุกคนมาเป็นเวลาอันยาวนานมาก

จน linux kernel ก็ออก features ที่สามารถแบ่ง virtual environment ออกเป็นชุดย่อยๆ เพื่อ run แต่ละ application ได้ พร้อมทั้งสามารถ pack dependencies ต่างๆ เข้าไปได้อีกด้วย

containers จึงค่อยๆ ถือกำเนิด และพัฒนาต่อมาเรื่อยๆ จนถึงปัจจุบัน และยังคงพัฒนาต่อไปเรื่อยๆ

ทำไมถึงต้องมี containers ?

1) เพื่อให้การ develop และ การ deploy application ได้รวดเร็วทันต่อตลาดและความต้องการของลูกค้า
2) ถ้าเรามี innovation อะไรแล้ว develop บน containers เราสามารถใช้มัน run ใน production ได้เลย
3) ในการ patch fix bug หรือเพิ่ม feature ถ้าเกิด deploy ไปแล้วมีปัญหาเราสามารถ rollback ไปใช้ container version เก่าที่ใช้งานได้ได้เลย เพราะทุกอย่างอยู่ใน container อยู่แล้ว
4) คุ้มค่า เพราะสามารถ run ได้หลาย app ใน 1 เครื่อง โดยไม่ต้องห่วงเรื่อง dependencies

และอื่นๆ อีกมากมาย

Containers ไม่ใช่ Light-weight VMs

แต่สิ่งที่มันเหมือนกันคือ สามารถแยก environment และ resource เพื่อให้ application run เท่านั้นเอง

จากภาพ

  • VMs run บน Guest OS ซึ่ง run อยู่บน Hypervisor
  • Containers run บน Container Engine ซึ่ง run อยู่บน Host OS

เราไม่สามารถ run Windows application ใน Container ที่ run อยู่บน Linux Host OS แต่ VM สามารถทำได้

เราจะ deploy containers ได้ที่ไหนบ้าง?

เราสามารถ run container ได้ทั้งบน VM และ Bare-Metal

แต่ run ที่ไหนจะดีกว่าล่ะ ?

  • ในมุมมองของ Containers 🡆 ยังไงก็ได้ไม่ต่างกัน
  • ในมุมมองของ IT Department 🡆 ขึ้นอยู่กับหลายปัจจัย เช่น stability, performance, ค่าใช้จ่าย และ ทักษะของผู้ปฏิบัติงาน เป็นต้น

Containers สามารถ scale ได้โดยใช้ container orchestrator software เช่น Docker Swarm, Kubernetes, Mesos Marathon, Nomad, Amazon ECS, etc


Chapter 2: The History of Containers

History

  • Containers ไม่ใช่ของใหม่ มันเริ่มมาจาก File system container ที่เรียกว่า chroot ซึ่งมาพร้อมกับ Unix 7th Edition ซึ่งออกมาในเดือนมีนาคม ปี 1982
  • ในปี 2000, Free BSD ได้เพิ่ม feature ให้ chroot แล้วเปลี่ยนชื่อเป็น jail
  • ในช่วงแรกๆ ของทศวรรษ 2000, Solaris ปล่อย zone ซึ่งเป็น feature ในการแบ่ง OS ออกเป็นส่วนย่อยๆ (Virtualized Operation System Services)

chroot

Chroot is an operation that changes the apparent root directory for the current running process and its
children. A program that is run in such a modified environment cannot access files and commands
outside that environmental directory tree. This modified environment is called a chroot jail.

chroot เป็นการทำให้ application ที่เรา run ไม่เห็น path / (root) จริงๆ แต่เป็น / (root) ปลอมที่ถูกสร้างขึ้นเพื่อให้ แต่ละ process และ child process ของมัน เห็น

Alt Text

  • / (root) ขอแต่ละ process จริงๆ แล้ว ถูก mount ไว้ที่ /mnt
  • เราสามารถ demo chroot ได้ด้วย debootstrap ซึ่งสามารถ install ใน Debian ได้

ถ้าใช้ chroot:
process ที่ถูกแบ่งแค่ file system นอกนั้น share กันใน 1 server
ถ้าใช้ jail:
process ที่ถูกแบ่งทั้ง file system, users, network, sub-system และอื่นๆ

systemd-nspawn

systemd-nspawn ใช้ systemd เป็น init system ในการแบ่ง userspace และ จัดการ process ต่างๆ

เราสามารถใช้ systemd-nspawn ในการ launch container ได้ โดย systemd-nspawn เปรียบได้กับ chroot + virtualized process tree, users, host and domain name, etc


Chapter 3: Building Block

3 Building Blocks of Containers

1) Namespaces

namespaces ถูก release มาพร้อมกับ linux kernel version 2.4.19 ในปี 2002 โดย ทำหน้าที่ในการ virtualized system resources ดังต่อไปนี้ ให้แต่ละ process

  • mount point (mnt): เป็นการ virtualized mount point คล้ายๆ กับ chroot
  • process id (pid): เป็นการ virtualized pid โดยในแต่ละ namespace จะมี pid ซ้ำกันได้ โดย pid ในแต่ละ namespace จะถูก map เป็น pid ของ host อีกที
  • network (net): เป็นการ isolate /proc/net, IPs, interfaces, และ routes ตามแต่ละ namespaces
  • user id (users): เป็นการ isolate User และ group IDs ตามแต่ละ namespaces
  • inter-process communication (ipc): เป็นการ isolate SystemV IPC และ POSIX Message Queues ตามแต่ละ namespaces
  • UTS (hostname): เป็นการ isolate the hostname และ NIS (Network Information Service) name ตามแต่ละ namespaces

2) Control Group (cgroups)

cgroups ถูก release มากับ linux kernel ในปี 2007 โดยทำหน้าที่ในการจำกัดการใช้งาน system resources เช่น

  • CPU (cpu/cpuset): ควบคุม time period และ upper limit ในการใช้งาน cpu รวมทั้ง assign งานในแต่ละ group
  • Memory (memory): ควบคุม maximum memory limit, memory swappiness, OOM, etc
  • disk i/o (blkio): assign value of block I/O รวมถึงกำหนดค่า hard limit ของ block I/O
  • network (net_cls/net_prio): tags network packets, prioritize และ weight traffic ขาออกของ network interface
  • devices: ควบคุมการ assign device ไปยัง cgroup
  • hugepages: ควบคุม hugepages size usage และ จัดการ hugepages matrices ในแต่ละ cgroup

ในแต่ละกลุ่มของ process

มี cgroup พิเศษชื่อ Freezer สำหรับใช้ในการ suspends/resumes tasks ใน group

3) UnionFS

UnionFS เป็นการรวมเอา file system อื่นๆ มารวมกันเป็นเสมือน file system เดียว โดยแต่ละ file system ที่เอามารวมกัน จะเรียกว่า branch สามารถ set priority และ กำหนดให้เป็น mode read-only ได้

UnionFS


Chapter 4: Container Runtimes

History of Container Runtimes

  • ในตอนแรก Docker ใช้ lxc ในการ ติดต่อกับ linux container จากนั้นจึงเปลี่ยนมาใช้ libcontainer
  • เดือนธันวาคม 2014, CoreOS ออก Container Runtimes ชื่อ Rocket (rkt)
  • เดือมมิถุนายน 2015, มาตรฐาน OCI (Open Container Initiative) ถือกำเนิดขึ้น ภายใต้การกำกับดูแลของ Linux Foundation เพื่อป้องกันไม่ให้เกิดปัญหา vendor lock-in ในส่วนของ runtime และ image specification
  • หลังจากนัน runC ถือกำเนิดขึ้นตามมาตรฐานของ OCI โดย นำเอา code ของ libcontainer มาแก้ไขเพิ่มเติม

RunC

  • เป็น container runtime ที่พัฒนาขึ้นมาตาม spec ของ OCI
  • มี command line ของตัวเองในการจัดการ container ได้
  • สามารถ embedded ไปใน software อื่นๆ ได้
  • compatible กับ Docker
  • ไม่ create daemon
  • สามารถทำงานร่วมกับ systemd ได้เป็นอย่างดี

Docker

  • Docker เป็นมากกว่า Container Runtime เพราะมันทำได้ทั้ง dev, ship และ run application ได้
  • Core ของ docker คือ Docker Engine โดยมันจะทำหน้าที่ไป สั่ง containerd เพื่อจัดการ runC ที่ run container
Docker
Source: docker.com
  • Docker มีโครงสร้างการทำงานเป็น client-server แบบ Restful API
  • Docker Product
    • Community Edition (CE) - Free
      • edge: release ทุกเดือน
      • stable: release ทุก 3 เดือน
    • Enterprise Edition (EE) - Paid
      • integrated และ supported กับ certified container platform
      • release ทุก 3 เดือน / แต่ละ release จะ support เป็นเวลา 1 ปี
      • มี 3 tier ได้แก่ basic / standard / advance
  • การนับ version ของ Docker
    • ก่อน มีนาคม 2017, จะนับแบบ Semantic Versioning คือ Major.Minor.Patch
    • หลังจากนั้น, จะนับแบบ Calendar Versioning คือ YY.MM-ce และ YY.MM-ee

APIs version ของ Docker จะนับแยกจาก Docker version โดยเริ่มมี inter-portability มาตั้งแต่ Docker 1.13

Rocket (rkt)

  • ในปี 2014, CoreOS launch App Container (appc)
  • ในปี 2016, launch rkt ซึ่ง implement ต่อมาจาก appc
  • จากนั้นเมื่อ OCI ถือกำเนิด, rkt ถูกปรับให้ compatible กับ OCI
  • rkt ทำงานรวมกันได้ดีกับ systemd
  • rkt ใช้ image format ใหม่ชื่อ Application Container Image ซึ่งประกอบด้วย 2 ส่วนสำคัญคือ
    • rootfs: เป็นที่เก็บ files ต่างๆ ที่ต้องใช้งาน
    • Image Manifest: เป็น configure ที่เก็บ execution parameters และ resource limit ต่างๆ
  • rkt Architecture
rkt-flow
Source: CoreOS.com
  • stage0: discovers, fetches และ จัดการ application image
  • stage1: เตรียม execution engine สำหรับการ launch containers
  • stage2: เตรียมแบ่งแยก virtual environment สำหรับแต่ละ application


Chapter 5: Docker for Mac and Windows

History

  • ก่อนที่จะเป็น Native Support การใช้ docker บน windows หรือ Mac ต้องใช้ตัวช่วยที่ชื่อว่า Docker Toolbox ซึ่งก็คือการลง Virtualbox แล้ว run linux VM ขึ้นมา 1 ตัว จากนั้นคำสั่งต่างๆ ที่เราส่งไป ก็จะูกส่งไปที่ linux VM นั่นๆ โดยส่วนประกอบของ "Dcoker Toolbox" มีดังนี้
    • Virtualized Environment
    • boot2docker VM
    • kitematic
    • Docker Engine
    • Docker Compose
    • Docker Machine
  • จากนั้นเดือนกรกฎาคมปี 2016 Docker จึงเริ่มออก Native Support สำหรับ Windows และ Mac
    • Mac: ใช้ Hardware Virtualization ในระดับ OS และ Unikernel Technology ที่เพิ่งไป acquire มา
      • ใช้ light-weight hypervisor แล้ว run linux instance ที่มี Docker Engine
      • จากนั้น map network และ Disk ของ container กับ linux instance
      • ซึ่ง linux instance นั้น map resource อยู่กับ host
    • Windows: มี 2 techniques ให้เลือก
      • Windows server containers -> เป็นการ share kernel กับ host เลย โดย kernel ของ Windows สามารถแยก namespaces และ cgroups ได้เหมือน Linux
      • Hyper-V Containers -> run "Windows server containers" ใน optimized VM ที่ใช้ Hyper-V เป็น Hypervisor

Prerequisite for Windows: Hyper-V และ Virtualization ต้อง enable ไว้ และต้องใช้ windows 10 pro, enterprise หรือ education แบบ 64 bit

Unikernel

Unikernel จะทำให้เราสามารถสร้าง image เฉพาะทางได้ โดยเราสามารถเลือกเฉพาะ library ที่ application ต้องการไป compile รวมกับ แล้ว build เป็น machine image เพื่อนำไป run บน hypervisor หรือ บน bare-metal เลยก็ได้ เช่น ถ้า app ของเราต้องการติดต่อกับโลกภายนอก ก็ เลือกเฉพาะ network library ไป build รวมกับ app ของเรา


Chapter 6: Accessing a Remote Docker Daemon

Docker Client and Docker Host Communication

Docker Client เป็น command ที่เรา run เพื่อไปสั่ง Docker Daemon ที่ run อยู่ที่ Host ต่างๆ โดย Docker Client 1 ตัว สามารถติดต่อได้กับ Docker Daemon ได้หลายตัว

โดย default, Docker daemon จะ listen ที่ Unix Socket เท่านั้น (เครื่องอื่นไม่สามารถ connect ได้) การที่จะให้ Docker daemon เปิดรับ connection จากภายนอกได้ ต้อง start ด้วย option -H เช่น -H 0.0.0.0:2375

การ connect ไปยัง Docker daemon ก็ใส่ -H <IP>:<PORT> ไปด้วยเช่นกัน ดังนี้ docker -H tcp://1.x.x.x info (ถ้าไม่ระบุ port default คือ 2375 (unencrypted) และ 2376 (encrypted))

อีกวิธีหนึ่งคือการประกาศ environment variables DOCKER_HOST เช่น export DOCKER_HOST=1.x.x.x จากนั้น docker info ได้เลย โดยไม่ต้องระบุ host

Docker Machine

docker-machine เป็น tool ในการ provision Docker บน เครื่องของตัวเองหรือ cloud provider ต่างๆ เช่น AWS, GCP, Digital Ocean และ อื่นๆ

นอกจากนั้นยังสามารถ access เข้าไปสั่งงาน docker daemon ที่สร้างขึ้นมาได้อย่างปลอดภัย

docker-machine สามารถ download ได้จาก Github


Chapter 7: Container Operations

What happened while creating a container ?

  1. process ถูกสร้างขึ้นมาใน host
  2. process ถูกผูกเข้ากับ namespaces ของ resources เช่น pid, net และ uts
  3. control group configuration ถูก apply ไปยัง process เพื่อ limit resources
  4. security context ถูก apply ไปยัง process

runC

ตัวอย่าง Commands ที่ใช้กับ runC มีดังนี้

Commands จุดประสงค์
runc run busybox run container ชื่อ busybox
runc list list container ที่ run ด้วย runc
runc ps busybox list process ที่ run ใน container ชื่อ busybox
runc pause busybox หยุดการทำงานของ container ชื่อ busybox ชั่วขณะ
runc resume busybox ยกเลิกการหยุดการทำงานของ container ชื่อ busybox ชั่วขณะ
runc state busybox ตรวจสอบสถานะของ container ชื่อ busybox
runc delete -f busybox หยุดการทำงาน และ ลบ container ชื่อ busybox

Docker

ตัวอย่าง Commands ที่ใช้กับ docker มีดังนี้

Commands จุดประสงค์
docker container create -it alpine sh สร้าง container ชื่อ alpine ที่ run sh command ในแบบที่มี interactive terminal
docker container start <container_id> start container
docker container ls (-a) list container ที่ run อยู่ในขณะนั้น แต่ถ้าเพิ่ม -a จะ list container ทั้งหมด
docker container run -it alpine sh สร้างและ run container ชื่อ alpine ที่ run sh แบบที่มี interactive terminal (เท่ากับ command ที่ 1 และ 2 รวมกัน)
docker container inspect <container name/id> ตรวจสอบรายละเอียดของ container
docker container stop หยุดการทำงานของ container
docker container exec -it <container name/id> เข้าไปยัง container
docker container rm (-f) <container name/id> ลบ container ถ้าใส่ -f จะ forece stop container ให้ด้วย

Note

  • ใช้ ctrl-p+q เพื่อออกจาก interactive terminal
  • ตั้งแต่ Docker 1.13 มีการเปลี่ยนแปลง syntax ของ command นิดหน่อย โดยเพิ่ม sub-command "image" และ "container" ขึ้นมา เพื่อแยก command ในการจัดการ image และ container ให้ชัดเจนมากขึ้น

rkt

ตัวอย่าง Commands ที่ใช้กับ rkt มีดังนี้

Commands จุดประสงค์
rkt run --interactive (--insecure-options=image) quay.io/coreos/alpine-sh run container ชื่อ alpine-sh แบบ interactive โดยถ้า image ไหนไม่ได้ sign GPG ให้ใส่ option --insecure-options=image ด้วย
rkt --insecure-options=image run docker://nginx run container จาก dockerhub
rkt list list container ที่ run ด้วย rkt
rkt stop <UUID_of_Container> หยุดการทำงาน ของ container
rkt rm <UUID_of_Container> ลบ container
rkt status <UUID_of_Container> ตรวจสอบสถานะของ container
systemd-run --slice=machine rkt run docker://nginx run container แบบ daemon mode โดยใช้ systemd เป็นคน manage ให้

Note

  • ทุก native image ของ rkt ต้องมี GPG-signed เสมอ


Chapter 8: Working with Image

Working with Image

Image คือ ส่วนที่สำคัญที่สุดของ container ecosystem เพราะทุก container ต้อง run จาก image

เราสามารถสร้าง container ได้จาก image ในทางกลับกันเราก็สามารถ แก้อะไรบ้างอย่างแล้ว convert container กลับไปเป็น image ได้ และโครงสร้างของ container จะเป็น layer ตามแบบ UnionFS

Dockerhub

Docker Hub เป็น repository ที่เก็บ image ที่สามารถทำ versioning ได้ด้วยการ tag นอกจากนั้นยังมี store สำหรับขาย enterprise-graded image ที่ผ่านการทำ security มาเรียบร้อย เพื่อนำไปใช้ในงานที่ต้องการความปลอดภัยและ support

Docker Image Operations

ตัวอย่าง Commands ที่ใช้ทำงานกับ docker image มีดังนี้

Commands จุดประสงค์
docker search nginx search image nginx ใน Docker Hub
docker image ls list image ในเครื่องของเรา
docker image pull alpine download image ชื่อ alpine จาก Docker Hub
docker image inspect alpine:lates แสดงรายละเอียดของ image ชื่อ alpine ที่ tag ว่าเป็น version ล่าสุด
docker container run -itd alpine sh start container alpine แล้ว run sh command ใน mode daemon (-d: daemon mode)
docker container diff myalpine ตรวจสอบความแตกต่างของ container ที่ run อยู่ และ image ของมัน
docker container commit myalpine <user>/<image_name>:<tag> สร้าง image ใหม่จาก container ชื่อ myalpine
docker container export > /path/to/file.tar export container ออกมาเป็น tar file
cat /path/to/file.tar | docker image import - <user>/<image_name>:<tag> import tar file เข้ามาเป็น docker image

Note

  • default tag คือ latest
  • image id ที่เป็นเลขฐาน 16 (hex) ได้มาจาการเข้ารหัส SHA256
  • เราสามารถสร้าง หลายๆ container ได้จาก image อันเดียว

Docker Image Push

ตัวอย่าง Commands ที่ใช้ push docker image เข้า repository มีดังนี้

Commands จุดประสงค์
docker login ทำการ authentication เพื่อ login เข้าไปยัง image repository
docker info แสดงข้อมูลของ docker engine ที่ติดต่อด้วย
docker image push <user>/<image_name>:<tag> push image ในเครื่องของเราไปยัง repository
docker image prune ลบ image ที่ไม่ได้ใช้
docker image rm (-f) nginx:alpine ลบ image nginx ที่มี tag ว่า alpine บนเครื่องเรา ถ้าใส่ option -f จะ force stop container ที่ใช้ image นี้ ก่อน remove image

rkt image

ตัวอย่าง Commands ที่ใช้ทำงานกับ rkt image มีดังนี้

Commands จุดประสงค์
rkt image list list rkt image บนเครื่องเรา
rkt fetch coreos.com/etcd:v2.0.0 download image etcd ที่มี tag v2.0.0 จาก coreos.com
rkt fetch --insecure-options=image docker://nginx download image nginx ที่มี tag latest จาก Docker Hub


Chapter 9: Working with Dockerfiles

Dockerfiles

Dockerfiles เป็น file ที่เราเขียนวิธีการสร้าง image เอาไว้ เพื่อให้มันสามารถ create image ซ้ำได้ และทำได้อย่างอัตโนมัติ

ด้วยความที่มันเป็น file ทำให้มันสามารถถูก share และ เก็บเป็นส่วนหนึ่งใน source code tree ใน source code repository อย่างเช่น github, gitlab หรือ bitbucket ได้ ทำให้เราสามารถ automate process ผ่าน CI/CD tools ได้ง่ายขึ้น

command ที่ใช้ในการ build docker image จาก dockerfiles คือ docker build -t <tag>

จากบทที่ผ่านมา docker image มีลักษณะเป็น layer โดยแต่ละ layer จะคือ แต่ละ RUN instruction ใน Dockerfiles ดังนั้น ในการ build แต่ละ layer สามารถ cache ได้ถ้า layer นั้นๆ ไม่ได้เปลี่ยนแปลง ด้วยการ cache จะทำให้การ build image เร็วขึ้น (เราสามารถ disable การ cache และการใช้ cahce ระหว่างการ build ได้ด้วย option --no-cache)

Dockerfiles Instructions

  • List of instructions

    • FROM: set และ download base image สำหรับการ build image
    • RUN: execute command ตามที่ configure ไว้ โดยจะมีการ create layer ใหม่
    • CMD: กำหนด command default ในการ execute container มีได้แค่ 1 บรรทัด ถ้ามีหลายบรรทัด บรรทัดสุดท้ายเท่านั้นที่จะมีผล
    • LABEL: เป็น metadata ของ image ในรูปแบบ key-value pairs
    • EXPOSE: ให้ container listen port อะไร
    • ENV: set environment variables สำหรับ image
    • ADD: copy files หรือ directories จากภายนอกหรือจาก URL หรือ แตก tar file ไปยัง image
    • COPY: copy files หรือ directories จากภายนอกไปยัง image
    • ENTRYPOINT: เป็น command ที่ container จะ run ตอนที่มันถูก start
    • VOLUME: create volume เพื่อ mount เป็นอีก 1 mount point ใน image
    • USER: set user id และ group id ในการ run instruction RUN, CMD และ ENTRYPOINT
    • WORKDIR: set working directory สำหรับการ run instruction RUN, CMD, ENTRYPOINT, COPY และ ADD
    • ARG: กำหนด build arguments เพื่อรองรับ จาก docker build command
    • ONBUILD: บอกให้ คนที่เอา image นี้ไปทำ base image run command พวกนี้ด้วย
    • STOPSIGNAL: set system call signal ที่จะทำให้ container หยุดการทำงาน
    • HEALTHCHECK: กำหนด liveness และ readiness probe ในการตรวจสอบ health ของ container
    • SHELL: กำหนด default shell เพื่อใช้กับ instruction SHELL default shell ของ Linux คือ ["/bin/sh", "-c"] และของ Windows คือ ["cmd", "/S", "/C"]
  • Instruction format

    • Shell form: <Instruction> <command>
    • Exec form: <Instruction> ["executable", "param1", "param2", ...]
  • Type of Instruction

    • Build time: RUN, ADD, COPY, USER, WORKDIR, ONBUILD, SHELL, etc
    • Run time: CMD, ENTRYPOINT

CMD vs ENTRYPOINT

  • CMD: ถ้าไม่มี ENTRYPOINT จะเป็น command ที่ container run โดยสามารถ overwrite ด้วยการ pass arguments ตอน start container
  • ENTRYPOINT: เป็น command ที่ container run เหมือน CMD แต่ ไม่สามารถ overwrite ได้ และ ถ้ามีการระบุ CMD CMD จะเป็นหนึ่งใน arguments ของ ENTRYPOINT


Chapter 10: Container Networking

Docker Networking Command

  • Network นี้จะเป็น network ที่ใช้ในการติดต่อสื่อสารระหว่าง container
  • Default network ของ docker คือ bridge
  • ใน mode bridge docker จะ สร้าง interface ขึ้นมาอีกอันหนึ่งคือ docker0 บน interface แรกของเครื่อง ในที่นี้คือ eth0 ในแต่ละ container ที่จะได้ veth ขึ้นมาเพื่อคุยกันภายใน namespace เดียวกัน ตามภาพ
  • สามารถดูสถานะของ bridge ได้จาก host โดยใช้ command bectl show

Docker Networking Drivers

  • Docker Network Drivers มีดังนี้

    • bridge: เป็น default network driver ถ้าไม่ระบุอะไรจะเป็น bridge ทั้งหมด เป็น Standalone mode
    • host: เป็น driver ที่ share network namespaces เดียวกับ host OS ปกติจะเป็น Standalone mode แต่สามารถ set up เป็น Swarm ได้ใน Docker 17.06 ขึ้นไป
    • overlay: ใช้ connect docker daemon หลายๆ ตัวเข้าด้วยกันเป็น swarm หรือ แค่อยากจะให้ docker daemon ที่อยู่ต่างเครื่องกันคุยกันได้ driver ตัวนี้ไม่ได้อาศัย routing ระดับ OS เพื่อให้มันคุยกันได้
    • macvlan: เราสามารถ assign MAC Address ไปยัง container ได้เลย ดังนั้นจึงเป็นเหมือนการ assign physical network ให้ container เลย เหมาะกับ legacy application ต้องการ physical interface
    • none: ไม่ assign interface ให้ container เลย (disable container networking) ดังนั้นใน container จะเห็นแค่ localhost interface
  • ตัวอย่าง Commands ที่ใช้ในการจัดการ container networking

Commands จุดประสงค์
docker network ls list network ทั้งหมด
docker network inspect <network_id> ตัวสอบรายละเอียดของ network
docker container run -it --network=none alpine sh run container โดยระบุ driver ของ container เป็น none นั้นคือ isable container networking
docker container run -it --network=container:web alpine sh run container ให้มี network เดียวกับ container ชื่อ web โดย ทั้ง 2 containers จะมี IP เดียวกันเลย
docker network create mynet create network ชื่อ mynet แต่เราไม่ได้ ระบุ driver ดังนั้น จะเป็น bridge

Container Networking Standard Specifications

Docker มีหลักๆ 2 Specifications ดังนี้

  • Container Network Model (CNM):
    • ริเริ่มโดย Docker
    • ใช้ libnetwork
    • มี build-in network driver
    • support 3rd party driver เช่น Cisco, Calico, Kuryr, Weave, etc
CNM
Source: thenewstack.io
  • Container Network Interface (CNI):
    • ริเริ่มโดย CoreOS
    • สามารถทำงานได้ใน container runtime ที่ต่างกัน
    • สามารถใช้ได้กับ Container Orchestrator เช่น Kubernetes, Mesos และ Cloud Foundry
    • support 3rd party driver เช่น Weave, Calico, etc
    • หลักการทำงานคือ container runtime จะ create namespace และ ให้ driver เป็นคน assign IP มาให้ container runtime อีกที
CNI
Source: thenewstack.io

rkt Networking

rkt support 3 modes

  • none: ไม่ assign interface ให้ container เลย โดย ใน container จะเห็นแค่ localhost interface
none
Source: CoreOS.com
  • host: container จะ share namespace กับ host
host
Source: CoreOS.com
  • container (default):
    • ใช้ PTP Plugin ซึ่งจะสร้าง veth pair ระหว่าง host และ pod
    • ใช้ technic NAT และ Routing ในการติดต่อกับ external network
    • build-in network ประกอบด้วย
    • ptp: จะสร้าง veth pair ระหว่าง pod และ host interface
    • bridge: จะสร้าง veth pair ระหว่าง pod และ bridge interface
    • macvlan: เป็นการสร้าง virtual interface ขึ้นมาบน physical master interface จากนั้น assign random MAC address เข้าไป
    • ipvlan: เป็นการสร้าง virtual interface ขึ้นมาบน physical master interface แต่ไม่ assign random MAC address เข้าไป แต่สามารถมี IP ที่ต่างไปจาก physical master interface
container
Source: CoreOS.com
  • ตัวอย่าง Commands ที่ใช้ในการจัดการ container networking
Commands จุดประสงค์
rkt run --interactive --net=host quay.io/coreos/alpine-sh:latest run rkt container โดยระบุ interface driver เป็นแบบ host
rkt run --port=80-tcp:8000 --insecure-options=image docker://nginx run rkt container โดย map port 8000 ของ host กับ port 80 ของ container
  • เราสามารถ create a user-defined bridge network ได้ดังนี้
# cat /etc/rkt/net.d/10-containers.conf
{
  "name": "containers",
    "type": "bridge",
    "bridge": "rkt1",
    "ipam": {
      "type": "host-local",
      "subnet": "10.1.0.0/16"
    }
}
Enter fullscreen mode Exit fullscreen mode


Chapter 11: Container Storage

UnionFS with Copy-on-Write

UnionFS เป็นการรวมเอา file system อื่นๆ มารวมกันเป็นเสมือน file system เดียว ให้จิตนาการเหมือนจานแก้วที่วางซ้อนกันเมื่อนเรามองจากด้านบนจะเห็นเหมือนเป็นจานจานเดียว

เมื่อ run container ขึ้นมา ephemeral storage จะถูกสร้างขึ้นมาด้วย unionFS ถ้ามองจาก ephemeral storage ของ container จะเห็นทั้ง file f1-f5

  • file f1 อยู่ในแต่ ephemeral storage ดังนั้นเมื่อ container ถูกลบไป file f1 จะหายไป
  • file f4 เมื่อถูกลบมันจะแค่ถูก mark เป็นสถานะ "white-out" ใน container แต่ file f4 ยังอยู่ใน base image layer
  • file f5 เมื่อถูกเปลี่ยนแปลงแก้ไขมันจะ effect แค่ใน ephemeral storage layer เท่านั้น (Copy-on-Write)

Managing Storage with Docker

  • สำหรับ ephemeral storage, Docker สามารถใช้ UnionFS with CoW กับ storage driver เหล่านี้ได้
    • Linux: aufs, btrfs, zfs, overlay, overlay2, devicemapper และ vfs
    • Windows: filter driver
  • สำหรับ persistent storage, Docker ใช้ feature volume ซึ่งมีทั้ง

    • Volumes เป็นการ create docker volume ขึ้นมาให้ mount
    • Bind mounts คือการ mount directory ของ host OS มาใช้ใน container
    • tmpfs mounts คือการ mount non-persistent storage
    • named pipes ใช้ในการ run 3rdParty plugin เช่น Flocker, GlusterFS, REX-Ray, gce-docker, HPE 3Par Volume เป็นต้น เพิ่มเติม
  • ตัวอย่าง Commands ที่ใช้ในการจัดการ container storage

Commands จุดประสงค์
docker volume create my-vol สร้าง container volume ขึ้นมา (defalt เป็น local)
docker volume ls list volume ในระบบ
docker volume inspect my-vol แสดงรายละเอียดของ volume
docker volume rm my-vol ลบ container volume
docker run -d --name devtest --mount source=myvol2,target=/app nginx:latest run container โดยใช้ --mount ในการ mount volume "myvol2" กับ path /app ใน container
docker run -d --name=nginxtest -v nginx-vol:/usr/share/nginx/html:ro nginx:latest run container โดยใช้ -v ในการ mount volume "nginx-vol" กับ path /usr/share/nginx/html ใน container แบบ read-only mode

Note

  • ถ้าลบ container ไปแล้ว volume จะยังคงอยู่
  • ถ้าจะลบ container พร้อมกับ volume ให้เพิ่ม option -v ให้กับ docker conatiner rm command

rkt Volumes

  • rkt support volume 2 ชนิด คือ

    • Host Volumes (host): mount directory ของ host OS มาใช้ใน container (--volume NAME,kind=host,source=SOURCE_PATH,readOnly=BOOL)
    • Empty Volumes (empty): เป็นการ mount local storage ซึ่งจะถูกทำลายเมื่อ container ถูกลบ (--volume NAME,kind=empty,mode=MODE,uid=UID,gid=GID)
  • ตัวอย่าง Commands ที่ใช้ในการจัดการ container storage

Commands จุดประสงค์
rkt run --volume data,kind=host,source=/srv/data,readOnly=false example.com/app1 run container โดย mount host volume path /srv/data กับ container path /var/data แบบ read-write
rkt run --volume data,kind=empty,readOnly=false example.com/app1 run container โดย mount empty volume กับ container path /var/data แบบ read-write


Chapter 12: Build a Multi-Container Application with Docker-Compose

Name Solving Technique

  • 1st generation technique: ใช้ options --link ในการเชื่อมต่อระหว่าง container โดย Docker daemon จะเข้าไป inject alias record ใน /etc/hosts ของ containers
  • 2nd generation technique: ใช้ dns-like feature ที่มาพร้อมกับ Docker engine

Docker Compose

docker-compose เป็น command ที่อ่าน Compose file ใน YAML format แล้วทำการ start container ขึ้นมาตามที่เราระบุไว้ใน Compose file นั้น

โดยในแต่ละครั้งที่ run Compose file docker-compose จะสร้าง custome network เพื่อใช้กับ containers ที่ระบุไว้ใน Compose file นั้นๆ

  • ตัวอย่าง Compose file
version: "3.7"

services:
  wordpress:
    image: wordpress
    ports:
      - "8080:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: vip

  mysql:
    image: mysql
    volumes:
       - db-data:/var/lib/mysql/data
    networks:
       - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: dnsrr

volumes:
  db-data:

networks:
  overlay:
Enter fullscreen mode Exit fullscreen mode
  • ตัวอย่าง Commands ที่ใช้ในการจัดการ container storage
Commands จุดประสงค์
docker-compose up start containers และ configure ต่างๆ ใน Compose file ใน foreground mode
docker-compose up -d start containers และ configure ต่างๆ ใน Compose file ใน background mode
docker-compose ps list containers ที่ create ไป
docker-compose stop stop containers ที่ create ไป
docker-compose rm ลบ containers ที่ create ไป


Chapter 13: Introducing Docker APIs

Docker Remote APIs

เนื่องจาก docker return ค่าเป็น minified json ดังนั้น command ที่สำคัญต้องลงเพิ่มเพื่อทำให้ เป็น pretty json คือ jq

โดย default Docker daemon bind UNIX socket ดังนั้นเราสามารถ curl UNIX socket ได้ดังนี้

  • curl --unix-socket /var/run/docker.sock http:/info | jq
  • curl --unix-socket /var/run/docker.sock http:/images/json | jq
  • curl --unix-socket /var/run/docker.sock http:/containers/json | jq

Docker client library

  • Official SDK จะมี 2 ภาษาคือ Go และ Python แต่ก็ยังมี Unofficial SDK ภาษาอื่นๆ อีก อ่านเพิ่มเติม
  • ตัวอย่าง การใช้งาน Python SDK
    • Install library: pip install docker
    • Coding
# import library
import docker
# connect to docker daemon 
client = docker.DockerClient(base_url='unix://var/run/docker.sock') 
# run containers
client.containers.run("ubuntu:latest", "echo hello world")
# list containers
client.containers.list()
# list image
client.images.list()
Enter fullscreen mode Exit fullscreen mode


Chapter 14: Docker Tips and Tricks

Tips and Tricks

  • Docker มี auto completion นะใช้ซะ ชีวิตจะดีขึ้น
  • สามารถใช้ GO templates ในการเลือก output จาก docker inspect ได้
# docker container inspect --format '{{.NetworkSettings.IPAddress}}' <container_id/name>
172.17.0.6
Enter fullscreen mode Exit fullscreen mode
  • filters with Docker sub-commands
# docker container ls -a --filter 'exited=0'
CONTAINER ID IMAGE        COMMAND                CREATED         STATUS                     PORTS       NAMES
bd0936a70412 nginx:alpine "nginx -g 'daemon off" 7 minutes ago   Exited (0) 47 seconds ago              determined_dijkstra
3397ab1b421b alpine       "sh"                   8 minutes ago   Exited (0) 7 minutes ago               awesome_galileo
Enter fullscreen mode Exit fullscreen mode
  • ดูการใช้งาน disk space สำหรับแต่ละ container
# docker system df -v
Images space usage:

REPOSITORY      TAG             IMAGE ID        CREATED
SIZE            SHARED SIZE     UNIQUE SIZE     CONTAINERS
nginx           latest          cc1b61406712    13 days ago
181.8 MB        0 B             181.8 MB        1
alpine          latest          88e169ea8f46    5 weeks ago
3.984 MB        0 B             3.984 MB        2

Containers space usage:
CONTAINER ID    IMAGE           COMMAND                 LOCAL VOLUMES
SIZE            CREATED         STATUS                  NAMES
f3686500c54c    alpine          "sh"                    1
86 B            6 minutes ago   Up 6 minutes            cmyvol
3bb26bfde13d    alpine          "sh"                    1
22 B            20 minutes ago  Up 20 minutes           cvol
d35e448942a7    nginx           "nginx -g 'daemon ..."  0
0 B             54 minutes ago  Created                 web1

Local Volumes space usage:
VOLUME NAME                                                         LINKS   SIZE
c2842864d4fe791d8a9615a3724f684503d554b61fbbfc58b4c91a45f1afa03f    1       0 B
myvol                                                               1       37 B
Enter fullscreen mode Exit fullscreen mode
  • ลบ docker image ที่ไม่ได้ใช้เพื่อ clean up host disk usage
docker system prune -a
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
peepeepopapapeepeepo
Sawit M.

Posted on January 7, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

LFS253: Containers Fundamentals
lecture LFS253: Containers Fundamentals

January 7, 2020