ภาพประกอบ นำระบบขึ้นคลาวด์และขยายรองรับโหลด

งานพาระบบจากเครื่องนักพัฒนาขึ้นไปอยู่บนอินเทอร์เน็ต แล้วทำให้มันอยู่ต่อได้เมื่อคนใช้มากขึ้น ครอบคลุมตั้งแต่ reverse proxy ที่ให้หลายระบบใช้เครื่องและที่อยู่สาธารณะเดียวกันโดยแยกตามโดเมน ใบรับรอง TLS ที่ต่ออายุเอง สคริปต์นำขึ้นระบบที่ทำซ้ำได้แทนการพิมพ์คำสั่งทีละบรรทัด การปล่อยเวอร์ชันใหม่โดยไม่ตัดคำขอที่ค้างอยู่ health check ที่วัดถึงระดับพอร์ต ตัวคุมที่เริ่มบริการใหม่ให้เองเมื่อมันตาย log ที่ค้นได้จริงตอนตีสอง ไปจนถึงการขยายทั้งแบบเพิ่มขนาดเครื่องและเพิ่มจำนวนเครื่อง

เหมาะกับใคร
องค์กรที่พัฒนาระบบเสร็จแล้วแต่ยังไม่มีวิธีนำขึ้นใช้งานที่ไว้ใจได้ ทีมที่ต้องดูแลหลายระบบบนโครงสร้างพื้นฐานชุดเดียว และธุรกิจที่มีระบบใช้งานอยู่แล้วแต่รู้ว่ามันล่มก็ต่อเมื่อลูกค้าโทรมาบอก

Cloud DeploymentnginxReverse ProxyTLSScaling

สอบถามเรื่องนี้

หลายระบบบนเครื่องเดียว แต่มีประตูสาธารณะบานเดียว

เว็บแอปพลิเคชันหลายตัวใช้เครื่องเดียวกันได้โดยไม่ต้องแย่งพอร์ตสาธารณะกัน วิธีที่เราใช้กับระบบของเราเองคือให้แต่ละแอปฟังอยู่บนพอร์ตวงในของเครื่อง แล้ววาง nginx ไว้ข้างหน้าเป็นประตูสาธารณะบานเดียว nginx จะอ่านชื่อโดเมนที่ผู้ใช้เรียกเข้ามา แล้วส่งต่อไปยังแอปที่รับผิดชอบโดเมนนั้น การเพิ่มระบบใหม่จึงเท่ากับเพิ่มพอร์ตหนึ่งพอร์ตและ virtual host หนึ่งชุด ไม่ต้องเพิ่มเครื่องและไม่ต้องเปลี่ยนที่อยู่สาธารณะ ตอนนี้ระบบของเราเองราวยี่สิบตัวรันอยู่บนเครื่องเดียวแบบนี้ แต่ละตัวมี virtual environment และเวอร์ชันของภาษาเป็นของตัวเอง

จุดที่พลาดกันบ่อยคือการให้แอปผูกกับทุกอินเทอร์เฟซ เพราะพอร์ตนั้นจะเปิดตรงออกอินเทอร์เน็ต เข้าถึงได้โดยไม่ผ่าน TLS ไม่ว่าจะตั้งค่าพร็อกซีข้างหน้าไว้ดีแค่ไหนก็ตาม เราจึงผูกทุกแอปไว้กับ loopback โดยตั้งใจ ให้ nginx เป็นทางเข้าเดียวจริง ๆ ใบรับรอง TLS ออกจาก Let's Encrypt และต่ออายุอัตโนมัติ โดยใบเดียวครอบได้หลายชื่อโดเมนในสายเดียวกัน ส่วนกฎที่ทุกเว็บต้องมีเหมือนกัน เช่น การปิดหน้าเอกสาร API ของเฟรมเวิร์กและไฟล์ที่ขึ้นต้นด้วยจุด เราเก็บเป็นไฟล์กลางแล้ว include เข้าทุกโดเมน เพราะกฎที่ต้องไปจำใส่ทีละโดเมน สุดท้ายจะมีสักโดเมนที่ลืม เราเพิ่มชุดนี้หลังจากเจอสแกนเนอร์ดึงไฟล์เหล่านั้นออกจากเว็บข้างเคียงไปได้จริง

  • แต่ละแอปฟังบนพอร์ตวงในของตัวเอง พร้อม virtual environment และเวอร์ชันภาษาของตัวเอง
  • nginx เลือกปลายทางจากชื่อโดเมน หลายโดเมนจึงใช้ที่อยู่สาธารณะเดียวกันได้
  • ใบรับรอง TLS จาก Let's Encrypt ต่ออายุอัตโนมัติ ใบเดียวครอบได้หลายชื่อโดเมน
  • ไม่ผูกแอปกับทุกอินเทอร์เฟซ เพื่อไม่ให้มีทางเข้าที่ข้าม TLS
  • กฎปิดกั้นชุดกลางที่ include เข้าทุกโดเมน ทั้งหน้าเอกสาร API และไฟล์ที่ขึ้นต้นด้วยจุด

