Small Scale Kubernetes Part I: สร้างคลัสเตอร์ใน GKE

หลังจากเขียนเรื่อง Kubernetes ไปในบล็อคที่แล้ว ก็มีคนรีเควสมาว่าอยากให้เขียนเกี่ยวกับการใช้ Kubernetes สักหน่อย

จริงๆ เนื้อหาในบล็อคจะพยายามไม่เน้น howto อย่างนึงคือผมมองว่าบล็อคส่วนตัวไว้เขียนเรื่องส่วนตัวว่าเราทำอะไร เจออะไรมาดีกว่า แล้วก็วิธีการใช้งานก็อยากให้ศึกษาจากคู่มือของเค้าเองซะมากกว่า แต่สำหรับ Kubernetes นี่ต้องยกเว้นไว้หน่อยเพราะเว็บมันอ่านยากจริงๆ

ทีนี้ถัดมาก็นึกอยู่ว่าจะเขียนที่ไหนดี ที่บล็อคบริษัทก็น่าเขียน เพราะผมก็ implement Kubernetes ไว้ให้ แต่คิดว่าในสเกลนั้นถ้าเขียนออกไปคนอ่านอาจจะอยากรู้เรื่องการใช้งานใน scale ใหญ่มากกว่า ซึ่งก็ยังไม่คิดว่าพร้อมจะเล่าเท่าไร ก็เลยอยากจะเล่าในมุมของเว็บเล็กๆ ที่ใช้ Kubernetes ใน Production ซะมากกว่า

เปิดใช้ GKE

สำหรับการติดตั้ง Kubernetes ผมคงไม่เขียนถึงเพราะหลายๆ เหตุผลครับ

  1. ผมเคยใช้ kube-up ติดตั้งใน AWS แล้วอัพเกรดไม่ได้ (ของบริษัทใช้วิธีนี้อยู่) ซึ่งตอนหลัง Kubernetes ออกของใหม่มาแล้วแต่ผมยังไม่ได้ทดลอง
  2. ตอนนี้ Google Cloud และ Azure มีบริการ managed Kubernetes แล้ว (10 ปีก่อนถ้าบอกผมว่าผมจะมาเขียนขายของ Microsoft นี่ผมไม่เชื่อเลยนะ)
  3. บริการ managed Kubernetes ใน Google Cloud นั้นถ้าคลัสเตอร์ของเราขนาดไม่เกิน 5 nodes จะไม่คิดค่า master node ซึ่งถ้าไปลงเองก็จะต้องเสีย 1 เครื่องมาทำ นอกจากนี้ของ Google Cloud นี่ master มี SLA 99.95% เช่นเดียวกับ Compute Engine ด้วย เรียกได้ว่าทั้งประหยัดเงินและเสถียรกว่าด้วย

ฉะนั้นแล้วมาใช้ Google Cloud เถอะครับ ฮ่าๆ ซึ่งตัวบริการ managed Kubernetes ของ Google Cloud นั้นจะเรียกว่า Google Container Engine แต่ย่อว่า GKE เพราะถ้าเรียก GCE มันจะไปซ้ำกับ Compute Engine ก็เลยใช้ K จาก Kubernetes

