Infrastructure as Code คือ การเขียน Code เพื่อจัดการกับส่วนประกอบต่างๆของ Infrastructure ตัวอย่างของ Infrastructure as Code(IaC) เช่น Terraform จัดการ Resource ต่างๆบน Cloud และ Ansible ที่นำมาจัดการ Configuration บน Server หรือใน router
Infrastructure as Code(IaC) vs Shell Script
ถ้าเราอยากทำงาแบบอัตโนมัติ เราก็เขียน Bash script หรือ Shell script ก็ได้นี่ไม่เห็นต้องมาเรียนรู้ Syntax ของ Infrastructure as Code ให้วุ่นวาย ซึ่งเราจะพบปัญหาต่างๆเหล่านี้
- ต่างคนต่างเขียน ต่างคนก็มีวิธีการของตัวเองไม่มีมาตรฐาน
- ไม่รู้ว่า Shell Script ที่เขียนนี้ ต่างจากสถานะล่าสุดของ Server หรือ Resource ที่เราสนใจอย่างไร
- เกิด Error ได้ง่ายกว่า เพราะถ้าไม่ได้จุดเริ่มต้นแตกต่างจากที่คนเขียน script คิดก็จะ run ไม่ได้ทันที
- ทำความเข้าใจได้ยากกว่ามาก เพราะต้องเขียนเยอะกว่า โดยเฉพาะเมื่อเทียบกับ Infrastructure as Code(IaC) แบบ Declarative
- ไม่สามารถเขียน Code เพื่อ Test ได้ก็เลยตรวจสอบการทำงานของ shell script นั้นไม่ได้ เราจะเห็นแต่มัน error หรือ ไม่ error
- ไม่สา่มารถควบคุมสิ่งที่ต้องทำหรือห้ามทำ(Policy) ลงไปได้
- เราแยกตัวแปร(data) และ code ออกจากกันไม่ได้ แต่ Infrastructure as Code สามารถแยกได้
- Secret ต่างๆเช่น API Key หรือ password ก็แยกออกจาก Code ไม่ได้ซึ่งอันตรายมาก
ดังนั้น Infrastructure as Code(IaC) จะเกิดมาเพื่อแก้ปัญหาต่างๆเหล่านี้ ข้อแนะนำสำหรับผู้ที่เขียน Shell script หรือ Bash script คือเปลี่ยนจากการเขียน script มาเป็น IaC ซะเพราะมันง่ายกว่าสิ่งที่คุณกำลังเขียนอยู่มากๆ
Declarative vs Imperative
การเขียน Code หรือ Script เพื่อจัดการกับ Infrastructure นั้นมีได้ 2 รูปแบบคือ
- Declarative เป็นการนิยามสิ่งที่เราอยากได้ ไม่ต้องบอกขั้นตอนการทำงานเพื่อให้ได้มาซึ่งสิ่งที่เราอยากได้ ยกตัวอย่างเช่น การออกแบบบ้านเราจะใช้ blueprint ในการสื่อสาร เราไม่ต้องบอกขั้นตอนการสร้างบ้าน
- Imperative เป็นการระบุขั้นตอนการทำงานที่ชัดเจน เหมือนกับคู่มือการทำอาหารที่จะต้องระบุการทำแบบ steps by steps
ในปัจจุบัน Infrastructure as Code(IaC) จะเป็นการเขียนแบบ Declarative
Idempotency คืออะไร?
Idempotency คือ เราเขียนสามารถ run command ซ้ำๆได้ โดยที่ไม่เกิด Error หรือการเปลี่ยนแปลงกับ state ของระบบ(Managed System) เนื่องจาก Infrastructure as Code ของเราเขียนแบบ Declarative จึงเริ่มต้นจากจุดไหนก็ได้ ในตัวอย่างเราจะเขียนคำว่า “foobar” ลงไปในไฟล์ชื่อว่า “myfile” ซึ่งเหมือนกับ command ในตัวอย่างนี้
echo foobar >> /tmp/myfile
ใน Code ชุดแรกจะเขียนด้วย puppet ซึ่งเป็น Infrastructure as Code แบบ declarative เราจะสามารถ run puppet apply ซ้ำๆได้ โดยที่เนื้อหาใน “myfile” จะยังคงมีคำว่า “foobar” บรรทัดเดียวเหมือนเดิม
puppet apply sample.pp
ไฟล์ sample.pp จะมีเนื้อหาแบบนี้
file_line { 'foobar':
ensure => present,
path => '/tmp/myfile',
line => 'foobar',
}
แบบที่ 2 เราจะเขียนโดย shell script โดยใช้ชื่อว่า sample.sh ซึ่งจะมีเนื้อหาแบบนี้
#!/bin/sh
if ! grep -E '^foobar$' /tmp/myfile > /dev/null 2>&1; then
echo foobar >> /tmp/myfile
fi
ซึ่งทุกครั้งที่เรา Run shell script นี้ด้วยคำสั่งนี้ซ้ำๆ
./sample.sh
สิ่งที่เกิดขึ้นคือจะมีการเพิ่มคำว่า “foobar” เข้าไปใน myfile เรื่อยๆ นั่นก็คือ state ของ Managed System จะเปลี่ยนไปเรื่อยๆ ทุกครั้งที่ run
ดังนั้นความหมายของ Idempotency คือไม่ว่าเราจะ run Code กี่ครั้งก็ตาม state สุดท้ายจะตรงกันเสมอ
ข้อดีของ Infrastructure as Code
ซึ่งข้อดีของการทำ Infrastructure as Code มีดังนี้
- สามารถจัดเป็น Component หรือเป็น function เพื่อใช้งานซ้ำได้ง่าย
- Deploy แบบอัตโนมัติ (Automated Deploy)
- สามารถทำซ้ำกี่รอบก็ได้(Idempotency) ถ้าทำแบบ Manual หรือใช้ shell script ก็ทำซ้ำได้แต่ผลลัพธ์อาจไม่เหมือนเดิม
- เราจะมั่นใจได้เลยว่าเราจะได้ Environment ที่เหมือนกันแน่นอน
- เราเขียนเป็น Code ดังนั้นจะสามารถ ส่งให้คนอื่น Review ได้สำคัญมากสำหรับการดูแล Security ของระบบ เราเองก็สามารถอ่านได้ว่าทำอะไรไปบ้าง และยังสามารถจัดการ Version ได้อีกด้วย
ในปัจจุบบันเราจะนิยมการเขียนแบบ Declarative มากกว่า เพราะสั้น กระชับเข้าใจง่าย และที่สำคัญคือ error น้อยกว่า เพราะเราไม่ได้สนใจจุดตั้งต้น เราจะเริ่มจากจุดไหนก็ได้ แต่ imperative จะต้องเริ่มจากศูนย์เสมอ
Push vs Pull
Infrastructure as Code(Iac) จะถูกจัดออกเป็น 2 กลุ่มคือ Push และ Pull โดยที่ทั้ง 2 กลุ่มนี้จะต่างกันตรงที่
- Push เครื่องที่ run คำสั่ง apply เช่น kubectl apply หรือ terraform apply จะเป็นเครื่องที่อ่านค่า configuration ปัจจุบันของ Managed System และเปลี่ยนแปลงให้เป็นไปตามสิ่งที่เราเขียนไว้ใน Infrastructure as Code(IaC)
- Pull โดยปกติ Model นี้จะต้องมีการติดตั้ง Agent โดยที่ Agent จะทำการตรวจสอบ Configuration ของ Managed System ซึ่งจะเหมาะกับ Infrastructure ที่เราสามารถเข้าไปติดตั้ง Agent ได้
ความแตกต่างของ 2 Model นี้คือคนที่ตรวจสอบว่า Current State(สิ่งที่ระบบเป็นอยู่) กับ Desired State(สิ่งที่เราอยากได้) นั้นต่างกันยังไงคือ Push model จะใช้ controller (จะอยู่ในเครื่องที่ run command) แต่ถ้าเป็น Pull model จะใช้ Agent เป็นคนจัดการ
ซึ่งเราจะจัดกลุ่มของ Infrastructure as Code ได้ดังนี้
- Puppet server + agents (pull model)
- Ansible (push model)
- Controller-less Ansible over Git (pull model)
- Terraform (push model)
- Docker ผ่าน docker command (push model)
- Kubernetes ผ่าน kubectl (push model)
หลังจากที่รู้จักกับ Infrastructure as Code(IaC) กันมาพอสมควรแล้วลองมาดูกันว่า IaC แต่ละตัวนั้นมีวิธีการติดตั้งและใช้งานยังไงบ้าง