การนำขึ้นระบบเป็นสคริปต์ ไม่ใช่คำสั่งที่พิมพ์เอาหน้างาน

การขึ้นระบบด้วยการไล่พิมพ์คำสั่งทีละบรรทัดจะได้ผลก็ต่อเมื่อคนพิมพ์จำได้ครบทุกขั้นและไม่พลาดสักตัวอักษร ซึ่งไม่ใช่สิ่งที่ควรฝากไว้กับความจำ เราจึงทำทั้งชุดให้เป็นสคริปต์ ตั้งแต่เขียนไฟล์ virtual host ขอใบรับรอง ไปจนถึงตั้งการต่ออายุอัตโนมัติ ผลคือขึ้นระบบครั้งที่สิบได้เหมือนครั้งแรก ทำซ้ำกับอีกโดเมนได้ทันที และคนอื่นในทีมอ่านสคริปต์แล้วรู้ว่าเครื่องถูกตั้งค่าอะไรไว้บ้าง ก่อนขอใบรับรองทุกครั้ง เราจะตรวจจากนอกเครือข่ายก่อนว่าโลกภายนอกเข้าถึงเครื่องได้จริง ขั้นนี้สำคัญกว่าที่ฟัง เพราะการทดสอบจากในเครือข่ายเดียวกันอาจผ่านได้ด้วยการวนกลับที่เราเตอร์ ทั้งที่คำขอจากข้างนอกถูกบล็อกอยู่ และผู้ออกใบรับรองก็อยู่ข้างนอกนั้น

การปล่อยเวอร์ชันใหม่ไม่ควรทำให้คำขอที่กำลังทำงานอยู่หลุดหายไป เราจึงเริ่มเวอร์ชันใหม่ขึ้นมาข้าง ๆ ตัวเดิมก่อน ยังไม่ส่งผู้ใช้เข้าไปจนกว่ามันจะตอบ health check บนพอร์ตของตัวเองได้ แล้วจึงสลับให้พร็อกซีชี้มาที่ตัวใหม่ ส่วนตัวเดิมทำคำขอที่รับไว้แล้วให้จบก่อนจะถูกปิด และยังคงอยู่จนกว่าตัวใหม่จะพิสูจน์ตัวเองแล้ว เพราะทางแก้ที่เร็วที่สุดของการปล่อยที่มีปัญหาคือเอาของเดิมกลับมา ไม่ใช่นั่งไล่แก้สดตอนที่ทุกคนกำลังรออยู่ ทุกครั้งที่ deploy จะมี log ของตัวเองแยกไว้ ย้อนดูได้ว่าครั้งไหนเปลี่ยนอะไร และเริ่มพังตั้งแต่ตอนไหน

  • สคริปต์เดียวจบ ตั้งแต่เขียน virtual host ขอใบรับรอง ไปจนถึงตั้งการต่ออายุ
  • ตรวจจากนอกเครือข่ายว่าเข้าถึงเครื่องได้จริง ก่อนขอใบรับรองทุกครั้ง
  • เริ่มเวอร์ชันใหม่ข้างตัวเดิม รอให้ผ่าน health check ก่อนค่อยสลับ
  • ปล่อยให้คำขอที่รับไว้แล้วทำงานจนจบ ก่อนปิดเวอร์ชันเก่า
  • ย้อนกลับได้ทันที เพราะตัวเดิมยังอยู่จนกว่าจะแน่ใจ
  • แยก log ของการ deploy ไว้ทุกครั้ง ตรวจย้อนหลังได้ว่าเปลี่ยนอะไรไป

เช็คว่าพอร์ตตอบ ไม่ใช่เช็คว่าโปรเซสยังอยู่

การเฝ้าระบบด้วยคำถามว่าโปรเซสยังรันอยู่หรือเปล่า คือวิธีที่ทำให้ระบบล่มโดยไม่มีใครรู้ โปรเซสหนึ่งยังมีชีวิต ยังถือ PID เดิม ยังโผล่ในรายการโปรเซสครบทุกอย่าง แต่เลิกฟังพอร์ตไปแล้วก็ได้ ไม่ว่าจะเพราะค้าง เพราะตัวรับการเชื่อมต่อหลุดไป หรือเพราะเริ่มใหม่แล้วผูกพอร์ตไม่สำเร็จ สำหรับผู้ใช้นั่นคือเว็บที่เข้าไม่ได้ ในขณะที่หน้าจอเฝ้าระวังยังเขียวอยู่ การตรวจของเราจึงเปิดการเชื่อมต่อ TCP ไปที่พอร์ตจริงโดยตั้งเวลารอสั้น ๆ และนับว่าบริการยังดีก็ต่อเมื่อโปรเซสยังอยู่และพอร์ตตอบกลับ ในระบบที่เดิมพันสูงกว่านั้น เราให้ยิงไปยังปลายทางที่แตะฐานข้อมูลจริง เพราะเว็บเซิร์ฟเวอร์ตอบรับได้อย่างสุภาพทั้งที่ทุกอย่างข้างหลังมันหายไปแล้ว