สำหรับการสมัครนั้นก็สามารถเข้าไปที่ GKE Console กดสร้าง project แล้วสร้าง cluster ได้เลย (ถ้าสร้าง project ใหม่อาจจะต้องรอ activate ประมาณ 5 นาที) ซึ่งวิธีการก็คือ

  1. กด Create cluster กลางจอ (ในภาพผมมีเครื่องแล้วมันเลยอยู่ด้านบน)
  2. กรอกข้อมูลดังนี้
    • Name จะตั้งอะไรก็ได้
    • Zone เลือกเป็น asia-southeast1-a หรือ b ก็ได้ (ความแตกต่างแต่ละ Zone สำหรับของ asia-southeast1 หรือสิงคโปร์เนื่องจากเป็นโซนเปิดใหม่ก็จะยังไม่ต่างกันครับ)
    • Cluster version จะเลือกเป็นรุ่นล่าสุดก็ได้ หรือรุ่นเก่าก็ได้ แต่ถ้าจะใช้ของใหม่อย่าลืมอ่าน Release Note ก่อนเนื่องจากอาจจะมี bug
    • Machine type เลือกตามสะดวกครับ ปกติจะเลือกเป็น 1 vCPU มาให้ แต่เราสามารถลดลงเหลือ micro/small ก็ได้ มีข้อจำกัดคือถ้าใช้ micro จะต้องซื้อ 3 เครื่องขึ้นไป
      • 1 vCPU = 1 hyperthread
      • สำหรับเครื่อง f1-micro จะได้ 0.2 vCPU, g1-small จะได้ 0.5 vCPU ซึ่งหมายความว่า cpu usage เราจะใช้ได้ไม่เกิน 50% และอาจจะ boost เกินได้เป็นระยะสั้นๆ
      • อย่าลืมว่าเราสามารถมีหลายๆ เครื่องเป็นคลัสเตอร์ได้ ฉะนั้นไม่จำเป็นต้องเลือกใหญ่มากก็ได้ครับ คิดว่า 2 vCPU (n1-standard-2) น่าจะเหมาะที่สุดถ้ามีงบ (ซึ่งผมไม่มี) เนื่องจากจะได้ 1 physical core ไปเต็มๆ
    • Size จะเอากี่เครื่องก็ใส่ได้เลยครับ เครื่องเดียวก็ได้ ยกเว้นถ้าเลือก Machine type เป็น micro จะต้องซื้อ 3 เครื่อง
    • Node image แนะนำ Container optimized OS ครับ ซึ่งจะมีระบบ security ของ Google ด้วย แต่จะติดตั้งโปรแกรมนอก Docker ไม่ได้ ส่วน container-vm จะเป็นอิมเมจที่เบสมาจาก Debian สามารถลงโปรแกรมได้ (ความแตกต่าง)
      • Node มันอัพเกรดด้วยการลบสร้างใหม่ ฉะนั้นไม่ต้องคิดว่าจะได้ลงอะไรอยู่แล้วครับ
    • Automatic node upgrade/repair อันนี้ผมยังไม่เปิดเนื่องจาก Google บอกว่าหลังออกจาก Beta แล้วอาจจะคิดเงิน ก็เลยขอรอดูราคาก่อน
    • Legacy Authorization กด Enable ไว้
    • Logging and monitoring ถ้าลงทะเบียน Stackdriver monitoring ก็เปิดได้ครับ ถ้าไม่เคยลงทะเบียนไว้จะปิดก็ได้ หรือไปลงทะเบียนทดลองใช้ 30 วันฟรีก็ได้ (หลังหมดฟรีแล้วใช้ต่อได้ แต่จะโดนลดฟีเจอร์) ส่วน Logging ไม่แนะนำให้ปิดครับ
    • ในส่วน Advanced จะตั้งตามนี้ครับ
    • Basic Authentication/Client certificate Disable ไปได้เลย
    • Autoscaling จะเปิดไว้ก็ไม่เสียหายครับ ซึ่งถ้าเปิดจะให้ตั้งจำนวน node สูงสุดที่ต้องการได้
    • Preemptible nodes Disable ไว้ ถ้าเปิดแล้วจะใช้เครื่องราคาถูกกว่า แต่ใช้ไปสักพักจะโดนปิดเอง ซึ่งจะเหมาะกับ boost มากกว่าการใช้จริงจังครับ
    • Boot disk size in GB ปกติจะตั้งไว้ 100GB ลดได้ครับ แต่แนะนำว่าไม่ควรต่ำกว่า 30GB ไม่งั้น IO มันจะช้ามาก
    • Project access ไม่ต้องแตะส่วนนี้ครับ ถ้าเปิดสิทธิ์อะไรเพิ่มไว้มันจะทำให้ container ใน Cluster ทุกตัวสามารถใช้สิทธิ์ได้เลย ซึ่งเราควรจะแจก service account เองดีกว่า

หลังจาก create แล้วก็รอสร้างประมาณ 5 นาทีครับ ระหว่างนี้เราทำอย่างอื่นดีกว่า

ติดตั้ง Google Cloud SDK

เนื่องจากเราปิด authentication หมดทุกประเภทเลย วิธีเดียวที่เข้าได้คือจะต้องมี Google Cloud SDK ครับ ซึ่งผมใช้ Arch Linux ก็สามารถกดลงจาก AUR ได้เลย และอีกโปรแกรมหนึ่งที่ต้องลงคือ kubectl ซึ่งสามารถติดตั้งจาก Google Cloud SDK ก็ได้ หรือใน AUR ก็ได้

