หลังจากที่ลองพัฒนาระบบด้วยภาษา Python ตามแนวคิด The Twelve Factor App
มาแล้ว 4 ข้อคือ

  1. Codebases
  2. Dependencies
  3. Configs
  4. Backing services

ซึ่งยังเหลืออีก 8 ข้อ ดังนั้นมาต่อกันให้จบ
โดยทั้ง 8 ข้อนี้จะเข้ากันมาก ๆ กับโลกของ Containerization
ในตัวอย่างจะเน้นไปที่ Docker เป็นหลัก มี Kubernetes มาผสมบ้างเล็กน้อย

ปล.
เขียนไปเขียนมาทำไมมันยาว ดังนั้นเพิ่มแค่ 4 ข้อเป็น 8 ก็แล้วกัน
ที่เหลืออีก 4 ข้อ เอาไว้อีก blog

มาเริ่มกันเลย

ข้อที่ 5 Build, release, run

Strictly separate build and run stages

ขั้นตอนการ deploy source code ไปยัง environment ต่าง ๆ เป็นอย่างไรกัน ?
ทำการ copy หรือ FTP หรือ Rsync ขึ้นเองไหม
หรือแก้ไฟล์เดียว ก็เอาขึ้นไฟล์เดียว !!

ตามแนวคิดนี้ จะทำการแบ่งขั้นตอนการนำ source code ไป deploy เป็น 3 ขั้นตอน
ขั้นตอนที่ 1 Build
ทำการแปลงจาก source code จากข้อหนึ่ง ตาม commit หรือ version ที่กำหนดไว้
กับ dependency จากข้อสอง
ไปเป็น executable ไฟล์ ยกตัวอย่างเช่น dll, exe, JAR, WAR, ZIP หรือ binary file อื่น ๆ เป็นต้น

ขั้นตอนที่ 2 Release
นำผลที่ได้จากขั้นตอนการ build มารวมกับข้อสามคือ Config
ซึ่งพร้อมที่จะเริ่มทำงานทันที

ขั้นตอนที่ 3 Run หรือ Runtime
ทำการ run หรือสร้าง process การทำงานของระบบงานจากขั้นตอนที่สอง

จากการทำงานที่มี 3 ขั้นตอนนั้น
เราไม่สามารถทำการแก้ไขแบบข้ามขั้นตอนได้
ยกตัวอย่างเช่น ไม่สามารถไปแก้ไขในขั้นตอนการ Run ได้
ถ้าไม่ผ่านขั้นตอนของการ Build และ Release โดยเด็ดขาด

สิ่งที่ได้รับกลับมาคือ
เราสามารถทำการ rollout หรือ rollback ระบบงานได้ตามที่ต้องการ

กลับมายังระบบงานตัวอย่างของเราบ้าง ที่พัฒนาด้วยภาษา Python
เราจะทำอย่างไรดี ตามแนวความคิดนี้

สิ่งที่ง่ายขึ้นคือ เราใช้งาน Docker ดีกว่า
เพียงแค่สร้าง Docker Image จาก Dockerfile เท่านั้น (มันเป็น Immutable อีกด้วย นั่นคือไม่สามารถแก้ไขได้)
ก็สามารถทำการ build image ที่พร้อมจะ release และ run ได้เลย
ซึ่งมีการทำงาน 3 ขั้นตอนดังนี้

  1. ทำการสร้าง Docker Image จาก Dockerfile
  2. ทำการสร้าง Docker Image ตาม environment ที่ต้องการ
  3. ทำการสร้าง Container จาก Docker Image ที่ต้องการ

ขั้นตอนที่ 1 สร้าง Dockerfile สำหรับการ build กันก่อน

คำอธิบาย
ใช้ base image ของ python ไปเลย ง่ายดี
ทำการเพิ่ม source code และ dependency ต่าง ๆ เข้าไป

จากนั้นทำการสร้าง Docker Image ของการ build ด้วยคำสั่ง

$docker image build -t demo:0.1.0 -f Dockerfile.build .

