Sawit M.
Posted on January 7, 2020
Index
- What's Containers?
- The History of Containers
- Building Block
- Container Runtimes
- Docker for Mac and Windows
- Accessing a Remote Docker Daemon
- Container Operations
- Working with Image
- Working with Dockerfiles
- Container Networking
- Container Storage
- Build a Multi-Container Application with Docker-Compose
- Introducing Docker APIs
- Docker Tips and Tricks
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 ของมัน เห็น
-
/ (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 ได้
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 มีโครงสร้างการทำงานเป็น 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
- Community Edition (CE) - Free
- การนับ version ของ Docker
- ก่อน มีนาคม 2017, จะนับแบบ
Semantic Versioning
คือ Major.Minor.Patch - หลังจากนั้น, จะนับแบบ
Calendar Versioning
คือ YY.MM-ce และ YY.MM-ee
- ก่อน มีนาคม 2017, จะนับแบบ
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
-
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
-
Mac: ใช้ Hardware Virtualization ในระดับ OS และ Unikernel Technology ที่เพิ่งไป acquire มา
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 ?
- process ถูกสร้างขึ้นมาใน host
- process ถูกผูกเข้ากับ namespaces ของ resources เช่น pid, net และ uts
- control group configuration ถูก apply ไปยัง process เพื่อ limit resources
- 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 instructionRUN
,CMD
และENTRYPOINT
-
WORKDIR
: set working directory สำหรับการ run instructionRUN
,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 เพื่อใช้กับ instructionSHELL
default shell ของ Linux คือ["/bin/sh", "-c"]
และของ Windows คือ["cmd", "/S", "/C"]
-
-
Instruction format
-
Shell form:
<Instruction> <command>
-
Exec form:
<Instruction> ["executable", "param1", "param2", ...]
-
Shell form:
-
Type of Instruction
-
Build time:
RUN
,ADD
,COPY
,USER
,WORKDIR
,ONBUILD
,SHELL
, etc -
Run time:
CMD
,ENTRYPOINT
-
Build time:
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
-
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 อีกที
rkt Networking
rkt support 3 modes
-
none
: ไม่ assign interface ให้ container เลย โดย ใน container จะเห็นแค่ localhost interface
-
host
: container จะ share namespace กับ host
-
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
- ตัวอย่าง 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"
}
}
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
-
Linux:
-
สำหรับ 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
)
-
Host Volumes (
ตัวอย่าง 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:
- ตัวอย่าง 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
- Install library:
# 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()
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
- 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
- ดูการใช้งาน 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
- ลบ docker image ที่ไม่ได้ใช้เพื่อ clean up host disk usage
docker system prune -a
Posted on January 7, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.