9
CREATE THE FOUNDATIONS OF OUR DEPLOYMENT PIPELINE (สร้างรากฐานของ Deployment Pipeline ของเรา)
เพื่อสร้าง flow ที่รวดเร็วและเชื่อถือได้จาก Dev ไปยัง Ops เราต้องมั่นใจว่าเราใช้สภาพแวดล้อมที่เหมือน production (production-like environments) ในทุกขั้นตอนของ value stream นอกจากนี้ สภาพแวดล้อมเหล่านี้ต้องถูกสร้างขึ้นโดยอัตโนมัติ ควรจะสร้างได้ตามต้องการจาก scripts และข้อมูลคอนฟิกที่เก็บใน version control และให้บริการแบบ self-service โดยสมบูรณ์ โดยไม่ต้องให้ Operations ทำงาน manual ใดๆ เป้าหมายของเราคือการทำให้เราสามารถสร้างสภาพแวดล้อม production ขึ้นมาใหม่ทั้งหมดจากสิ่งที่อยู่ใน version control
The Enterprise Data Warehouse Story (2009) (เรื่องราวของ Enterprise Data Warehouse)
บ่อยครั้งที่ครั้งเดียวที่เราจะได้เห็นว่าแอปพลิเคชันของเราทำงานในสภาพแวดล้อมที่คล้าย production จริงๆ ก็คือตอน deploy ขึ้น production ซึ่งสายเกินไปที่จะแก้ไขปัญหาโดยที่ลูกค้าไม่ได้รับผลกระทบ ตัวอย่างของปัญหาที่เกิดจากการสร้างแอปพลิเคชันและสภาพแวดล้อมที่ไม่สอดคล้องกันคือโปรแกรม Enterprise Data Warehouse ที่นำโดย Em Campbell-Pretty ที่บริษัทโทรคมนาคมขนาดใหญ่ในออสเตรเลียในปี 2009 Campbell-Pretty ได้เป็น general manager และ business sponsor สำหรับโปรแกรมมูลค่า 200 ล้านดอลลาร์นี้ โดยรับผิดชอบวัตถุประสงค์เชิงกลยุทธ์ทั้งหมดที่ต้องพึ่งพาแพลตฟอร์มนี้
ในการนำเสนอของเธอในงาน DevOps Enterprise Summit ปี 2014 Campbell-Pretty อธิบายว่า
ในตอนนั้นมีงานดําเนินการอยู่ 10 สายงาน (streams of work) ทั้งหมดใช้กระบวนการ waterfall และทั้ง 10 สายงานก็ล่าช้ากว่ากําหนดอย่างมาก มีเพียงสายงานเดียวจากสิบที่ทํา User Acceptance Testing (UAT) ได้ทันตามกําหนด และต้องใช้เวลาอีกหกเดือนกว่าสายงานนั้นจะทํา UAT เสร็จ โดยผลลัพธ์ที่ได้ก็ต่ํากว่าความคาดหวังทางธุรกิจอย่างมาก ผลงานที่ย่ำแย่นี้เป็นตัวเร่งหลักที่ทําให้แผนกต้องปรับเปลี่ยนไปใช้ Agile 1
อย่างไรก็ตาม หลังจากใช้ Agile มาเกือบปี พวกเขาก็เห็นการปรับปรุงเพียงเล็กน้อย และยังคงไม่บรรลุผลลัพธ์ทางธุรกิจที่ต้องการ
Campbell-Pretty จัด retrospective ทั่วทั้งโปรแกรมและถามว่า "หลังจากสะท้อนประสบการณ์ทั้งหมดที่เรามีตลอด release ที่ผ่านมา มีอะไรบ้างที่เราสามารถทําได้เพื่อเพิ่ม productivity เป็นสองเท่า" 2
ตลอดทั้งโปรเจกต์ มีเสียงบ่นเกี่ยวกับ "การขาดการมีส่วนร่วมจากฝ่ายธุรกิจ" อย่างไรก็ตาม ในระหว่าง retrospective "การเพิ่มความพร้อมใช้งานของสภาพแวดล้อม" (improve availability of environments) กลับเป็นสิ่งที่ถูกโหวตมาอันดับหนึ่ง 3 เมื่อมองย้อนกลับไป ก็เห็นได้ชัด—ทีม Development ต้องการสภาพแวดล้อมที่ provision แล้วเพื่อเริ่มทำงาน และมักต้องรอนานถึงแปดสัปดาห์
พวกเขาสร้างทีม integration และ build ใหม่ที่รับผิดชอบ "การสร้างคุณภาพไว้ในกระบวนการของเรา แทนที่จะพยายามตรวจสอบคุณภาพหลังจากความจริง" 4 ในตอนแรกทีมประกอบด้วย database administrators (DBAs) และผู้เชี่ยวชาญด้าน automation ที่ได้รับมอบหมายให้ automate กระบวนการสร้างสภาพแวดล้อม ทีมค้นพบสิ่งที่น่าประหลาดใจอย่างรวดเร็ว: มี source code เพียง 50% ในสภาพแวดล้อม development และ test ที่ตรงกับสิ่งที่รันใน production 5
Campbell-Pretty กล่าวว่า "ทันใดนั้นเราก็เข้าใจว่าทำไมเราถึงเจอ defects มากมายทุกครั้งที่ deploy โค้ดของเราลงในสภาพแวดล้อมใหม่ ในแต่ละสภาพแวดล้อมเราคอยแก้ไขไปเรื่อยๆ (fix forward) แต่การเปลี่ยนแปลงที่ทำไปไม่ได้ถูกนำกลับเข้าไปใน version control" 6
ทีมงานทำ reverse engineering การเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นในสภาพแวดล้อมต่างๆ อย่างระมัดระวัง และนำทั้งหมดเข้า version control พวกเขายัง automate กระบวนการสร้างสภาพแวดล้อมเพื่อให้สามารถสร้างสภาพแวดล้อมได้ซ้ำแล้วซ้ำเล่าอย่างถูกต้อง
Campbell-Pretty อธิบายผลลัพธ์ว่า "เวลาที่ใช้ในการได้สภาพแวดล้อมที่ถูกต้องลดลงจากแปดสัปดาห์เหลือหนึ่งวัน นี่คือหนึ่งในการปรับเปลี่ยนสำคัญที่ทำให้เราบรรลุเป้าหมายด้าน lead time ต้นทุนในการ deliver และจำนวน escaped defects ที่หลุดรอดไปถึง production" 7
เรื่องราวของ Campbell-Pretty แสดงให้เห็นปัญหาต่างๆ ที่สืบย้อนกลับไปที่การสร้างสภาพแวดล้อมที่ไม่สอดคล้องกันและการเปลี่ยนแปลงที่ไม่ถูกนำกลับเข้า version control อย่างเป็นระบบ
ในบทที่เหลือนี้ เราจะพูดถึงวิธีการสร้างกลไกที่จะช่วยให้เราสามารถสร้างสภาพแวดล้อมตามต้องการ ขยายการใช้ version control ให้กับทุกคนใน value stream ทำให้ infrastructure ง่ายต่อการ rebuild มากกว่าการซ่อมแซม และมั่นใจว่านักพัฒนาได้รันโค้ดของตนในสภาพแวดล้อมที่เหมือน production ในทุกขั้นตอนของ software development life cycle
Enable On-Demand Creation of Dev, Test, and Production Environments (เปิดใช้งานการสร้างสภาพแวดล้อม Dev, Test และ Production ตามต้องการ)
ดังที่เห็นในตัวอย่าง enterprise data warehouse ข้างต้น สาเหตุหลักประการหนึ่งที่ทำให้การปล่อยซอฟต์แวร์เกิดความโกลาหล วุ่นวาย และบางครั้งถึงขั้นหายนะคือ ครั้งแรกที่เราได้เห็นว่าแอปพลิเคชันของเราทำงานในสภาพแวดล้อมที่เหมือน production (production-like environment) ด้วยโหลดที่สมจริงและชุดข้อมูล production จริงก็คือตอน release * ในหลายกรณี ทีม development อาจขอสภาพแวดล้อม test ไว้ในช่วงต้นของโปรเจกต์
แต่เมื่อมี lead time ที่ยาวนานที่ Operations ต้องใช้ในการส่งมอบสภาพแวดล้อม test ทีมอาจไม่ได้รับมันทันเวลาที่จะทำการทดสอบอย่างเพียงพอ ยิ่งไปกว่านั้น สภาพแวดล้อม test มักถูกตั้งค่าผิดพลาดหรือแตกต่างจากสภาพแวดล้อม production มากจนเรายังคงเจอปัญหาใหญ่ใน production แม้จะทำการทดสอบก่อน deploy แล้วก็ตาม
ในขั้นตอนนี้ เราต้องการให้นักพัฒนาใช้สภาพแวดล้อมที่เหมือน production บน workstation ของตนเอง สร้างขึ้นตามต้องการและให้บริการแบบ self-service การทำเช่นนี้นักพัฒนาสามารถรันและทดสอบโค้ดของตนในสภาพแวดล้อมที่เหมือน production ซึ่งเป็นส่วนหนึ่งของงานประจำวัน ทำให้ได้รับ feedback ตั้งแต่เนิ่นๆ และสม่ำเสมอเกี่ยวกับคุณภาพของงาน
แทนที่จะเพียงแค่บันทึกข้อกำหนดของสภาพแวดล้อม production ไว้ในเอกสารหรือหน้า wiki เราสร้างกลไก build ร่วมกันที่สร้างสภาพแวดล้อมทั้งหมดของเรา เช่น สำหรับ development, test และ production การทำเช่นนี้ทุกคนจะได้สภาพแวดล้อมที่เหมือน production ภายในไม่กี่นาที โดยไม่ต้องเปิด ticket หรือรอเป็นสัปดาห์ †
การทำเช่นนี้ต้องการให้เรากำหนดและ automate การสร้างสภาพแวดล้อมที่ดีที่เรารู้จัก (known, good environments) ซึ่งมีความเสถียร ปลอดภัย และอยู่ในสถานะที่ลดความเสี่ยง เป็นตัวแทนของความรู้ร่วมกันของทั้งองค์กร ข้อกำหนดทั้งหมดของเราถูกฝังไว้ ไม่ใช่ในเอกสารหรือในความรู้ในหัวของใครสักคน แต่ถูกทำให้เป็นรหัสในกระบวนการ build สภาพแวดล้อมอัตโนมัติของเรา
แทนที่ Operations จะสร้างและกำหนดค่าสภาพแวดล้อมด้วยตนเอง เราสามารถใช้ automation สำหรับสิ่งใดสิ่งหนึ่งหรือทั้งหมดต่อไปนี้:
• การคัดลอกสภาพแวดล้อม virtualization (เช่น VMware image, การรัน Vagrant script, การบูท Amazon Machine Image ใน EC2)
• การสร้างกระบวนการสร้างสภาพแวดล้อมอัตโนมัติที่เริ่มจาก "bare metal" (เช่น PXE install จาก baseline image)
• การใช้เครื่องมือ "infrastructure as code" สำหรับจัดการ configurations (เช่น Puppet, Chef, Ansible, Salt, CFEngine ฯลฯ)
• การใช้เครื่องมือกำหนดค่าระบบปฏิบัติการอัตโนมัติ (เช่น Solaris Jumpstart, Red Hat Kickstart, Debian preseed)
• การประกอบสภาพแวดล้อมจากชุด virtual images หรือ containers (เช่น Docker, Kubernetes)
• การสร้างสภาพแวดล้อมใหม่ใน public cloud (เช่น Amazon Web Services, Google App Engine, Microsoft Azure), private cloud (เช่น stack ที่ใช้ Kubernetes) หรือ PaaS อื่นๆ (platform as a service เช่น OpenStack หรือ Cloud Foundry ฯลฯ)
เนื่องจากเรากำหนดทุกแง่มุมของสภาพแวดล้อมไว้ล่วงหน้าอย่างรอบคอบ เราไม่เพียงแค่สร้างสภาพแวดล้อมใหม่ได้อย่างรวดเร็ว แต่ยังมั่นใจได้ว่าสภาพแวดล้อมเหล่านี้จะมีความเสถียร เชื่อถือได้ สอดคล้องกัน และปลอดภัย ซึ่งเป็นประโยชน์ต่อทุกคน
Operations ได้ประโยชน์จากความสามารถนี้ในการสร้างสภาพแวดล้อมใหม่ได้รวดเร็ว เพราะ automation ของกระบวนการสร้างสภาพแวดล้อมบังคับใช้ความสอดคล้องและลดงาน manual ที่น่าเบื่อและมีข้อผิดพลาดได้ง่าย นอกจากนี้ Development ยังได้ประโยชน์จากการสามารถทำซ้ำส่วนที่จำเป็นทั้งหมดของสภาพแวดล้อม production เพื่อ build, รัน และทดสอบโค้ดบน workstation ของตน การทำเช่นนี้ช่วยให้นักพัฒนาสามารถค้นหาและแก้ไขปัญหาต่างๆ ได้มากมาย แม้กระทั่งในช่วงแรกๆ ของโปรเจกต์ แทนที่จะเจอระหว่าง integration testing หรือที่แย่กว่านั้นคือใน production
การให้นักพัฒนามีสภาพแวดล้อมที่ควบคุมได้อย่างเต็มที่ ทำให้พวกเขาสามารถทำซ้ำ วินิจฉัย และแก้ไข defects ได้อย่างรวดเร็ว โดยแยกออกจากบริการ production และทรัพยากรที่ใช้ร่วมกันอื่นๆ อย่างปลอดภัย พวกเขายังสามารถทดลองกับการเปลี่ยนแปลงสภาพแวดล้อม รวมถึงโค้ด infrastructure ที่สร้างมันขึ้นมา (เช่น configuration management scripts) ซึ่งเป็นการสร้างความรู้ร่วมกันระหว่าง Development และ Operations ‡
Create Our Single Repository of Truth for the Entire System (สร้าง Single Repository of Truth สำหรับทั้งระบบ)
ในขั้นตอนก่อนหน้านี้ เราเปิดใช้งานการสร้างสภาพแวดล้อม development, test และ production ตามต้องการ ตอนนี้เราต้องมั่นใจว่าทุกส่วนของระบบซอฟต์แวร์ของเราสามารถกำหนดค่าและจัดการได้โดยใช้ source of truth ที่ดูแลรักษาใน version control
เป็นเวลาหลายทศวรรษที่การใช้ version control อย่างครอบคลุมกลายเป็นแนวปฏิบัติที่จำเป็นสำหรับนักพัฒนาและทีม development แต่ละคน § ระบบ version control บันทึกการเปลี่ยนแปลงของไฟล์หรือชุดไฟล์ที่เก็บไว้ในระบบ 9 ซึ่งอาจเป็น source code, assets หรือเอกสารอื่นๆ ที่เป็นส่วนหนึ่งของโปรเจกต์พัฒนาซอฟต์แวร์ เราทำการเปลี่ยนแปลงเป็นกลุ่มที่เรียกว่า commits หรือ revisions แต่ละ revision พร้อมด้วย metadata เช่น ใครเป็นผู้ทำการเปลี่ยนแปลงและเมื่อไหร่ จะถูกเก็บไว้ในระบบในรูปแบบใดรูปแบบหนึ่ง ทำให้เราสามารถ commit, เปรียบเทียบ, merge และย้อนกลับ revisions ในอดีตได้ นอกจากนี้ยังช่วยลดความเสี่ยงด้วยการสร้างวิธีการย้อนกลับวัตถุใน production กลับไปเป็นเวอร์ชันก่อนหน้า ¶
เมื่อนักพัฒนาใส่ไฟล์ source code และ configurations ทั้งหมดของแอปพลิเคชันไว้ใน version control มันจะกลายเป็น single repository of truth ที่มีสถานะที่ตั้งใจไว้ของระบบอย่างแม่นยำ อย่างไรก็ตาม เนื่องจากการส่งมอบคุณค่าให้ลูกค้าต้องการทั้งโค้ดของเราและสภาพแวดล้อมที่มันรันอยู่ เราจึงต้องการสภาพแวดล้อมของเราใน version control ด้วยเช่นกัน กล่าวอีกนัยหนึ่ง version control มีไว้สำหรับทุกคนใน value stream ของเรา รวมถึง QA, Operations, Infosec รวมถึงนักพัฒนา
การใส่ artifacts production ทั้งหมดลงใน version control ทำให้ repository version control ของเราช่วยให้เราสามารถทำซ้ำส่วนประกอบทั้งหมดของระบบซอฟต์แวร์ที่ทำงานได้อย่างถูกต้องซ้ำแล้วซ้ำเล่าและเชื่อถือได้—ซึ่งรวมถึงแอปพลิเคชันและสภาพแวดล้อม production ของเรา ตลอดจนสภาพแวดล้อม pre-production ทั้งหมด
เพื่อให้มั่นใจว่าเราสามารถกู้คืนบริการ production ได้ซ้ำแล้วซ้ำเล่าและคาดการณ์ได้ (และควรจะรวดเร็ว) แม้เมื่อเกิดเหตุการณ์ภัยพิบัติ เราต้อง check in สินทรัพย์ต่อไปนี้ไปยัง shared version control repository:
• โค้ดแอปพลิเคชันทั้งหมดและ dependencies (เช่น libraries, static content ฯลฯ)
• สคริปต์ใดๆ ที่ใช้สร้าง database schemas, application reference data ฯลฯ
• เครื่องมือและ artifacts สำหรับสร้างสภาพแวดล้อมทั้งหมดที่อธิบายไว้ในขั้นตอนก่อนหน้า (เช่น VMware หรือ AMI images, Puppet, Chef หรือ Ansible scripts)
• ไฟล์ใดๆ ที่ใช้สร้าง containers (เช่น Docker, Rocket หรือ Kubernetes definitions หรือ composition files)
• การทดสอบอัตโนมัติที่สนับสนุนทั้งหมดและ test scripts แบบ manual
• สคริปต์ใดๆ ที่สนับสนุนการ packaging, deployment, database migration และ environment provisioning
• artifacts ของโปรเจกต์ทั้งหมด (เช่น เอกสารข้อกำหนด, ขั้นตอนการ deploy, release notes ฯลฯ)
• ไฟล์คอนฟิก cloud ทั้งหมด (เช่น AWS Cloudformation templates, Microsoft Azure Stack DSC files, OpenStack HEAT)
• สคริปต์อื่นๆ หรือข้อมูลคอนฟิกที่จำเป็นในการสร้าง infrastructure ที่รองรับหลาย services (เช่น enterprise service buses, database management systems, DNS zone files, กฎการกำหนดค่า firewall และอุปกรณ์เครือข่ายอื่นๆ) **
เราอาจมีหลาย repositories สำหรับวัตถุและบริการประเภทต่างๆ โดยมีการกำหนด label และ tag ควบคู่ไปกับ source code ของเรา ตัวอย่างเช่น เราอาจเก็บ virtual machine images ขนาดใหญ่, ISO files, compiled binaries และอื่นๆ ไว้ใน artifact repositories (เช่น Nexus, Artifactory) หรือเราอาจใส่ไว้ใน blob stores (เช่น Amazon S3 buckets) หรือใส่ Docker images ไว้ใน Docker registries และอื่นๆ นอกจากนี้เรายังจะสร้างและเก็บ cryptographic hash ของวัตถุเหล่านี้ในเวลาที่ build และตรวจสอบ hash นี้ในเวลาที่ deploy เพื่อให้แน่ใจว่ามันไม่ถูกดัดแปลง
การเพียงแค่สามารถสร้างสถานะก่อนหน้าใดๆ ของสภาพแวดล้อม production ขึ้นมาใหม่นั้นไม่เพียงพอ เรายังต้องสามารถสร้างกระบวนการ pre-production และ build ทั้งหมดขึ้นมาใหม่ได้ด้วย ดังนั้นเราจึงต้องใส่ทุกสิ่งที่กระบวนการ build ของเราต้องพึ่งพาลงใน version control รวมถึงเครื่องมือของเรา (เช่น compilers, testing tools) และสภาพแวดล้อมที่พวกมันต้องพึ่งพา ††
งานวิจัยชี้ให้เห็นถึงความสำคัญของ version control รายงาน State of DevOps Report ปี 2014–2019 ที่นำโดยผู้ร่วมเขียน Dr. Nicole Forsgren แสดงให้เห็นว่าการใช้ version control สำหรับ production artifacts ทั้งหมดเป็นตัวทำนายประสิทธิภาพการส่งมอบซอฟต์แวร์ (software delivery performance) ที่สูงกว่า ซึ่งส่งผลต่อประสิทธิภาพขององค์กร
ผลการวิจัยนี้เน้นย้ำถึงบทบาทที่สำคัญของ version control ในกระบวนการพัฒนาซอฟต์แวร์ ตอนนี้เรารู้แล้วว่าเมื่อการเปลี่ยนแปลงแอปพลิเคชันและสภาพแวดล้อมทั้งหมดถูกบันทึกใน version control มันช่วยให้เราไม่เพียงเห็นการเปลี่ยนแปลงทั้งหมดที่อาจมีส่วนทำให้เกิดปัญหาได้อย่างรวดเร็ว แต่ยังให้วิธีการย้อนกลับไปยังสถานะที่รู้จักว่าทำงานได้ก่อนหน้านี้ ทำให้เรากู้คืนจากความล้มเหลวได้เร็วขึ้น
แต่ทำไมการใช้ version control สำหรับสภาพแวดล้อมของเราถึงทำนายประสิทธิภาพการส่งมอบซอฟต์แวร์และมีส่วนทำให้ประสิทธิภาพขององค์กรดีกว่าการใช้ version control สำหรับโค้ดของเรา?
เพราะในเกือบทุกกรณี จำนวนการตั้งค่าคอนฟิก (configurable settings) ในสภาพแวดล้อมของเรามีมากกว่าในโค้ดของเราหลายเท่า ดังนั้น สภาพแวดล้อมต่างหากที่ต้องการ version control มากที่สุด ‡‡
Version control ยังให้วิธีการสื่อสารสำหรับทุกคนที่ทำงานใน value stream—การให้ Development, QA, Infosec และ Operations สามารถเห็นการเปลี่ยนแปลงของกันและกันช่วยลดความประหลาดใจ สร้างความโปร่งใสในงานของแต่ละคน และช่วยสร้างและเสริมสร้างความไว้วางใจ (ดู Appendix 7 ) แน่นอนว่านี่หมายความว่าทุกทีมต้องใช้ระบบ version control เดียวกัน
Make Infrastructure Easier to Rebuild Than to Repair (ทำให้ Infrastructure ง่ายต่อการ Rebuild มากกว่าการซ่อมแซม)
เมื่อเราสามารถ rebuild และสร้างแอปพลิเคชันและสภาพแวดล้อมของเราใหม่ได้อย่างรวดเร็วตามต้องการ เราก็สามารถ rebuild สิ่งเหล่านั้นใหม่แทนที่จะซ่อมแซมเมื่อมีสิ่งผิดปกติเกิดขึ้น แม้ว่าสิ่งนี้จะเป็นสิ่งที่การดำเนินงานเว็บขนาดใหญ่เกือบทั้งหมดทำ (คือการดำเนินงานที่มีเซิร์ฟเวอร์มากกว่าหนึ่งพันเครื่อง) แต่เราควรนำแนวปฏิบัตินี้มาใช้แม้ว่าเราจะมีเซิร์ฟเวอร์เพียงเครื่องเดียวใน production
Bill Baker วิศวกรดีเด่นของ Microsoft กล่าวว่าแต่ก่อนเราปฏิบัติต่อเซิร์ฟเวอร์เหมือนสัตว์เลี้ยง "คุณตั้งชื่อพวกมัน และเมื่อพวกมันป่วย คุณก็พยาบาลให้มันหาย [ตอนนี้] เซิร์ฟเวอร์ถูกปฏิบัติเหมือนวัว คุณกำหนดหมายเลขให้พวกมัน และเมื่อพวกมันป่วย คุณก็ยิงมันทิ้ง" 11
ด้วยระบบสร้างสภาพแวดล้อมที่ทำซ้ำได้ เราสามารถเพิ่มความจุได้ง่ายๆ โดยการเพิ่มเซิร์ฟเวอร์เข้าไปในการหมุนเวียน (คือ horizontal scaling) นอกจากนี้เรายังหลีกเลี่ยงหายนะที่มักจะเกิดขึ้นเมื่อเราต้องกู้คืนบริการหลังจากความล้มเหลวร้ายแรงของ infrastructure ที่ไม่สามารถทำซ้ำได้ ซึ่งถูกสร้างขึ้นผ่านการเปลี่ยนแปลง production ด้วยมือที่ไม่มีเอกสารเป็นเวลาหลายปี
เพื่อให้มั่นใจในความสอดคล้องของสภาพแวดล้อมของเรา เมื่อใดก็ตามที่เราเปลี่ยนแปลง production (การเปลี่ยนแปลงคอนฟิก, การแพตช์, การอัปเกรด ฯลฯ) การเปลี่ยนแปลงเหล่านั้นต้องถูกทำซ้ำทุกที่ทั้งในสภาพแวดล้อม production และ pre-production รวมถึงในสภาพแวดล้อมที่สร้างขึ้นใหม่
แทนที่จะ log in เข้าเซิร์ฟเวอร์ด้วยตนเองและทำการเปลี่ยนแปลง เราต้องทำการเปลี่ยนแปลงในลักษณะที่มั่นใจว่าการเปลี่ยนแปลงทั้งหมดถูกทำซ้ำทุกที่โดยอัตโนมัติ และการเปลี่ยนแปลงทั้งหมดของเราถูกใส่เข้าไปใน version control
ขึ้นอยู่กับ life cycle ของคอนฟิกที่เกี่ยวข้อง เราสามารถพึ่งพาระบบคอนฟิกอัตโนมัติของเราเพื่อให้แน่ใจในความสอดคล้อง (เช่น Puppet, Chef, Ansible, Salt, Bosh ฯลฯ) ใช้ service mesh หรือ configuration management service เพื่อเผยแพร่ runtime configuration (Istio, AWS Systems Manager Parameter Store ฯลฯ) หรือเราสามารถสร้าง virtual machines หรือ containers ใหม่จากกลไก build อัตโนมัติของเราและ deploy ขึ้น production โดยทำลายเครื่องเก่าหรือนำออกจากการหมุนเวียน §§
รูปแบบหลังนี้กลายเป็นที่รู้จักในชื่อ immutable infrastructure ซึ่งไม่อนุญาตให้มีการเปลี่ยนแปลง manual กับสภาพแวดล้อม production อีกต่อไป—วิธีเดียวที่จะเปลี่ยนแปลง production ได้คือการใส่การเปลี่ยนแปลงลงใน version control และสร้างโค้ดและสภาพแวดล้อมขึ้นมาใหม่ตั้งแต่ต้น 13 การทำเช่นนี้จะไม่มีค่าความแตกต่างใดๆ (variance) แทรกซึมเข้าไปใน production ได้
เพื่อป้องกันความแตกต่างของคอนฟิกที่ไม่สามารถควบคุมได้ เราอาจปิดการใช้งาน remote logins ไปยังเซิร์ฟเวอร์ production ¶¶ หรือฆ่าและแทนที่ instances production เป็นประจำ *** เพื่อให้แน่ใจว่าการเปลี่ยนแปลง production ที่ทำด้วยมือจะถูกกำจัดออกไป การดำเนินการนี้เป็นแรงจูงใจให้ทุกคนใส่การเปลี่ยนแปลงของตนในวิธีที่ถูกต้องผ่าน version control การใช้มาตรการดังกล่าวเรากำลังลดวิธีที่ infrastructure ของเราสามารถเบี่ยงเบนจากสถานะที่ดีที่เรารู้จักอย่างเป็นระบบ (เช่น configuration drift, fragile artifacts, works of art, snowflakes และอื่นๆ)
นอกจากนี้ เราต้องทำให้สภาพแวดล้อม pre-production ของเราทันสมัยอยู่เสมอ โดยเฉพาะอย่างยิ่ง เราต้องการให้นักพัฒนาทำงานบนสภาพแวดล้อมปัจจุบันที่สุด นักพัฒนามักจะอยากทำงานบนสภาพแวดล้อมเก่าเพราะกลัวว่าการอัปเดตสภาพแวดล้อมอาจทำให้ฟังก์ชันการทำงานที่มีอยู่เสียหาย อย่างไรก็ตาม เราต้องการอัปเดตบ่อยๆ เพื่อค้นหาปัญหาในช่วงแรกสุดของ life cycle ††† และงานวิจัยจาก GitHub ในรายงาน State of Octoverse ปี 2020 แสดงให้เห็นว่าการทำให้ซอฟต์แวร์ของคุณทันสมัยอยู่เสมอเป็นวิธีที่ดีที่สุดในการรักษาความปลอดภัยของ codebase 15
CASE STUDY: NEW TO SECOND EDITION (กรณีศึกษา: เพิ่มเติมในฉบับที่สอง)
How a Hotel Company Ran $30B of Revenue in Containers (2020) (บริษัทโรงแรมแห่งหนึ่งดำเนินรายได้ 30,000 ล้านดอลลาร์ด้วย Container ได้อย่างไร)
ขณะทำงานอยู่ที่บริษัทโรงแรมที่ใหญ่ที่สุดแห่งหนึ่ง Dwayne Holmes ซึ่งขณะนั้นดำรงตำแหน่ง Senior Director of DevSecOps and Enterprise Platforms และทีมของเขาได้ containerize ระบบทั้งหมดที่สร้างรายได้ของบริษัท ซึ่งรวมกันสนับสนุนรายได้ต่อปีมากกว่า 30,000 ล้านดอลลาร์ 16
เดิมที Dwayne มาจากภาคการเงิน เขาพยายามหาสิ่งต่างๆ เพิ่มเติมที่จะ automate เพื่อเพิ่ม productivity ในงาน meetup ท้องถิ่นเกี่ยวกับ Ruby on Rails เขาก็บังเอิญเจอ containers สำหรับ Dwayne แล้ว containers เป็นคำตอบที่ชัดเจนในการเร่งสร้างมูลค่าทางธุรกิจและเพิ่ม productivity
Containers ตอบสนองสามสิ่งสำคัญ: มันทำให้ infrastructure เป็นนามธรรม (หลักการ dial-tone—คุณหยิบหูโทรศัพท์ขึ้นมาแล้วมันก็ทำงานได้โดยไม่ต้องรู้ว่ามันทำงานอย่างไร), specialization (Operations สามารถสร้าง containers ที่นักพัฒนาสามารถนำมาใช้ซ้ำแล้วซ้ำเล่า) และ automation (containers สามารถถูก build ซ้ำแล้วซ้ำเล่าและทุกอย่างจะทำงานได้) 17
ด้วยความรักใน containers ที่ฝังแน่น Dwayne จึงถือโอกาสลาออกจากตำแหน่งที่สบายเพื่อมาเป็น contractor ให้กับบริษัทโรงแรมที่ใหญ่ที่สุดแห่งหนึ่งซึ่งพร้อมจะลงทุนกับ containers อย่างเต็มที่ 18
ด้วยทีมข้ามสายงานขนาดเล็กที่ประกอบด้วยนักพัฒนาสามคนและผู้เชี่ยวชาญด้าน infrastructure สามคน เป้าหมายของพวกเขาคือการพูดถึงวิวัฒนาการ (evolution) versus การปฏิวัติ (revolution) เพื่อเปลี่ยนแปลงวิธีการทำงานขององค์กรขนาดใหญ่อย่างสิ้นเชิง 19
มีบทเรียนมากมายตลอดเส้นทาง ดังที่ Dwayne ได้สรุปไว้ในการนำเสนอ DevOps Enterprise Summit ปี 2020 แต่ท้ายที่สุดโปรเจกต์ก็ประสบความสำเร็จ 20
สำหรับ Dwayne และบริษัทโรงแรม containers คือหนทางที่ถูกต้อง พวกมันพกพาข้าม cloud ได้ (cloud portable) พวกมันปรับขนาดได้ (scalable) มี health checks ในตัว พวกเขาสามารถทดสอบ latency เทียบกับ CPU และ certificates ไม่ได้อยู่ในแอปพลิเคชันหรือถูกจัดการโดยนักพัฒนาอีกต่อไป นอกจากนี้ ตอนนี้พวกเขาสามารถโฟกัสที่ circuit breaking มี APM ในตัว ดำเนินการแบบ zero trust และ images มีขนาดเล็กมากเนื่องจากสุขอนามัยของ container ที่ดีและการใช้ sidecars เพื่อเสริมทุกอย่าง 21
ในช่วงเวลาที่ Dwayne อยู่ที่บริษัทโรงแรม เขาและทีมสนับสนุนนักพัฒนากว่าสามพันคนในหลายผู้ให้บริการ ในปี 2016 microservices และ containers ทำงานใน production ในปี 2017 มีการประมวลผลรายได้ 1,000 ล้านดอลลาร์ใน containers, 90% ของแอปพลิเคชันใหม่อยู่ใน containers และพวกเขามี Kubernetes ทำงานใน production ในปี 2018 พวกเขาเป็นหนึ่งในห้า Kubernetes cluster production ที่ใหญ่ที่สุดตามรายได้ และภายในปี 2020 พวกเขาทำ builds และ deployments นับพันครั้งต่อวัน และรัน Kubernetes ในห้า cloud providers 22
Containers ได้กลายเป็นวิธีการที่เติบโตอย่างรวดเร็วในการทำให้ infrastructure ง่ายต่อการ rebuild และ reuse มากกว่าการซ่อมแซม ท้ายที่สุดแล้วก็ช่วยเร่งการส่งมอบคุณค่าทางธุรกิจและ productivity ของนักพัฒนา
Modify Our Definition of Development "Done" to Include Running in Production-Like Environments (ปรับนิยาม "Done" ของ Development ให้รวมถึงการทำงานในสภาพแวดล้อมที่เหมือน Production)
ตอนนี้เมื่อสภาพแวดล้อมของเราสามารถสร้างได้ตามต้องการและทุกอย่างถูก check in เข้า version control แล้ว เป้าหมายของเราคือทำให้แน่ใจว่าสภาพแวดล้อมเหล่านี้ถูกใช้ในงานประจำวันของ Development เราจำเป็นต้องตรวจสอบว่าแอปพลิเคชันของเราทำงานได้ตามที่คาดหวังในสภาพแวดล้อมที่เหมือน production ก่อนสิ้นสุดโปรเจกต์หรือก่อนการ deploy ขึ้น production ครั้งแรก
วิธีการพัฒนาซอฟต์แวร์สมัยใหม่ส่วนใหญ่กำหนดช่วงการพัฒนาแบบสั้นและวนซ้ำ (iterative) แทนที่จะเป็นแนวทาง big-bang (คือโมเดล waterfall) โดยทั่วไปยิ่งช่วงเวลาระหว่าง deployment นานเท่าไหร่ ผลลัพธ์ก็ยิ่งแย่ลง ตัวอย่างเช่น ในวิธี Scrum sprint คือช่วงการพัฒนาที่มีกรอบเวลา (maximum หนึ่งเดือนแต่โดยทั่วไปน้อยกว่า) ซึ่งเราต้องทำให้เสร็จ โดยนิยามกว้างๆ ว่าเมื่อเรามี "working and potentially shippable code"
เป้าหมายของเราคือให้แน่ใจว่า Development และ QA กำลัง integrate โค้ดกับสภาพแวดล้อมที่เหมือน production เป็นประจำในช่วงเวลาที่ถี่ขึ้นตลอดทั้งโปรเจกต์ เราทำสิ่งนี้โดยขยายนิยามของ "done" ให้เกินกว่าแค่ฟังก์ชันโค้ดที่ถูกต้อง: เมื่อสิ้นสุดช่วงการพัฒนาแต่ละช่วงหรือบ่อยกว่านั้น เรามีโค้ดที่ integrate, ทดสอบ, ทำงานได้ และสามารถ shippable ได้ โดยสาธิตในสภาพแวดล้อมที่เหมือน production
กล่าวอีกนัยหนึ่ง เราจะยอมรับงาน development ว่า done ก็ต่อเมื่อมันสามารถ build, deploy และยืนยันได้ว่าทำงานตามที่คาดหวังในสภาพแวดล้อมที่เหมือน production แทนที่จะยอมรับเมื่อนักพัฒนาเชื่อว่ามันเสร็จแล้ว ตามอุดมคติ มันควรทำงานภายใต้โหลดที่เหมือน production (production-like load) ด้วยชุดข้อมูลที่เหมือน production ก่อนสิ้นสุด sprint ซึ่งป้องกันสถานการณ์ที่ฟีเจอร์ถูกเรียกว่า done เพียงเพราะนักพัฒนาสามารถรันมันได้สำเร็จบน laptop ของตน แต่ไม่สามารถรันที่อื่นได้
การให้นักพัฒนาเขียน ทดสอบ และรันโคดของตนเองในสภาพแวดล้อมที่เหมือน production งานส่วนใหญ่ในการ integrate โค้ดและสภาพแวดล้อมของเราจะเกิดขึ้นระหว่างการทำงานประจำวัน แทนที่จะเป็นตอนท้ายของ release เมื่อสิ้นสุดช่วงแรกของเรา แอปพลิเคชันของเราสามารถสาธิตได้ว่าทำงานถูกต้องในสภาพแวดล้อมที่เหมือน production โดยที่โค้ดและสภาพแวดล้อมได้ถูก integrate รวมกันหลายครั้ง ควรจะทำทุกขั้นตอนโดยอัตโนมัติ (ไม่ต้องปรับแต่งด้วยมือ)
ยิ่งไปกว่านั้น เมื่อสิ้นสุดโปรเจกต์ เราจะได้ deploy และรันโค้ดของเราในสภาพแวดล้อมที่เหมือน production หลายร้อยหรือหลายพันครั้ง ทำให้เรามั่นใจว่าปัญหา deployment ใน production ส่วนใหญ่ถูกค้นพบและแก้ไขแล้ว
ตามอุดมคติ เราใช้เครื่องมือเดียวกัน เช่น monitoring, logging และ deployment ในสภาพแวดล้อม pre-production เหมือนกับที่ใช้ใน production การทำเช่นนี้เราจะมีความคุ้นเคยและประสบการณ์ที่จะช่วยให้เรา deploy และรัน รวมถึงวินิจฉัยและแก้ไขบริการของเราได้อย่างราบรื่นเมื่ออยู่ใน production
การทำให้ Development และ Operations มีความเชี่ยวชาญร่วมกันว่าโค้ดและสภาพแวดล้อมมีปฏิสัมพันธ์กันอย่างไร และการฝึกซ้อม deployment ตั้งแต่เนิ่นๆ และบ่อยครั้ง เราจะลดความเสี่ยงในการ deploy ที่เกี่ยวข้องกับการปล่อยโค้ดขึ้น production ได้อย่างมาก นอกจากนี้ยังช่วยให้เรากำจัดข้อบกพร่องด้านปฏิบัติการและความปลอดภัย รวมถึงปัญหาทางสถาปัตยกรรมทั้งชั้นที่มักจะถูกจับได้ช้าเกินไปในโปรเจกต์ที่จะแก้ไขได้
Conclusion (บทสรุป)
การไหลของงานอย่างรวดเร็วจาก Development ไปยัง Operations ต้องการให้ทุกคนสามารถรับสภาพแวดล้อมที่เหมือน production ได้ตามต้องการ การให้นักพัฒนาใช้สภาพแวดล้อมที่เหมือน production แม้ในช่วงแรกสุดของโปรเจกต์ซอฟต์แวร์ช่วยลดความเสี่ยงของปัญหาใน production ในภายหลังได้อย่างมาก นี่คือหนึ่งในหลายแนวปฏิบัติที่แสดงให้เห็นว่า Operations สามารถทำให้นักพัฒนามีประสิทธิผลมากขึ้นได้อย่างไร เราบังคับใช้แนวปฏิบัติที่นักพัฒนาต้องรันโค้ดของตนในสภาพแวดล้อมที่เหมือน production โดยรวมมันเข้าไปในนิยามของ "done"
ยิ่งกว่านั้น การใส่ artifacts production ทั้งหมดลงใน version control เรามี "single source of truth" ที่ช่วยให้เราสามารถสร้างสภาพแวดล้อม production ทั้งหมดขึ้นมาใหม่ได้อย่างรวดเร็ว ทำซ้ำได้ และมีเอกสารกำกับ โดยใช้แนวปฏิบัติ development เดียวกันกับงาน Operations เหมือนกับที่เราทำกับงาน Development และการทำให้ production infrastructure ง่ายต่อการ rebuild มากกว่าการซ่อมแซม ทำให้การแก้ปัญหาง่ายและเร็วขึ้น รวมถึงทำให้การขยายความจุง่ายขึ้นด้วย การมีแนวปฏิบัติเหล่านี้จะเป็นการปูทางสำหรับการเปิดใช้งาน test automation ที่ครอบคลุม ซึ่งจะถูกสำรวจในบทถัดไป