บริการแต่ละตัวถูกเริ่มไว้ในกลุ่มโปรเซสของตัวเอง การรีสตาร์ตตัวคุมจึงไม่ลากบริการดับตามไปด้วย เราบันทึก PID ไว้ แล้วตรวจสถานะจริงตอนบูตแทนการเดา ตัวไหนตายก็เริ่มใหม่ให้ กับดักของขั้นนี้คือการเริ่มใหม่ที่ล้มเพราะพอร์ตยังถูกโปรเซสค้างจากรอบก่อนถืออยู่ แล้วตัวคุมก็ปลุกมันซ้ำทุกไม่กี่วินาทีเป็นวงวนที่ไม่จบ การเก็บกวาดจึงต้องเจาะจง คือโปรเซสนั้นต้องกำลังฟังพอร์ตนั้นจริง และบรรทัดคำสั่งของมันต้องระบุถึงแอปตัวนั้นจริง บนเครื่องที่มีระบบยี่สิบตัวใช้ชื่อไฟล์เริ่มต้นเหมือนกัน การจับคู่จากชื่ออย่างเดียวจะไปฆ่าของคนอื่นเข้าสักวัน และเราเคยเห็นคำสั่งฆ่าตามชื่อครั้งเดียวทำให้เว็บที่ใช้งานจริงดับพร้อมกันหลายตัวมาแล้ว

ตอนตีสอง คำถามแรกคือจะเปิดไฟล์ไหน ทุกบริการจึงเขียน log ของตัวเองแยกไฟล์ รวม stdout และ stderr ไว้ที่เดียวกัน แยกจาก log ของการ deploy และของการติดตั้ง environment ทุกบรรทัดมีเวลากำกับและมีบริบทพอให้ค้นย้อนได้ว่าเกิดอะไรขึ้นก่อนหน้านั้น ส่วน log ที่อยู่แต่ในหน้าต่างเทอร์มินัลที่ใครสักคนปิดไปแล้ว ไม่นับว่าเป็น log

  • health check เปิดการเชื่อมต่อ TCP ไปที่พอร์ตจริง ไม่ใช่ดูแค่ว่าโปรเซสยังอยู่
  • นับว่าให้บริการได้ ต่อเมื่อโปรเซสยังอยู่และพอร์ตตอบกลับ
  • จุดที่เดิมพันสูง ตรวจถึงปลายทางที่แตะฐานข้อมูลจริง
  • แต่ละบริการอยู่ในกลุ่มโปรเซสของตัวเอง รีสตาร์ตตัวคุมแล้วไม่ดับตาม
  • เก็บ PID ไว้ ตรวจสถานะจริงตอนบูต และเริ่มบริการที่ตายให้ใหม่
  • เก็บกวาดโปรเซสค้างแบบเจาะจงทั้งพอร์ตและบรรทัดคำสั่ง ไม่ฆ่าตามชื่อ
  • log แยกไฟล์ต่อบริการ พร้อม log ของการ deploy และการติดตั้ง environment

เครื่องใหญ่ขึ้น กับเครื่องหลายตัว แก้คนละปัญหากัน

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

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

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

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

ความสามารถหลัก

  • reverse proxy แยกตามโดเมน ให้หลายระบบใช้เครื่องและที่อยู่สาธารณะเดียวกัน
  • ใบรับรอง TLS จาก Let's Encrypt ต่ออายุอัตโนมัติ ใบเดียวครอบหลายโดเมน
  • สคริปต์นำขึ้นระบบที่ทำซ้ำได้ พร้อมตรวจการเข้าถึงจากภายนอกก่อนขอใบรับรอง
  • ปล่อยเวอร์ชันใหม่โดยไม่ตัดคำขอที่กำลังทำงานอยู่ และย้อนกลับได้
  • health check ระดับพอร์ต ไม่ใช่แค่ดูว่าโปรเซสยังอยู่
  • ตัวคุมที่เริ่มบริการที่ตายให้ใหม่ และกู้สถานะจริงตอนบูต
  • log แยกไฟล์ต่อบริการ ต่อการ deploy และต่อการติดตั้ง environment
  • แผนขยายทั้งเพิ่มขนาดเครื่องและเพิ่มจำนวนเครื่อง พร้อมบอกว่าแต่ละแบบแก้อะไร

อยากได้ระบบแบบนี้

เล่าโจทย์ให้เราฟัง แล้วเราจะช่วยประเมินว่าต้องปรับอะไรให้เข้ากับงานของคุณ

ติดต่อเรา ดูโซลูชันอื่น