$ gcloud components install kubectl

(ผมไม่แน่ใจว่า Windows ลงด้วยวิธีนี้ได้หรือเปล่านะครับ)

แต่ถ้าขี้เกียจลงอะไรเยอะแยะ Google Cloud ก็มีของอำนวยความสะดวกให้เราครับ นั่นคือ Cloud Shell ซึ่งสามารถเปิดจากเมนูขวาบนได้เลยโดยไม่มีค่าใช้จ่ายใดๆ แถมลงของเล่นไว้ให้หมดแล้วด้วย

ลูกศร low cost มาก แต่คลัสเตอร์นั่นไม่ low cost เลย…

ถ้าจะใช้ Cloud Shell แนะนำให้ลง Chrome Extension ของเค้าด้วยครับ (กดจากเมนูซ้ายบนของหน้าต่าง shell ก็มีลิงค์เหมือนกัน) ซึ่งจะทำให้สามารถกดคีย์ลัดได้ทุกปุ่ม

อย่างแรกที่จะต้องทำก็คือ login เข้า Google Cloud ก่อนครับ ซึ่งถ้าใครใช้ Cloud Shell ก็ข้ามไปได้เลย

$ gcloud auth login
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?redirect_uri=....

WARNING: `gcloud auth login` no longer writes application default credentials.
If you need to use ADC, see:
  gcloud auth application-default --help

You are now logged in as [email].
Your current project is [project].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID

พอพิมพ์คำสั่งนี้แล้วจะเด้ง browser ขึ้นมา ก็ให้ login และอนุมัติ API access ครับ เสร็จแล้วก็ปิดหน้าต่างกลับไปที่ shell ต่อได้เลย

