มาลอง Kubernetes ด้วย Minikube กันเถอะ
สงสัยมานานแล้วว่า Kubernetes มันคืออะไร วันนี้เลยจะมาลองเล่น Kubernetes ดู แต่ว่าจะใช้อย่างไร Document ของ Kubernetes ได้แนะนำให้ใช้ Minikube สำหรับเริ่มต้นเรียนรู้ Kubernetes ดังนั้นผมจึงจะมาลอง Minikube เพื่อให้รู้ว่า Kubernetes มันทำงานเบื้องต้นอย่างไร โดยอ้างอิงจาก Hello Minikube
โดยเป้าหมายของบทความนี้ก็จะสร้างแอพพลิเคชัน Hello World ของ Node.js ง่ายๆ เพื่อจะรันบน Kubernetes ซึ่งจะแสดงให้เห็นว่าโค้ดที่เราพัฒนาในเครื่องเราสามารถจะเอาขึ้นไปบน Docker container image และรันบน Minikube ได้อย่างไร
Kubernetes คืออะไร?
เป็น production-ready และ open-source platform ที่สร้างจากประสบการณ์ที่สะสมมาของ Google ใน container orchestration (จัดเรียงหรือควบคุม) ซึ่งจะช่วยทำให้มั่นใจว่า containerized application ทำงานเมื่อคุณต้องการ
Kubernetes is a production-grade, open-source platform that orchestrates the placement (scheduling) and execution of application containers within and across computer clusters.
Minikube เป็นเครื่องมือที่ง่ายที่สุดที่เราจะเรียนรู้การรัน Kubernetes โดยจะสามารถรัน single-node Kubernetes cluster ข้างใน VM ในเครื่องเรา ซึ่งจะรองรับ feature ต่างๆ ของ Kubernetes
ติดตั้งก่อนที่จะเริ่ม
- Node.js เพื่อใช้ในการรันแอพพลิเคชัน
- Docker ใช้สำหรับสร้าง Docker container image
ติดตั้ง Minikube
ก่อนอื่นต้องติดตั้ง minikube ในเครื่องของเราก่อน ซึ่งสามารถตรวจสอบวิธีติดตั้งได้ ที่นี่ แต่สำหรับ macOS สามาใช้ brew cask install minikube
ติดตั้ง Kubernetes-cli
หลังจากติดตั้ง minikube แล้วก็ติดตั้ง kubernetes-cli หรือ kubectl ด้วยคำสั่ง brew install kubernetes-cli
บน macOS
สร้าง Kubernetes cluster ด้วย Minikube
ตรวจสอบว่า docker รันแล้วในเครื่องของเราด้วยคำสั่ง จะแสดง images ทั้งหมดในเครื่องของเรา แต่ถ้าลง docker ใหม่ๆ จะไม่มี images แสดง
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
สร้าง cluster ด้วย Minikube บน VM ด้วยคำสั่ง จะสังเกตเห็นการทำงานของการเริ่มต้น cluster จนเสร็จสิ้น
$ minikube start
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
ตรวจสอบ cluster ที่เราสร้างด้วย kubectl
ดังนี้
$ kubectl cluster-info
Kubernetes master is running at https://192.168.99.100:8443
KubeDNS is running at https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxyTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
ตรวจสอบ node ด้วยคำสั่ง จะเห็นได้ว่า minikube รันอยู่
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready master 12m v1.10.0
เปิด Kubernetes dashboard ของ Minikube ด้วยคำสั่ง จะเปิด dashboard บน web browser ให้โดยอัตโนมัติ ซึ่งจะแสดงรายละเอียดทั้งหมดของ cluster
$ minikube dashboard
สร้างแอพพลิเคชัน Node.js
สร้างโฟล์เดอร์ hellonode และสร้างไฟล์ server.js
ด้วยโค้ดง่ายๆ สำหรับสร้าง node.js web server
vrvrลองรันแอพพลิเคชันด้วยคำสั่ง
$ node server.js
เราจะสามารถเข้าถึง web server ได้ด้วย URL localhost:8080
โดยจะเห็นข้อความ Hello World! และสามารถหยุด web server ด้วย Ctrl+C
สร้าง Docker container image
สร้างไฟล์ Dockerfile ในโฟล์เดอร์ hellonode เพื่อสร้าง docker image โดย extend จาก Node.js image และใส่ไพล์ server.js
เข้าไปและก็สั่งคำสั่งรันแอพพลิเคชัน
สำคัญ ในบทความนี้เราใช้ Minikube แทนที่จะ push Docker image ไปยัง registry ดังนั้นเราจะต้อง build image โดยใช้ Docker daemon ใน Minikube VM ดังนั้นจะต้องใช้คำสั่งนี้ เพื่อใช้ Docker daemon ของ Minikube
$ eval $(minikube docker-env)
สร้าง image ด้วยคำสั่ง docker build
ตามด้วย -t hello-node:v1
เพื่อกำหนด tag ให้กับ image และ .
เพื่อเอาไฟล์ทั้งหมดในโพล์เดอร์ที่ทำงานอยู่สร้างเป็น image
$ docker build -t hello-node:v1 .
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM node:6.9.2
6.9.2: Pulling from library/node
75a822cd7888: Pull complete
57de64c72267: Pull complete
4306be1e8943: Pull complete
871436ab7225: Pull complete
0110c26a367a: Pull complete
1f04fe713f1b: Pull complete
ac7c0b5fb553: Pull complete
Digest: sha256:2e95be60faf429d6c97d928c762cb36f1940f4456ce4bd33fbdc34de94a5e
Status: Downloaded newer image for node:6.9.2
---> faaadb4aaf9b
Step 2/4 : EXPOSE 8080
---> Running in 47bc498bf19d
Removing intermediate container 47bc498bf19d
---> 7396bf7e77dc
Step 3/4 : COPY server.js .
---> 2807abb9a519
Step 4/4 : CMD node server.js
---> Running in bd5b7b9f2781
Removing intermediate container bd5b7b9f2781
---> 158b037ad488
Successfully built 158b037ad488
Successfully tagged hello-node:v1
เราสามารถตรวจสอบ image ที่สร้างขึ้นด้วยคำสั่ง docker images
จะแสดงรายการ image ทั้งหมดที่มีอยู่ในเครื่อง จากเดิมที่ไม่มี image
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-node v1 158b037ad488 2 minutes ago 655MB
สร้าง Deployment
Kubernetes Pod เป็นกลุ่มของ 1 หรือ มากกว่า Container ผูกเข้ากันเพื่อจุดประสงค์ของ adminitration และ networking ซึ่ง Pod ในบทความนี้จะมีเพียง 1 container เท่านั้น
Kubernetes Deployment จะตรวจสอบสถานะของ Pod และ restart Container ของ Pod ถ้าในกรณีที่มันหยุดทำงาน โดยที่ Deployment เป็นวิธีแนะนำเพื่อจัดการ สร้าง และ scale Pod
ใช้คำสั่ง kubectl run
เพื่อสร้าง Deployment เพื่อที่จัดการ Pod ซึ่งใน Pod จะรัน container ที่สร้างจาก docker image hello-node:v1
ที่เราสร้างขึ้น เซ็ต flag --image-pull-policy
เป็น Never
เพื่อระบุว่าใช้ local image แทนที่จะ pull จาก Docker registry
$ kubectl run hello-node --image=hello-node:v1 --port=8080 --image-pull-policy=Never
deployment.apps/hello-node created
ตรวจสอบว่า Deployment ที่สร้างขึ้น ดัวยคำสั่ง
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-node 1 1 1 0 1m
ตรวจสอบ Pod ที่รันอยู่ใน Deployment ด้วยคำสั่ง
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-node-57c6b66f9c-djl6p 0/1 ErrImageNeverPull 0 4m
ดู kubernetes
clusters config ด้วยคำสั่ง
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority: /Users/Phayao/.minikube/ca.crt
server: https://192.168.99.100:8443
name: minikube
contexts:
- context:
cluster: minikube
user: minikube
name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
client-certificate: /Users/Phayao/.minikube/client.crt
client-key: /Users/Phayao/.minikube/client.key
สร้าง Service
โดยค่าเริ่มต้น Pod เข้าถึงได้จาก IP address ภายใน Kubernetes cluster เท่านั้น เพื่อทำให้ container hello-node
เข้าถึงได้จากภายนอกนั้น เราจะต้อง expose Pod ด้วย Kubernestes Services
จาก Deployment machine ของเรา เราสามารถ expose Pod ให้ภายนอกเข้าถึงได้ด้วยคำสั่ง kubectl expose
$ kubectl expose deployment hello-node --type=LoadBalancer
service/hello-node exposed
และตรวจสอบ Service ที่สร้างขึ้นด้วยคำสั่ง
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.102.117.121 <pending> 8080:31493/TCP 1m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h
ซึ่ง flag --type=LoadBalancer
เพื่อกำหนดว่าเราจะ expose Service สู่ภายนอกของ cluster ด้วย load balancer ซึ่งสามารถเข้าถึง cluster ด้วย IP address ภายนอก
ใน Minikube LoadBalancer
ทำให้เข้าถึง Service ผ่านคำสั่ง minikube service
$ minikube service hello-node
Opening kubernetes service default/hello-node in default browser...
จะเปิด web browser อัตโนมัติ โดยใช้ local IP address ที่ให้บริการแอพพลิเคชันของเรา และแสดงข้อความ “Hello World”
เราสามาถดู log ของ Pod ด้วยคำสั่ง
$ minikube logs hello-node-57c6b66f9c-djl6p
Scale Up/Down
เพื่อ Scale out Deployment จะทำให้แน่ใจว่า Pod ใหม่ ถูกสร้างขึ้นและ schedule ไปยัง Node ดัวยทรัพยากรที่มีอยู่ การ Scale จะเพิ่มจำนวนของ Pod ในสถานะที่ต้องการ โดยที่ Kubenetes จะยอมรับ autoscaling สำหรับ Pod ด้วย
เราจะ scale Deployment ของเราไปเป็น 4 replicas หรือขยายออกเป็น 4 Pod ดัวยคำสั่ง kubectl scale
ตามด้วย deployment type, ชื่อ และจำนวน instance ที่ต้องการขยาย
$ kubectl scale deployments/hello-node --replicas=4
deployment.extensions/hello-node scaled
ตรวจสอบ Deployment ที่เรา scale แล้ว ด้วยคำสั่ง get deployments
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-node 4 4 4 4 1h
จะเห็นได้ว่าจำนวนของ Pod ที่ scale แล้วมีจำนวนเท่ากับที่เราต้องการ
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
hello-node-57c8dd9df8-6hk2t 1/1 Running 0 6m 172.17.0.9 minikube
hello-node-57c8dd9df8-nz8v5 1/1 Running 0 18m 172.17.0.7 minikube
hello-node-57c8dd9df8-vr756 1/1 Running 0 6m 172.17.0.6 minikube
hello-node-57c8dd9df8-xn7jk 1/1 Running 0 6m 172.17.0.8 minikube
เพื่อตรวจสอบรายละเอียดของ Deployment ด้วยคำสั่ง describe deployments
$ kubectl describe deployments/hello-node
Name: hello-node
Namespace: default
CreationTimestamp: Tue, 07 Aug 2018 20:59:47 +0700
Labels: run=hello-node
Annotations: deployment.kubernetes.io/revision=2
Selector: run=hello-node
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: run=hello-node
Containers:
hello-node:
Image: hello-node:v2
Port: 8080/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Progressing True NewReplicaSetAvailable
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-node-57c8dd9df8 (4/4 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------Normal ScalingReplicaSet 24m deployment-controller Scaled up replica set hello-node-57c8dd9df8 to 1
Normal ScalingReplicaSet 24m deployment-controller Scaled down replica set hello-node-57c6b66f9c to 0
Normal ScalingReplicaSet 13m deployment-controller Scaled up replica set hello-node-57c8dd9df8 to 4
เพื่อ scale down Service ให้เหลือ 2 replicas ใช้คำสั่ง scale deployments
$ kubectl scale deployments/hello-node --replicas=2
deployment.extensions/hello-node scaled
ตรวจสอบ Deployment ที่เรา scale แล้ว ด้วยคำสั่ง get deployments
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-node 2 2 2 2 1h
จะเห็นได้ว่าจำนวนของ Pod เหลือเพียงเท่าที่เราต้องการ
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
hello-node-57c8dd9df8-nz8v5 1/1 Running 0 39m 172.17.0.7 minikube
hello-node-57c8dd9df8-xn7jk 1/1 Running 0 27m 172.17.0.8 minikube
Update แอพพลิเคชัน
แก้ไขไฟล์ server.js
ลองให้แสดงข้อความอื่นเช่น
build เวอร์ชั่นใหม่ของ Docker image (เป็นเวอร์ชั่น v2)
$ docker build -t hello-node:v2 .
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM node:6.9.2
---> faaadb4aaf9b
Step 2/4 : EXPOSE 8080
---> Using cache
---> 1d65026e61f4
Step 3/4 : COPY server.js .
---> 2a4a3b95174a
Step 4/4 : CMD node server.js
---> Running in 8b18614f4067
Removing intermediate container 8b18614f4067
---> 9432edca59c2
Successfully built 9432edca59c2
Successfully tagged hello-node:v2
update เวอร์ชั่นใหม่ของ Docker image ไปยัง Deployment ด้วยคำสั่ง
$ kubectl set image deployment/hello-node hello-node=hello-node:v2
deployment.extensions/hello-node image updated
ลองรัน app ของเราอีกครั้ง ด้วยคำสั่ง
$ minikube service hello-node
Opening kubernetes service default/hello-node in default browser...
หลังจากเปิด web browser จะเห็นได้ว่าข้อความเปลี่ยนไปดังที่เราแก้ไข แสดงว่า pod ถูก update เรียบร้อยแล้ว
Enable addons
Minikube สามารถมี build-in addons เสริมมาให้ ดังนั้นเราสามารถ เปิด/ปิด ได้ ใน local Kubenetes environment
แสดงรายการของ addons ด้วยคำสั่ง minikube addons list
$ minikube addons list
- addon-manager: enabled
- coredns: disabled
- dashboard: enabled
- default-storageclass: enabled
- efk: disabled
- freshpod: disabled
- heapster: enabled
- ingress: disabled
- kube-dns: enabled
- metrics-server: disabled
- nvidia-driver-installer: disabled
- nvidia-gpu-device-plugin: disabled
- registry: disabled
- registry-creds: disabled
- storage-provisioner: enabled
เปิด addons ด้วยคำสั่ง minikube addons enable heapster
$ minikube addons enable heapster
heapster was successfully enabled
ดู Pod และ Service ที่ได้ เปิด ด้วยคำสั่ง kubectl get
$ kubectl get po,svc -n kube-system
NAME READY STATUS RESTARTS AGE
pod/etcd-minikube 1/1 Running 0 22h
pod/heapster-tfq6v 1/1 Running 0 22hNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/heapster ClusterIP 10.99.11.40 <none> 80/TCP 22h
Clean up
ตอนนี้เรามาทำความสะอาดสิ่งที่เราสร้างขึ้นใน cluster โดยที่เราจะลบ Service และ Deployment
$ kubectl delete service hello-node
service "hello-node" deleted
$ kubectl delete deployment hello-node
deployment.extensions "hello-node" deleted
ลบ Docker image ด้วยคำสั่ง docker rmi
ในที่นี้จะลบทั้ง 2 เวอร์ชัน
$ docker rmi hello-node:v1 hello-node:v2 -f
Untagged: hello-node:v1
Deleted: sha256:2cb559e45536f214ddcf2bf3e95ef7f307be90b899bda76291b9
Deleted: sha256:613af895d7e25932973b1c622a9d6cedb2b2099509c51b89f903
Deleted: sha256:d00565ce39e09f55b729a6d7105540f0c085fb662f7484103dab
Untagged: hello-node:v2
Stop Minikube VM ด้วยคำสั่ง
$ minikube stop
Stopping local Kubernetes cluster...
Machine stopped.
$ eval $(minikube docker-env -u)
ลบ Minikube VM ด้วยคำสั่ง
$ minikube delete
Deleting local Kubernetes cluster...
Machine deleted.
สรุป
จากที่ลองใช้งาน Kubernetes ผ่าน Minikube นั้น เริ่มตั้งแต่สร้าง Cluster ขึ้นมา สร้างแอพพลิเคชัน Node.js อย่างง่าย และนำมาสร้างเป็น Docker container image หลังจากนั้นก็ deploy ไปเป็น Deployment พร้อมทั้ง expose Deployment ด้วย Service แล้วลอง scale up และ down ดูความสมารถการ scale ของ Kubernetes แล้ว enable addons ดู สุดท้ายก็ลบทุกสิ่งทุกอย่างที่สร้างมาทิ้ง
นอกจากนี้แล้วเว็บไซต์ของ Kubernetes ยังมีความรู้อีกมากมายที่จะทำให้เก่งขึ้น