ขั้นตอนที่ 2 สร้าง Dockerfile สำหรับการ release
จะใช้ Docker Image จากขั้นตอนที่ 1
พร้อมกับกำหนด config ของ Database ที่ใช้งาน

จากนั้นทำการสร้าง Docker Image ของการ release ด้วยคำสั่ง

$docker image build -t demo_release:0.1.0 -f Dockerfile.release .

ขั้นตอนที่ 3 ทำการ run หรือสร้าง container จาก Docker Image ที่ได้จากขั้นตอนที่ 2
ใช้คำสั่งดังนี้

$docker container run -p 8000:8000 demo_release:0.1.0

ถ้าเป็น Kubernetes ก็เอาที่สบายใจเลยว่า
จะ run แบบไหนทั้ง Deployments, ReplicaSets และ DaemonSets เป็นต้น

ข้อที่ 6 Processes

Execute the app as one or more stateless processes

ถือว่าเป็นหัวใจหลักของ Cloud Native Application
ระบบงานจะมี process ที่เป็นแบบ stateless จำนวนตั้งแต่ 1 process ขึ้นไป
นั่นคือแต่ละ process จะไม่มีการ share state เลย (ไม่มี session นะ)
ตามแนวคิดนี้ ทำให้ง่ายต่อการ scale out (Horizontal scaling)

แต่ถ้าจำเป็นต้องเก็บข้อมูล
ก็จะต้องใช้ Backing service ตามแนวคิดข้อ 4 ซึ่งทำงานแบบ stateful
หรือถ้าใน Kubernetes ก็สามารถใช้งาน StatefulSets ได้เช่นกัน

ระวัง process ตายด้วยละ !!
เป็นอีกคำพูดหนึ่งที่น่ากลัวใช้ได้เลย
แน่นอนว่า เราต้องมีคำตอบให้ด้วย
โดยใน Docker และ Kubernetes มีตัวจัดการมาให้พร้อมอยู่แล้ว
เพื่อทำให้แน่ใจว่า process ยังทำงานตามจำนวนที่กำหนดไว้เสมอ

ข้อที่ 7 Port binding

Export services via port binding

หมายความว่า service ที่เราทำการพัฒนาขึ้นมานั้น
ไม่ว่าจะทำงานบน Application/Web server อะไรก็ตาม
เช่น
Java อาจจะทำงานบน Apache Tomcat
Python อาจจะทำงานบน Flask

ซึ่งล้วนมี port การทำงานที่แตกต่างกัน
แต่ service ของเรานั้นต้องไม่ผูกติดกับ port ของเครื่องมือที่ใช้ในการพัฒนา

ถ้าเป็นการพัฒนาปกติ
เราสามารถกำหนด port ของ service ด้วยการ configuration
ผ่าน environment variable ได้เลย
ยกตัวอย่างเช่น

ทั้ง Docker และ Kubernetes นั้น
สามารถทำงาน binding port ของ service ต่าง ๆ ได้
โดยไม่ขึ้นอยู่กับ Application/Web server ที่ใช้งาน

ข้อที่ 8 Concurrency

Scale out via the process model

เนื่องจาก process ของ service ต่าง ๆ เป็นแบบ stateless อยู่แล้ว
ดังนั้นการ scale out ก็ทำได้ด้วยการเพิ่ม process เข้ามานั่นเอง ( scale out over scale up )
แน่นอนว่า ในระบบงานมี service จำนวนมาก
ดังนั้นแต่ละ service ก็มีการ scale ที่แตกต่างกันไป และเป็นอิสระแก่กัน

ซึ่งทั้ง Docker และ Kubernetes ล้วยสนับสนุนแนวคิดนี้ด้วยเช่นกัน
ไม่ต้องพยายาม

มาถึงตรงนี้น่าจะพอทำให้เข้าใจแนวคิดของ The Twelve -Factor App มากขึ้นมาบ้าง
ใน blog ต่อไปจะเป็น 4 เรื่องสุดท้ายแล้ว