ขั้นถัดมาเราจะเลือก project ที่เราสร้าง cluster ไว้ครับ โดยดู project ID ได้จากใน URL ของเว็บ (https://console.cloud.google.com/kubernetes/list?project=my-project)

$ gcloud config set project my-project
Updated property [project].
$ gcloud config set compute/zone asia-southeast1-a
Updated property [compute/zone].

และสุดท้ายก็ login เข้า Kubernetes ครับ โดยตรง cluster-1 ให้กรอกชื่อ cluster ที่เราตั้งไว้

$ gcloud container clusters get-credentials cluster-1
Fetching cluster endpoint and auth data.
kubeconfig entry generated for cluster-1.

สุดท้ายลองเช็คดูว่าสามารถใช้ Kubernetes ได้จริงแล้ว

$ kubectl describe nodes
NAME                         STATUS    AGE       VERSION
gke-tipme-n1-a7ee1a90-mwzz   Ready     1h        v1.7.2

ติดตั้งของเล่น

ก่อนจะจบตอนไปมาลงอะไรเล่นดูก่อนดีกว่าครับ เอาเป็นว่าเรามาลอง hello world หน่อยแล้วกัน

อย่างแรกก็จะต้องสร้าง Pod ขึ้นมาก่อนครับ โดยเขียนไฟล์ helloworld.yaml ดังนี้

apiVersion: v1
kind: Pod
metadata:
  name: helloworld
spec:
  hostNetwork: true
  containers:
  - name: helloworld
    image: kitematic/hello-world-nginx
    ports:
    - containerPort: 80

ก็แปลว่า Pod นี้จะใช้ hostNetwork (เหมือน --net=host ใน Docker) และใช้อิมเมจ kitematic/hello-world-nginx

(ProTip: แนะนำให้ทำ Git repo มาเก็บ YAML ทั้งหมดที่ใช้ไว้ครับ จะสามารถ track changes ได้ง่ายตามสไตล์ Infrastructure as Code เลย)

เสร็จแล้วก็โหลดเข้าไปใน Kubernetes

$ kubectl create -f helloworld.yaml
pod "helloworld" created

$ kubectl get pods
NAME         READY     STATUS    RESTARTS   AGE
helloworld   1/1       Running   0          1m

เสร็จแล้วก็สามารถเข้าเว็บได้จาก IP ของเครื่องเลยครับ ซึ่งสามารถหา IP ภายนอกได้จากในหน้า External IP Address หรือจะกดที่เครื่องในหน้า Compute Engine ก็ได้ (ไม่สามารถหาจาก kubectl ได้เนื่องจาก GCE จะทำ 1:1 NAT ด้านนอกเครื่องเราทำให้เครื่องไม่ทราบ IP ตัวเอง)

ซึ่งไหนๆ เข้าไปหน้า External IP Address แล้ว สามารถจอง IP ที่ใช้อยู่ให้เป็น IP ถาวร (ปกติถ้าปิดเครื่อง IP จะสุ่มใหม่) เพียงแค่กด Type เป็น Static ซึ่งจะต่างกับใน AWS คือของ AWS ไม่สามารถจอง IP ที่ใช้อยู่ได้ ต้องกดขอ IP ใหม่มาใส่ตลอด

(Note: IP static ที่ไม่ได้ต่อกับเครื่องจะคิดเงินรายชั่วโมง ถ้าจะลบเครื่องออกอย่าลืมมาลบ IP ด้วยครับ)

สรุป

สำหรับตอนนี้เราก็ได้สร้างคลัสเตอร์ด้วย GKE และติดตั้งโปรแกรมแบบพื้นฐานไปแล้ว แต่นี่ยังแค่ความสามารถระดับพื้นๆ ของ Kubernetes ครับ ตอนหน้าเราจะมาพูดถึงคอนเซปต์ต่างๆ ใน Kubernetes กัน

ขออภัยในความไม่สะดวก

Note: จริงๆ บล็อคนี้เขียนไว้เป็นตอนจบของบล็อคที่แล้ว แต่รู้สึกว่าควรจะแยกเป็นตอนใหม่

ถ้าใครเคย inbox เข้ามาที่เพจ หรืออ่านเวลาผมประกาศว่าเว็บล่ม คำพูดนึงที่ใช้บ่อยมากคือ “ขออภัยในความไม่สะดวก”

ประกาศในหน้าเว็บเคยมีคำนี้ทั้งหมด 10 ครั้ง

เวลาเขียนคำนี้มันเจ็บนะ มันรู้สึกว่าเรากำลังทำลายความเชื่อมั่นของผู้ใช้งานอยู่ และคำขอโทษที่ใช้จนเฝือเกินไปมันไม่มีความหมาย


ขณะนี้ระบบสื่อสารของเว็บขัดข้อง

ขออภัยในความไม่สะดวก

ผมจำไม่ได้ว่าประโยคประมาณนี้เคยพูดไปกี่รอบ โดยเฉพาะในช่วงเดือนก่อนย้ายเว็บ

หลายต่อหลายครั้งเข้า ประกาศจึงต้องเปลี่ยนรูปแบบไป

ตอนนี้ระบบสื่อสารมีปัญหา อยู่ในระหว่างแก้ไขครับ น่าจะใช้เวลาประมาณ 30 นาที – 1 ชั่วโมง

ระยะหลังเราเริ่มมีปัญหาลักษณะนี้กับผู้ให้บริการ ซึ่งเรากำลังพิจารณาเปลี่ยนไปใช้บริการ Google Cloud ครับ

สิ่งที่ควรพูดมากกว่าในตอนนี้แล้วคือ ในเมื่อมีปัญหาเกิดขึ้นบ่อยครั้งมาก จะทำอย่างไรไม่ให้เกิดปัญหา

คนที่ให้แนวคิดนี้ก็ไม่ใช่ใครแต่ก็คือ Google Cloud ที่เราย้ายเข้ามา

เมื่อปีที่แล้ว Google Cloud ล่มพร้อมกันทั่วโลก แต่หลังจากอ่านรายงานนั้นแล้วผมรู้สึกว่าผมไว้ใจระบบของเค้ามากกว่าเดิมเสียอีก

ลองมาดูรายงานไปพร้อมๆ กันนะครับ

  • วันที่ 11 เมษายน 2016 เวลา 14:50 วิศวกร Google ได้ลบ IP ของ Compute Engine ที่ไม่ได้ใช้ออกจากระบบ
  • เนื่องจากข้อผิดพลาดของระบบ ทำให้ไฟล์ตั้งค่า 2 อันไม่ตรงกัน ระบบควบคุมจับข้อผิดพลาดได้จึงพยายามยกเลิกการแก้ไข
  • กระบวนการยกเลิกมีบั๊ก ทำให้มันลบ IP ทั้งหมดออกจากการตั้งค่า
  • การตั้งค่าใหม่จะถูกทดลองกับ 1 ที่ก่อน ซึ่งในขั้นทดลองก็จับข้อผิดพลาดนี้ได้
  • ระบบควบคุมมีข้อผิดพลาดอีกจุดหนึ่งที่ทำให้แทนที่จะเลิก กลับไปติดตั้งให้กับระบบที่เหลือ
  • พอระบบเริ่มกระจายการตั้งค่าใหม่นี้ออกไป ระบบยังไม่ล่มในทันทีเพราะผู้ใช้งานจะถูกย้ายไปเชื่อมต่อกับจุดอื่นๆ ที่ยังไม่ได้อัพเดต
  • พอการตั้งค่าเริ่มกระจายมากขึ้นเรื่อยๆ ระบบจึงแจ้งวิศวกรจากการที่ latency เพิ่มสูงขึ้นเรื่อยๆ
  • วิศวกร Google ได้เริ่มตรวจสอบตั้งแต่ได้รับข้อความแจ้งเตือน แต่ยังหาสาเหตุไม่ได้
  • 53 นาทีต่อมา การตั้งค่าใหม่กระจายครบทั้งทั่วโลกแล้วทำให้ไม่สามารถเชื่อมต่อเข้าสู่ Compute Engine ได้โดยสมบูรณ์
  • ระบบแจ้งเตือนเห็นปริมาณข้อมูลลดลงผิดปกติจึงแจ้งเตือนอีกครั้ง
  • วิศวกรที่กำลังตรวจสอบจึงทราบว่าปัญหาเกิดขึ้นทั่วโลก เค้าจึงย้อนการตั้งค่ากลับในทันที
  • รวมแล้วจากเวลาที่ตรวจพบจนถึงเริ่มย้อนการตั้งค่า ใช้เวลา 18 นาที
  • สิ่งที่ Google จะปรับปรุงในอนาคตคือ เพิ่มการตรวจจับเมื่อ redundancy ลดลงแม้ระบบจะยังใช้งานได้อยู่, ตรวจสอบขนาด IP Block ว่ายังมีขนาดถูกต้องอยู่หลังการแก้ไข และตรวจสอบ config อัตโนมัติว่ามี IP Block ที่กำหนดไว้

ความผิดพลาดเป็นเรื่องปกติที่ใครๆ ก็เจอ สิ่งที่ผมเห็นจากรายงานนี้คือระบบที่ออกแบบมาป้องกันความผิดพลาดหลายชั้น และยังมีการแจ้งเตือนเมื่อระบบทำงานผิดพลาด แม้ปราการทั้งหมดจะล้มเหลวไปพร้อมกัน แต่เค้ามีแผนการชัดเจนว่าจะทำอย่างไรให้ไม่เกิดข้อผิดพลาดแบบนี้อีก

นั่นคือสิ่งที่ผมอยากจะทำในเว็บ อาจจะไม่ได้ถึงกับว่าล่มครั้งเดียวแล้วแก้ไขได้ใน 18 นาที เพราะคนเฝ้ามีผมคนเดียว

แต่อย่างน้อยๆ คือถ้ามันเกิดซ้ำหลายครั้งแล้วเราจะต้องสามารถแจ้งผู้ใช้งานได้ว่าจะทำยังไงไม่ให้มันเกิดขึ้นอีก


Streamlabs ขัดข้องครับ

ขออภัยในความไม่สะดวก

ก่อนระบบล่มครั้งสุดท้าย เว็บมีปัญหากับ Streamlabs เยอะมาก บางครั้งก็ Login ไม่ได้ บางครั้งส่ง Alert ไปก็ไม่ขึ้นให้

คำตอบเดียวที่ให้ผู้ใช้งานได้คือ “แจ้งไปทาง Streamlabs แล้วครับ ต้องรอทางนั้นแก้ไข” ซึ่งก็เป็นเรื่องจริง แต่ผมว่าผู้ใช้งานคงไม่ชอบ

แผนการต่อไปของเว็บคือเราจะทำระบบมาแข่งกับ Streamlabs

ซึ่งมันไม่ง่ายเลย มันเหนื่อยมากและยังมองไม่เห็นว่าจะใช้เวลากี่เดือนจึงจะถึงจุดที่ผู้ใช้งานยอมรับ

แต่ก็ต้องทำเพราะไม่อยากใช้คำขอโทษสิ้นเปลืองอีกแล้ว