ก่อนจะเริ่มต้นการเดินทางเข้าสู่ Kubernetes
TLDL; ตั้งใจเขียนบทความเกี่ยวกับ Kubernetes มาซักพักนึง แต่ก็ผลัดมาตลอด สุดท้ายได้โอกาสเริ่มซะที บทความชุดนี้อาจจะไม่บอกครบทุกเรื่อง เพราะถ้าบอกทุกเรื่อง ผู้อ่านคงหาอ่านเอาเองได้จาก Official Document
ก้าวแรกกับ Kubernetes (อ่านว่า คู-เบอ-เน-เทส|ทีส) ไม่ใช่เรื่องของ Kubernetes แต่เป็นเรื่อง Container พูดถึง Container เราก็มักจะนึกถึง Docker ด้วยเหตุผลที่ว่า Docker เป็นรายแรกที่ทำให้ Container ป๊อบปูล่า ฮิตติดหู ผมเองก็ใช้คำว่า Docker กับ Container สลับกันในความหมายเดียวกัน (ออกตัวไว้ก่อนเลย)
แล้ว Container นี่มันอะไรยังไง? ลองมาเปรียบเทียบ Container กับรุ่นพี่ๆกันดู
รุ่นแรก
โบราณที่สุด (ที่ผมเคยใช้) เป็น Bare Metal เครื่องหนึ่งเครื่อง จะรันกี่โปรแกรม (App) ก็รันไป สำคัญที่ว่า Libraries (.dll, .a หรือ .so) กับพวกโปรแกรมพื้นฐาน ( awk
, sed
, tar
, etc) จะต้องไม่ชนกัน (Conflict) ถ้าชนกันก็ต้องหาทางแก้กันไป ไม่ก็เลือกรันแค่ App นึง ระบบแบบนี้มีข้อดีตรงที่ทำงานได้เร็วสุด เพราะว่ามีจำนวนส่วนต่างๆ (Layers) น้อยที่สุด ไม่มีส่วนไหนที่เกินจำเป็นพื้นฐานเลย (Zero Overhead) ข้อเสียคือจัดการลำบากสุด
รุ่นสอง
เป็น Virtualization จาก Server เครื่องนึง เราสามารถสร้าง Server จำลองได้หลายเครื่อง และใน Server จำลองแต่ละเครื่องสามารถลง OS และโปรแกรมต่างๆได้โดยไม่ไปกวนกัน (Conflict) ระบบส่วนใหญ่ในปัจจุบันจะย้ายมาเป็นแบบนี้เกือบทั้งหมดแล้ว (นอกจากบางงานที่ยังจำเป็นต้องใช้ Bare metal)
ในการใช้งานจริงเราจะมีเครื่อง Server หลายๆเครื่อง ไม่ได้มีเครื่องเดียวเหมือนในรูป ทุกเครื่องทำงานร่วมกันเป็น Cluster รายละเอียดส่วนนี้ขอเว้นไว้แค่นี้ ไม่งั้นจะนอกเรื่องไปไกลขึ้นอีก
รุ่นเรา
เป็นรุ่น Containerization ในรูปจะอยู่แถวขวาสุด เพิ่มชั้นสี่ส้มมาจัดการ Containers บางที่ก็รวม Guest OS, Hypervisor กับ Container Engine ไว้ด้วยกันเป็น Layer ก็มี แต่นั่นไม่ใช่แบบที่คนหมู่มากติดตั้ง ซึ่งจะเหมือนตามในรูปมากกว่า
แล้วมันดียังไง? แต่ละชุดของ App+Libs+Bins ไม่จำเป็นต้องรัน Guest OS ขึ้นมาโดยเฉพาะ แล้วเจ้า Guest OS เนี่ย จริงๆแล้วมันหนาเทอะทะมากกว่า Container Engine เยอะ พอมาใช้ Container เราจะสามารถรันหลายโปรแกรมที่เมื่อก่อนไม่สามารถรันในเครื่องเดียวกันได้ (Guest OS เดียวกัน)
ข้อดีอีกข้อคือ Container เนี่ยรันจาก Container Image (หลังจากนี้จะเรียกสั้นๆว่า Image) ซึ่งเป็นสิ่งเดียวกันตั้งแต่ครั้งแรกที่มันโดน Build + รันในเครื่องแรก + เครื่องสอง สาม สี่ห้า จนไปถึงเครื่อง Production ข้อดีข้อนี้จะทำให้ประโยคยอดฮิตกลายเป็นอดีต It works on my computer!
เริ่มเล่นละนะ
อารัมภบทมาซะเยิ่นยาว มาลองเริ่มเล่นกันซักที
ข้อหนึ่ง ลงโปรแกรม Docker Desktop โปรแกรมนี้ใช้ได้ทั้ง Mac และ Windows จากเว็บ Docker เอง โปรแกรมลงไม่ยาก ก็กดๆคลิกๆไปตามถนัดลงแล้วจะได้ icon ปลาวาฬแบกตู้ containers โผล่มาให้เห็น
เพิ่มเติมสำหรับคนที่ใช้ Windows Subsystem for Linux (WSL) สามารถใช้ Docker client ใน Linux ต่อเข้า Docker Desktop ที่รันใน Windows ได้ ใครไม่ใช้แบบนี้ ข้ามส่วนนี้ไปได้เลย
ขั้นแรก config ให้ Docker เปิดพอร์ตรอไว้เลย
สเต็ปสองก็ชี้ Docker Host ไปที่ Docker Desktop
export DOCKER=tcp://127.0.0.1:2375สุดท้ายก็ลง Docker CLI สำหรับ Ubuntu ลงด้วยคำสั่ง
sudo apt-get install docker-ce-cli
ปิดท้ายด้วยคำสั่งพื้นฐานสำหรับ Docker
ถ้าเราคิดซะว่า Container เป็นเหมือน Virtual Machine (VM) เครื่องนึง คำสั่งที่เราต้องการก็ไม่มีอะไรมากไปว่า เปิด-ปิด-ต่อเข้าเครื่อง-ลบทิ้ง เพิ่มมาอีกนิดก็จะเป็น เปิด Firewall กับทำ Port Mapping ซึ่งเราอาจจะไม่ได้ทำใน VM
ส่วน Image ก็จะเหมือนการทำ Zip Archive หรือ ISO File แต่จะง่ายกว่า ซึ่ง Image จะทำเป็น Layer ตยช (ตัวอย่างเช่น) Layer C
สร้างจาก Layer B
(ซึ่งสร้างจาก Layer A
อีกที) เรื่อง Image นี่เอาไว้เรามาว่ากันอีกที สำหรับตอนนี้ ลองใช้ Image ของคนอื่นไปก่อน (เหมือนกับที่เราไม่ได้สร้าง ISO File เอง แต่ดาวน์โหลด Ubuntu ISO มาใช้เพื่อลง Ubuntu Linux)
เปิดเครื่อง Web Server (Container)
$ docker container run -d nginx ced7a1d474a10b6e4e0d2e23b47585d7772a481a6a8fd5b0b1aeca038b6ef05d
เรากำหนด -d
เพื่อให้ Container รันด้านหลัง (Background/Detached) เราจะๆได้ ID เป็นชุด Hexadecimal Unique ID ชุดนึง ซึ่งเราสามารถเราไปใช้เลือกว่าจะสั่งงาน Container ไหนในตอนหลังได้
ดูรายชื่อ
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ced7a1d474a1 nginx “nginx -g ‘daemon of…” About a minute ago Up About a minute 80/tcp ecstatic_hertz
คำหลังสุด (ecstatic_hertz) เป็นชื่อ Container ซึ่งถ้าเราไม่กำหนด Docker Engine จะตั้งมาให้เราอัตโนมัติ ถ้าผมลองสร้าง Container อีกอันด้วยคำสั่งเดิม ผมก็จะได้ชื่อใหม่ที่ไม่ซ้ำกับชื่อเดิมเสมอ เราสามารถกำหนดชื่อ Container โดยใช้พารามิเตอร์ --name
เช่น docker container run -d --name web-server nginx
ปิดเครื่อง
$ docker container stop ecstatic_hertz ecstatic_hertz
การกำหนดว่าจะปิด (และสั่งงานอื่น) สามารถใช้ชื่อหรือ ID ที่เราได้มาก่อนหน้าได้ การใช้ ID ยังพิเศษไปอีกตรงที่เราไม่ต้องพิมพ์ให้ครบก็ได้ แค่สามสี่ตัวอักษรก็เพียงพอ ขอแค่ให้มันกำหนด Container ได้ตัวเดียว เช่นในตัวอย่าง ผมสามารถปิด Container ได้ด้วยคำสั่ง docker container stop ced7
แต่ถ้าเราใช้ชื่อ จะต้องพิมพ์ให้ครบถ้วนทุกตัวอักษร
ถ้าเราลอง ls
ดูจะไม่เห็น ecstatic_hertz แล้ว แต่จริงๆแล้ว ecstatic_hertz ยังอยู่ เราต้องเพิ่มพารามิเตอร์ -a
เข้าไปแบบนี้ docker container ls -a
จึงจะเห็นทุก Container รวมถึง Container ที่ซ่อนอยู่ด้วย
เปิดเครื่องพร้อมเปิด Firewall และทำ Port Mapping
$ docker container run -d -p 82:80 nginx adbe9c6247cbb69a2493eb501178455c08f1b75ba32ab22ecd0abbf70b869619
เพิ่มพารามิเตอร์ -p 82:80
เพื่อจะ Map Port 82 ที่เครื่องของเราเข้าไปที่ Port 80 ของ Container ถ้าเรา docker container ls
จะได้ข้อมูลเกี่ยวกับ Network แบบนี้ 0.0.0.0:82->80/tcp
และถ้าจะ Map มากกว่าหนึ่ง Port เราสามารถกำหนด -p
ได้หลายครั้ง
ต่อเข้าเครื่อง
$ docker container exec -it adbe sh
พารามิเตอร์ -it
เพื่อกำหนดให้เป็น Interactive Terminal ตามด้วยชื่อหรือ ID ของ Container และคำสั่งที่จะรัน คำสั่งที่จะรันนี้จะ Path เต็มเช่น /bin/sh
หรือจะใช้แค่ชื่อคำสั่งก็ได้
ลบ Container
$ docker container rm ced7
ถ้าเรามองว่า Container ก็เหมือน Mini VM ดังนั้น เราก็ควรจะลบ VM ที่เราไม่ได้ใช้ จะได้ไม่รก ถ้าจะลบหลายๆ Container เราสามารถใช้ ID หรือชื่อ ต่อๆกันไปตามที่ต้องการได้ หรือถ้าจะลบทุกๆ Container ที่หยุดทำงานไปแล้ว สามารถใช้คำสั่ง prune
ได้
$ docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y Deleted Containers: 84e245645e1e338a8e4fd70c95e964d5cf4c861d65ff33999adb5e8188e0a8d6 c8cc3a0e8ec9a0c0a4df10ef1c20d06a78c3c5c2625bad6f2d6257985b2a876d b95ee9202ec4dff59c7fb658f304c042f4dc60536f98f17dd1535998e1d071d4 bde4f18ef33139e3f714b848ddc7bbf98f0fc58ae3f816f12bdae8b95f5543b8
Total reclaimed space: 27.38MB
แล้วถ้าจะ รัน Container ของ Ubuntu 20.04 ละ
$ docker container run -d ubuntu:20.04 7ecfa780a33541c7435ce385851084a4f9599f7cd8d602752254b5197274679e $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7ecfa780a335 ubuntu:20.04 "/bin/bash" 8 seconds ago Exited (0) 7 seconds ago quirky_clarke
อ้าว! ทำไม Status เป็น Exited ซะละ? ทุกๆ Container จะต้องเริ่มด้วยการรันคำสั่งหนึ่งคำสั่ง และคำสั่งนั้นจะต้องรันค้างไว้ ถ้าคำสั่งจบหรือมีปัญหาและหยุดการทำงาน Container นั่นก็จะตายไปด้วย
สำหรับกรณีของเรา สามารถรันได้สองแบบคือเป็น Interactive รันแล้วได้ Shell มา และออกจาก Shell ก็ปิด Container หรือแบบที่สอง เราสามารถรันคำสั่งให้ค้างเติ่งอยู่อย่างนั้น แล้วค่อยรัน Shell แบบที่เคยทำมาก่อนหน้า
แบบแรก
$ docker container run -it ubuntu:20.04 bash root@05b053dbc136:/# exit exit $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS 05b053dbc136 ubuntu:20.04 "bash" About a minute ago Exited (0) About a minute ago heuristic_meitner
จะเห็นว่า Container หยุดการทำงานไปหลังจากที่เราออกจาก Shell ซึ่งเป็นคำสั่ง (Process) แรกและคำสั่งเดียวของ Container
แบบสอง
$ docker container run -d ubuntu:20.04 tail -f /dev/null 6f4a2225dc15c04e36bba5fee46c8e7dd5dd41574622f1001d81fe66cb78d670 $ docker container exec -it 6f4a bash root@6f4a2225dc15:/# exit $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6f4a2225dc15 ubuntu:20.04 "tail -f /dev/null" 29 seconds ago Up 28 seconds objective_fermi
คำสั่ง tail -f /dev/null
ไม่กิน CPU และค้างไปอย่างนั้นจนกว่าเราจะสั่งให้มันหยุดเอง จากนั้นเราค่อยต่อเข้า Container เราสามารถต่อเข้าออกไปได้เรื่อย และปิด Container ตอนที่เราต้องการ
สำหรับ Docker Image เราจะกลับมาดูวิธีการสร้างกันอีกทีตอนหลัง (คุยกันตอนนี้มันจะยาว) ตอนนี้มาดูคำสั่งพื้นฐานที่ต้องรู้ซักสองสามคำสั่ง
- ดู Image ที่อยู่ในเครื่อง
docker image ls
- ดาวน์โหลด Image มาจาก Docker Hub
docker image pull nginx
- ลบ Image ที่เราไม่ได้ใช้แล้ว
docker image prune -f
แต๊ง แต๊ง หมดยก คราวหน้าเรามาต่อกันอีกที สัญญาว่าจะได้ลองเล่น Kubernetes กันละครับ