<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mongkol Thongkraikaew</title>
    <description>The latest articles on DEV Community by Mongkol Thongkraikaew (@mongkol_tho).</description>
    <link>https://dev.to/mongkol_tho</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2442353%2Fa247a8f1-4d52-4284-940a-656afc6475aa.JPG</url>
      <title>DEV Community: Mongkol Thongkraikaew</title>
      <link>https://dev.to/mongkol_tho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mongkol_tho"/>
    <language>en</language>
    <item>
      <title>Deploy LLM บน Amazon EKS ด้วย vLLM แบบ Step-by-Step ( EP.1 )</title>
      <dc:creator>Mongkol Thongkraikaew</dc:creator>
      <pubDate>Mon, 10 Aug 2026 05:04:50 +0000</pubDate>
      <link>https://dev.to/mongkol_tho/deploy-llm-bn-amazon-eks-dwy-vllm-aebb-step-by-step-ep1--42pb</link>
      <guid>https://dev.to/mongkol_tho/deploy-llm-bn-amazon-eks-dwy-vllm-aebb-step-by-step-ep1--42pb</guid>
      <description>&lt;blockquote&gt;
&lt;h2&gt;
  
  
  &lt;em&gt;&lt;strong&gt;By 2028, 95% of new AI deployments will use Kubernetes, up from less than 30% today&lt;/strong&gt;&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Gartner ® , Magic Quadrant™ for Container Management, 6 August 2025.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;จากผลคาดการณ์ของ Gartner ระบุว่า ภายในปี 2028 เกือบทุกองค์กรจะนำ Kubernetes มาใช้เป็นโครงสร้างพื้นฐานมาตรฐานในการบริหารจัดการระบบ AI ระดับ Production เพื่อเพิ่มประสิทธิภาพในการสเกลทรัพยากร GPU และยกระดับความปลอดภัยในระดับองค์กร ตัวเลขนี้เน้นย้ำอย่างชัดเจนถึงความจำเป็นในการ Reskill ทักษะสาย IT ไปสู่สายงาน Platform Engineer และ MLOps&lt;/p&gt;

&lt;p&gt;ผมจึงตั้งใจเขียนซีรีส์บทความนี้ขึ้นมาเพื่อแบ่งปันความรู้ให้กับทุกคนที่สนใจ โดยมาในธีมหลักอย่าง "Serving LLM บน Kubernetes Platform"&lt;/p&gt;

&lt;p&gt;ประเดิมด้วย EP.1 นี้ ผมจะพาทุกคนมาลอง Deploy LLM Model ด้วย vLLM บน Amazon EKS (Kubernetes) ตั้งแต่ขั้นตอนการสร้าง EKS Cluster ไปจนถึงการได้ OpenAI-compatible API และหน้าเว็บ Chat ที่พร้อมใช้งานจริง โดยทุก Command ในบทความนี้สามารถพิมพ์ตามไปพร้อมกันได้เลยครับ&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 ความตั้งใจของบทความนี้:&lt;br&gt;
ตอนที่ผมพยายาม Deploy LLM บน Kubernetes ครั้งแรก ผมเสียเวลาลองผิดลองถูกไปหลายชั่วโมงเหมือนกันครับ ถือว่าบทความนี้สรุปจากประสบการณ์จริงมาให้แล้ว หวังว่าจะช่วยให้คนที่กำลังเริ่มต้นไม่ต้องมาเจอ Error หรือเสียเวลาแบบที่ผมเคยเจอครับ 😂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;มาเริ่มกันเลยครับ...&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Architecture Diagram&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftdqwbcm7og239ud06myh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftdqwbcm7og239ud06myh.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🛠️ Tech Stacks&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal:&lt;/strong&gt; AWS CloudShell (ใช้สำหรับรัน Command ทั้งหมดในบทความนี้)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Provider:&lt;/strong&gt; AWS (Region: us-east-1)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes Platform:&lt;/strong&gt; Amazon EKS (Auto Mode)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute Instance:&lt;/strong&gt; EC2 Instance Type &lt;code&gt;g6.2xlarge&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;GPU Spec: NVIDIA L4 Tensor Core (24GB GPU Memory)&lt;/li&gt;
&lt;li&gt;GPU Driver: NVIDIA CUDA&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Inference Engine:&lt;/strong&gt; &lt;a href="https://github.com/vllm-project/vllm" rel="noopener noreferrer"&gt;vLLM&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat UI Platform:&lt;/strong&gt; &lt;a href="https://github.com/thesysdev/openui" rel="noopener noreferrer"&gt;OpenUI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Hub:&lt;/strong&gt; &lt;a href="https://huggingface.co/" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Model:&lt;/strong&gt; &lt;a href="https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct" rel="noopener noreferrer"&gt;meta-llama/Llama-3.1-8B-Instruct &lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parameters&lt;/strong&gt;: 8B &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inference Quantization&lt;/strong&gt;: FP16&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VRAM Requirement:&lt;/strong&gt; ต้องการ VRAM ขั้นต่ำประมาณ 17–18 GB (รวม Weights + Activations/CUDA Graphs + KV Cache) ดังนั้นจึงต้องใช้ GPU ที่มี VRAM 24 GB ขึ้นไป (เช่น NVIDIA L4 หรือ A10G) เพื่อให้มีพื้นที่เหลือสำหรับ KV Cache&lt;/li&gt;
&lt;li&gt;💡 ข้อแนะนำ: หากมี VRAM ไม่พอ สามารถเปลี่ยนไปใช้โมเดลที่ทำ Quantization เป็น FP8 แทนได้ : &lt;a href="https://huggingface.co/RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8" rel="noopener noreferrer"&gt;RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ ทำไมถึงเลือกใช้ vLLM ?
&lt;/h2&gt;

&lt;p&gt;vLLM คือ Open-source Inference Engine ที่กำลังมาแรงมากในปัจจุบัน และกำลังกลายเป็นมาตรฐานหลักสำหรับการ Serve LLM บน Production เหตุผลหลักๆ ที่ผมเลือกใช้ตัวนี้ ได้แก่:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;จัดการ GPU Memory ได้มีประสิทธิภาพสูงสุด:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PagedAttention:&lt;/strong&gt; เทคโนโลยีจัดการ KV Cache รูปแบบใหม่ที่ได้แรงบันดาลใจมาจาก Virtual Memory ของ OS ช่วยลด Memory Fragmentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Batching:&lt;/strong&gt; อนุญาตให้ Request ใหม่แทรกเข้า Batch ที่กำลังประมวลผลอยู่ได้ทันทีโดยไม่ต้องรอให้ Batch เดิมทำงานเสร็จ ส่งผลให้ TTFT (Time to First Token) และ Tokens/s ทำได้ดีกว่า Engine ตัวอื่นอย่างชัดเจน&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI-Compatible API:&lt;/strong&gt; ให้ API ในรูปแบบเดียวกับ OpenAI ช่วยให้สามารถเชื่อมต่อกับ Application หรือ Tools เดิมที่มีอยู่ได้ทันทีโดยไม่ต้องแก้ Code นอกจากนี้ยังมี Native Endpoints อย่าง &lt;code&gt;/health&lt;/code&gt; และ &lt;code&gt;/metrics&lt;/code&gt; สำหรับทำ Health Checks หรือตั้งค่า Auto-scaling บน Kubernetes ได้ง่าย&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Concurrency Production Ready:&lt;/strong&gt; รองรับการใช้งานที่มี Traffic เข้ามาพร้อมกันจำนวนมาก (High Concurrency) ได้ ในขณะที่การ setup ไม่ยุ่งยากซับซ้อนจนเกินไป&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Node &amp;amp; Multi-GPU Serving:&lt;/strong&gt; รองรับการทำ Tensor Parallelism และ Pipeline Parallelism ทั้งภายใน Node เดียวกัน และขยายข้ามหลาย Node (Multi-Node)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes Ecosystem Friendly:&lt;/strong&gt; ถูกนำไปใช้เป็น Backend หลักใน Framework สาย Cloud-Native อย่าง KServe รวมถึง AWS เองก็มี Deep Learning Containers (DLC) ที่ปรับแต่ง vLLM มาให้พร้อมรันบน EKS ได้ทันที&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source &amp;amp; Active Community:&lt;/strong&gt; ใช้ใบอนุญาตแบบ Apache 2.0 และมี Community ที่เติบโตอย่างต่อเนื่อง&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📋 สิ่งที่ต้องเตรียมก่อนเริ่ม
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. AWS Account&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Region:&lt;/strong&gt; ใน Lab นี้ผมจะใช้ Region us-east-1 (N. Virginia) เนื่องจากเป็น Region ที่มี Instance Family ตระกูล g6 ให้ใช้งาน&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 Service Quotas (สำคัญมาก):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;โดยปกติ AWS Account ใหม่จะตั้งค่า Quota สำหรับ GPU Instance (G and O instances) ไว้ที่ 0 vCPUs&lt;/li&gt;
&lt;li&gt;ต้องทำการส่ง Request ขอเพิ่ม Service Quotas สำหรับ &lt;strong&gt;Running On-Demand G and VT instances&lt;/strong&gt; ก่อน (แนะนำให้ขออย่างน้อย 8 vCPUs เพื่อรองรับ g6.2xlarge)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftltp9jws81xbougmno7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftltp9jws81xbougmno7b.png" alt="Resource Quotas : Running On-Demand G and VT instances" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permissions:&lt;/strong&gt; หากเป็นการทดสอบใน Sandbox/Lab แนะนำให้ตั้งค่า Permission เป็น &lt;code&gt;AdministratorAccess&lt;/code&gt; เพื่อป้องกันปัญหาการติด Permission ระหว่าง Deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Hugging Face Account&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create Access Token:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;เข้าไปที่ Settings &amp;gt; Access Tokens จากนั้นสร้าง Token ใหม่โดยกำหนด Role เป็น Read เพื่อนำมาใช้ดึงโมเดลลงมายัง Cluster ครับ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ddofvpmzlno8myphbj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ddofvpmzlno8myphbj6.png" alt=" " width="799" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Model Access:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;เนื่องจากในบทความนี้เลือกใช้โมเดล &lt;code&gt;meta-llama/Llama-3.1-8B-Instruct&lt;/code&gt; ซึ่งเป็น Gated Model บน Hugging Face จึงต้องทำการกดยอมรับเงื่อนไขสิทธิ์การใช้งานก่อน&lt;/li&gt;
&lt;li&gt;(หมายเหตุ: หากต้องการหลีกเลี่ยงขั้นตอน Gated Model สามารถเลือกใช้โมเดล Open-weight อื่นๆ เช่น Qwen, DeepSeek หรือ Mistral ก็ได้เช่นกันครับ )&lt;/li&gt;
&lt;li&gt;(หรือใช้ลองใช้ ungated mirror &lt;a href="https://huggingface.co/NousResearch/Meta-Llama-3.1-8B-Instruct" rel="noopener noreferrer"&gt;NousResearch/Meta-Llama-3.1-8B-Instruct&lt;/a&gt; แทนได้ เพราะใช้  weights ชุดเดียวกันกับของ meta)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📌 &lt;u&gt;ขั้นตอนการขอ Request Access Model:&lt;/u&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;ไปที่หน้า Model Repository &lt;a href="https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct" rel="noopener noreferrer"&gt;meta-llama/Llama-3.1-8B-Instruct &lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;p&gt;กรอกข้อมูลส่วนตัวและยอมรับเงื่อนไขใบอนุญาต จากนั้นกด &lt;strong&gt;Submit&lt;/strong&gt; เพื่อส่งคำขอ&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t2umm1v9i05d1bmsq9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t2umm1v9i05d1bmsq9i.png" alt=" " width="800" height="764"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ตรวจสอบสถานะการอนุมัติได้ที่หน้า &lt;a href="https://huggingface.co/settings/gated-repos" rel="noopener noreferrer"&gt;Gated Repos Status&lt;/a&gt; ในตั้งค่าบัญชีของตัวเอง &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuz4ylzqc6wu6yejw7k6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuz4ylzqc6wu6yejw7k6b.png" alt=" " width="799" height="171"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;strong&gt;และเมื่อเราเตรียมทั้งหมดแล้ว หลังจากนี้เราจะเริ่ม Deploy LLM บน Amazon EKS กันเลยครับ&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Deploy LLM บน Amazon EKS
&lt;/h2&gt;

&lt;p&gt;ก่อนจะเริ่มลงมือ ทำความเข้าใจกันก่อนว่า &lt;em&gt;เป้าหมายของบทความนี้คือความง่ายและรวดเร็ว&lt;/em&gt; เพื่อให้ทุกคนได้เห็นผลลัพธ์จริงแบบเร็วที่สุด รวมถึงเข้าใจ component ต่างในระบบ ดังนั้น สคริปต์และขั้นตอนทั้งหมดผมจึงออกแบบมาให้กระชับและทำตามได้ทันทีครับ (ผมคิดว่าน่าจะเป็นแนวทางง่ายที่สุดละ 😂)&lt;/p&gt;

&lt;p&gt;นอกจากนี้ ผมจะใช้ AWS CloudShell ในการรันสคริปต์และคำสั่งทั้งหมดตลอดทั้งบทความ ไม่จำเป็นต้องติดตั้ง Terraform, &lt;code&gt;kubectl&lt;/code&gt;, หรือ Tools ใดๆ ลงบนเครื่องตัวเองเลยครับ&lt;/p&gt;

&lt;p&gt;เริ่มต้นด้วยการให้เราเปิด AWS CloudShell บน AWS Console ขึ้นมาได้เลยครับ (อย่าลืมตรวจสอบ Region มุมขวาบนให้แน่ใจว่าเลือกเป็น us-east-1 ด้วยนะครับ)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7tmfhjlvxouo3wo1w4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7tmfhjlvxouo3wo1w4c.png" alt=" " width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 1: ตั้งค่า Environment Variables และติดตั้งเครื่องมือ
&lt;/h2&gt;

&lt;p&gt;รันคำสั่งกำหนดค่าตัวแปลบน AWS CloudShell (อย่าลืมเปลี่ยนค่า HF_TOKEN ให้เป็น Hugging Face Token ด้วยนะครับ):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# กำหนด Hugging Face Access Token (เปลี่ยนเป็น Token ของเรา)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"&lt;/span&gt;  

&lt;span class="c"&gt;# กำหนด AWS Region และชื่อ EKS Cluster&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKSClusterName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;llm-eks-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ติดตั้ง CLI Tools ที่จำเป็น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# 1. ติดตั้ง envsubst สำหรับจัดการ Template File&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install &lt;/span&gt;gettext &lt;span class="nt"&gt;-y&lt;/span&gt; 

&lt;span class="c"&gt;# 2. ติดตั้ง eksctl (CLI สำหรับจัดการ EKS Cluster)&lt;/span&gt;
&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64
&lt;span class="nv"&gt;PLATFORM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;_&lt;span class="nv"&gt;$ARCH&lt;/span&gt;

curl &lt;span class="nt"&gt;-sLO&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_&lt;/span&gt;&lt;span class="nv"&gt;$PLATFORM&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;

&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; eksctl_&lt;span class="nv"&gt;$PLATFORM&lt;/span&gt;.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /tmp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm &lt;/span&gt;eksctl_&lt;span class="nv"&gt;$PLATFORM&lt;/span&gt;.tar.gz

&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 /tmp/eksctl /usr/local/bin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; /tmp/eksctl

&lt;span class="c"&gt;# 3. ติดตั้ง kubectx และ kubens (สำหรับสลับ Context / Namespace)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;git clone https://github.com/ahmetb/kubectx /opt/kubectx

&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /opt/kubectx/kubectx /usr/local/bin/kubectx
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /opt/kubectx/kubens /usr/local/bin/kubens

&lt;span class="c"&gt;# 4. ตรวจสอบความถูกต้องของการติดตั้ง&lt;/span&gt;
eksctl version
kubectx &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;เครื่องมือต่างๆ พร้อมแล้ว!&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 2:  สร้าง AWS EKS Cluster
&lt;/h2&gt;

&lt;p&gt;ในขั้นตอนนี้เราจะใช้ &lt;code&gt;eksctl&lt;/code&gt; ในการ provisioning ตัว EKS Cluster โดยเปิดใช้งานฟีเจอร์ EKS Auto Mode เพื่อให้ AWS ช่วยดูแลจัดการเรื่อง Infrastructure และ Node Management ให้อัตโนมัติครับ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | eksctl create cluster -f -
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EKSClusterName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  region: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Region&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  version: "1.35"
iam:
  withOIDC: true
autoModeConfig:
  enabled: true
  nodePools: ["general-purpose", "system"]
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📌 &lt;u&gt;สรุปคอนฟิกสำคัญในการสร้าง EKS Cluster&lt;/u&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EKS Version:&lt;/strong&gt; &lt;code&gt;1.35&lt;/code&gt; &lt;em&gt;#(ระบุเวอร์ชัน EKS ที่จะใช้)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Auto Mode:&lt;/strong&gt; &lt;code&gt;true&lt;/code&gt; &lt;em&gt;#(เปิดใช้งาน EKS Auto Mode ให้ AWS บริหารจัดการ Compute/Node ให้อัตโนมัติ)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node Pools: กำหนด Built-in Node Pools เริ่มต้น 2 กลุ่ม:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;system&lt;/code&gt;: สำหรับรัน System Workloads และ Core Kubernetes Components&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;general-purpose&lt;/code&gt;: สำหรับรัน General Application Workloads ทั่วไป&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(รอประมาณ 10-15 นาทีในการสร้าง EKS Cluster ครับ...)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;เมื่อรันคำสั่งสร้าง Cluster เสร็จเรียบร้อยแล้ว ให้ทำการตรวจสอบสถานะของ EKS Cluster ดูครับ (หาก Cluster พร้อมใช้งานแล้ว สถานะจะแสดงผลเป็น &lt;code&gt;"ACTIVE"&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks describe-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$EKSClusterName&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$Region&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'cluster.status'&lt;/span&gt;

&lt;span class="c"&gt;# Output: "ACTIVE"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อ EKS พร้อมใช้งาน ก็มาทดสอบเรียก Kubernetes API ด้วย &lt;code&gt;kubectl&lt;/code&gt; ต่อครับ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Switch context ไปยัง cluster "llm-eks-la"&lt;/span&gt;
kubectx &lt;span class="si"&gt;$(&lt;/span&gt;kubectx | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"llm-eks-lab"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# ทดสอบ list node&lt;/span&gt;
kubectl get node 

&lt;span class="c"&gt;# ทดสอบ list Pod&lt;/span&gt;
kubectl get pod &lt;span class="nt"&gt;-A&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;จุดเด่นของ Amazon EKS Auto Mode คือการรวบรวม Tools สำคัญมาให้ครบถ้วนตั้งแต่แรก ไม่ว่าจะเป็น Karpenter, AWS Load Balancer Controller รวมถึง Nvidia Device Plugin ทำให้พร้อมรองรับ Workload GPU และเริ่มรัน Pod ได้ทันที&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 3: เตรียม GPU NodePool (Karpenter)
&lt;/h2&gt;

&lt;p&gt;ในขั้นตอนนี้เราจะสร้าง Karpenter NodePool สำหรับจัดเตรียม GPU Nodeเพื่อใช้สำหรับสั่ง Provision เครื่อง &lt;code&gt;g6.2xlarge&lt;/code&gt; มารองรับ vLLM ในขั้นตอนถัดไปครับ&lt;/p&gt;

&lt;p&gt;รันคำสั่งสั่งสร้าง NodePool ผ่าน kubectl ได้เลย:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu
spec:
  disruption:
    consolidationPolicy: WhenEmpty
    consolidateAfter: 5m       
  template:
    metadata:
      labels:
        node-type: gpu         
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["on-demand"]
        - key: "kubernetes.io/arch"
          operator: In
          values: ["amd64"]
        - key: "node.kubernetes.io/instance-type"
          operator: In
          values: ["g6.2xlarge"]   
      taints:
        - key: nvidia.com/gpu
          value: "true"
          effect: NoSchedule
      terminationGracePeriod: 24h0m0s
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Output: nodepool.karpenter.sh/gpu created&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📌 &lt;u&gt;สรุปคอนฟิกสำคัญของ NodePool&lt;/u&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;node.kubernetes.io/instance-type:&lt;/strong&gt; &lt;code&gt;g6.2xlarge&lt;/code&gt; &lt;em&gt;# ล็อกประเภท EC2 Instance เป็น &lt;code&gt;g6.2xlarge&lt;/code&gt; type&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;taints:&lt;/strong&gt; &lt;code&gt;nvidia.com/gpu=true:NoSchedule&lt;/code&gt;  &lt;em&gt;# ใส่ Taint เพื่อป้องกันไม่ให้ Pod ทั่วไป (ที่ไม่ได้ต้องการ GPU) ถูก Schedule มาลงใน Node นี้&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;metadata.labels:node-type:&lt;/strong&gt; &lt;code&gt;gpu&lt;/code&gt;  &lt;em&gt;# ติด Label ประจำ Node เพื่อให้ vLLM Deployment สามารถใช้ nodeSelector ชี้มาถูกเครื่อง&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;disruption.consolidationPolicy:&lt;/strong&gt; &lt;code&gt;WhenEmpty&lt;/code&gt;  &lt;em&gt;# ตั้งค่าให้คืนเครื่องออโต้เมื่อไม่มี Pod ใช้งานเกิน 5 นาที เพื่อช่วยประหยัดค่าใช้จ่าย&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;ข้อควรระวังสำหรับผู้ที่ใช้ Custom EKS (Non-Auto Mode):&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;หากใช้ AL2023 AMI จำเป็นต้องติดตั้ง NVIDIA Device Plugin เพิ่มเติมเอง เพื่อให้ Kubernetes Schedule Pod ลงบน GPU Node ได้&lt;/li&gt;
&lt;li&gt;หากใช้ AL2 หรือ Custom AMI นอกเหนือจากการติดตั้ง NVIDIA Device Plugin แล้l จะต้องติดตั้ง NVIDIA Driver บน Node เองด้วย เพื่อให้ Container Runtime สามารถเข้าถึง GPU Card ได้&lt;/li&gt;
&lt;li&gt;(ข้อดีของ EKS Auto Mode ในบทความนี้คือ ตัว EKS จะจัดการ Driver และ Device Plugin ให้เราอัตโนมัติทั้งหมดครับ!)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;em&gt;&lt;strong&gt;Q:&lt;/strong&gt; ทำไม Kubernetes ต้องมี Device Plugin?&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;A:&lt;/strong&gt; เพราะโดยปกติแล้ว Kubernetes ไม่รู้จัก GPU ครับ! ตัว &lt;code&gt;kube-scheduler&lt;/code&gt; จะรู้จักและคำนวณ resource พื้นฐานแค่ &lt;code&gt;cpu&lt;/code&gt;, &lt;code&gt;memory&lt;/code&gt; และ &lt;code&gt;ephemeral-storage&lt;/code&gt; เท่านั้น ส่วน GPU นั้นถือเป็น Extended Resource ที่ต้องมีคนช่วย "โฆษณา" (Advertise) ให้ Kubernetes รับรู้ ซึ่งทำหน้าที่โดย NVIDIA Device Plugin นั่นเอง โดยตัว Plugin จะไปบอกกับ &lt;code&gt;kubelet&lt;/code&gt; บน Node เพื่อประกาศว่าเครื่องนี้มีทรัพยากร &lt;code&gt;[nvidia.com/gpu]: 1&lt;/code&gt; เพิ่มเข้ามา ทำให้ค่านี้ไปปรากฏอยู่ใน node.status.allocatable และทำให้ Kubernetes สามารถ Schedule งานที่ร้องขอ GPU ได้ถูกต้องครับ&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;📌ตัวอย่างการติดตั้ง NVIDIA Driver และ Device Plugin&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;(⚠️ หมายเหตุ: สำหรับ Lab ในบทความนี้ ไม่จำเป็นต้องรันคำสั่งด้านล่างนี้ เนื่องจาก EKS Auto Mode จะจัดการส่วนนี้ให้อัตโนมัติทั้งหมดครับ นำมาลงไว้ให้ศึกษาเพิ่มเติมเท่านั้น)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# เพิ่ม Helm Repository ของ NVIDIA&lt;/span&gt;
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; helm repo update

&lt;span class="c"&gt;# กรณีที่ใช้ AMI ที่ยังไม่มี driver (ex. Ubuntu EKS AMI)&lt;/span&gt;
&lt;span class="c"&gt;# ต้องติดตั้งทั้ง GPU Driver, Container Toolkit และ Device Plugin&lt;/span&gt;
helm &lt;span class="nb"&gt;install &lt;/span&gt;gpu-operator nvidia/gpu-operator &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; gpu-operator &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; driver.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; toolkit.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; v25.3.0

&lt;span class="c"&gt;# กรณีที่ใช้ GPU-Accelerated AMI (ex. Amazon Linux 2023 : AL2023) ที่มี Driver ติดตั้งมาแล้ว &lt;/span&gt;
&lt;span class="c"&gt;# ติดตั้งเฉพาะ Device Plugin โดยไม่ต้องลง Driver ซ้ำ&lt;/span&gt;
helm &lt;span class="nb"&gt;install &lt;/span&gt;gpu-operator nvidia/gpu-operator &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; gpu-operator &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; driver.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; toolkit.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ขั้นตอนที่ 4:  เริ่ม Deploy vLLM และ LLM Model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. สร้าง Namespace และ Hugging Face Secret&lt;/strong&gt;&lt;br&gt;
เริ่มต้นด้วยการสร้าง Namespace &lt;code&gt;local-llm&lt;/code&gt; และสร้าง Kubernetes Secret เพื่อเก็บ &lt;code&gt;HF_TOKEN&lt;/code&gt; สำหรับใช้ยืนยันตัวตนในการดาวน์โหลดโมเดลจาก Hugging Face:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# สร้าง Namespace สำหรับระบบ LLM&lt;/span&gt;
kubectl create namespace local-llm

&lt;span class="c"&gt;# สร้าง Secret เก็บ Hugging Face Access Token &lt;/span&gt;
kubectl create secret generic hf-secret &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. ตรวจสอบสิทธิ์การเข้าถึง Gated Model&lt;/strong&gt;&lt;br&gt;
ถ้าใครใช้โมเดล meta-llama/Llama-3.1-8B-Instruct เหมือนในบทความนี้ ให้รันคำสั่งด้านล่างเพื่อทดสอบว่า Hugging Face Token ได้รับการอนุมัติสิทธิ์เข้าถึง Gated Repository เรียบร้อยแล้วหรือยัง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'HF gated repo check: %{http_code}\n'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct/resolve/main/config.json

&lt;span class="c"&gt;# Output ที่ถูกต้อง: HF gated repo check: 200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ หมายเหตุ: หากผลลัพธ์แสดงเป็น 401 หรือ 403 แสดงว่า Token ไม่ถูกต้อง หรือยังไม่ได้รับการอนุมัติสิทธิ์เข้าถึงโมเดลบน Hugging Face ให้กลับไปเช็กขั้นตอนในส่วน "สิ่งที่ต้องเตรียมก่อนเริ่ม" อีกครั้งครับ&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;ถัดมา เราจะทำการสร้างทั้ง Deployment และ Service ของ vLLM ไปพร้อมๆ กัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-llama31-8b
  namespace: local-llm
  labels:
    app: vllm-llama31-8b
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vllm-llama31-8b
  template:
    metadata:
      labels:
        app: vllm-llama31-8b
    spec:
      nodeSelector:
        node-type: gpu
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
          effect: NoSchedule
      containers:
        - name: vllm
          image: vllm/vllm-openai:v0.26.0
          args:
            - --model=meta-llama/Llama-3.1-8B-Instruct
            - --served-model-name=llama31-8b
            - --max-model-len=8192
            - --gpu-memory-utilization=0.90
            - --port=8000
          env:
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: HF_TOKEN
            - name: HF_HOME
              value: /root/.cache/huggingface
          ports:
            - containerPort: 8000
              name: http
          resources:
            requests:
              cpu: "4"
              memory: 16Gi
              nvidia.com/gpu: "1"
            limits:
              memory: 22Gi
              nvidia.com/gpu: "1"
          volumeMounts:
            # For shared memory (vLLM requirement)
            - name: dshm
              mountPath: /dev/shm
            - name: model-cache
              mountPath: /root/.cache/huggingface
          startupProbe:
            httpGet:
              path: /health
              port: 8000
            periodSeconds: 10
            failureThreshold: 120
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            periodSeconds: 30
            failureThreshold: 5
      volumes:
        - name: dshm
          emptyDir:
            medium: Memory
            sizeLimit: 8Gi
        - name: model-cache
          emptyDir:
            sizeLimit: 60Gi
---
apiVersion: v1
kind: Service
metadata:
  name: vllm-llama31-8b
  namespace: local-llm
  labels:
    app: vllm-llama31-8b
spec:
  type: ClusterIP
  selector:
    app: vllm-llama31-8b
  ports:
    - name: http
      port: 8000
      targetPort: 8000
&lt;/span&gt;&lt;span class="no"&gt;
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📌 &lt;u&gt;สรุปรายละเอียดคอนฟิกสำคัญ&lt;/u&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling &amp;amp; Placement:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;nodeSelector.node-type:&lt;/strong&gt; &lt;code&gt;gpu&lt;/code&gt; &lt;em&gt;# ระบุให้ Pod วิ่งไปลงเฉพาะ Node ที่มี Label node-type: &lt;code&gt;gpu&lt;/code&gt;&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tolerations: nvidia.com/gpu:NoSchedule operator: Exists&lt;/strong&gt; &lt;em&gt;# ปลด Taint บน GPU Node เพื่อให้ Pod สามารถ Schedule ลงไปทำงานได้&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vLLM Arguments:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--model&lt;/code&gt;: ระบุ Model Repository บน Hugging Face (&lt;code&gt;meta-llama/Llama-3.1-8B-Instruct&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--served-model-name&lt;/code&gt;: กำหนดชื่อโมเดลอ้างอิงผ่าน API (เช่น เวลาเรียกใช้งานผ่าน /v1/models จะเห็นชื่อ &lt;code&gt;llama31-8b&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--gpu-memory-utilization=0.90&lt;/code&gt;: จอง VRAM ไว้ 90% สำหรับ Model Weights และ KV Cache โดยเหลือไว้ 10% ให้กับ CUDA Context และ System Driver&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--max-model-len=8192&lt;/code&gt;: (ค่าสำคัญที่สุดใน Lab นี้!) ควบคุมขนาด Context Window รวม (Prompt + Output) ไว้ที่ 8,192 Tokens แม้ว่า Llama 3.1 จะรองรับสูงสุดถึง 131,072 Tokens แต่เนื่องจาก GPU L4 (VRAM 24GB) มีพื้นที่จำกัด หากไม่จำกัดค่านี้ไว้ VRAM จะเต็มและ Container จะระเบิด (OOM) ทันทีครับ 😂 (เรื่องวิธีคำนวณ VRAM เดี๋ยวผมมาแชร์รายละเอียดใน EP ถัดๆ ไปครับ)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Request &amp;amp; Memory Volumes:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nvidia.com/gpu: "1"&lt;/code&gt;: Extended Resource สำหรับแจ้ง kube-scheduler ให้ทำการ Reserve GPU 1 ใบให้กับ Pod &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dshm volume (medium: Memory, sizeLimit: 8Gi)&lt;/code&gt;: ค่านี้ยังไม่มีผลมาก แต่จะมีประโยชน์เมื่อมีการ share ข้อมูลกับ Worker Processes หลายตัวใน node เดียวกัน&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;model-cache volume (emptyDir, sizeLimit: 60Gi)&lt;/code&gt;: จองดิสก์ขนาด 60GB สำหรับ Cache ตัว Model Weights ที่ดาวน์โหลดมาจาก Hugging Face&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;หลังจากสั่ง Deploy เรียบร้อยแล้ว ให้รันคำสั่งด้านล่างนี้เพื่อติดตามสถานะการรันและดู Log ของ vLLM Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ตรวจสอบสถานะของ Pod (กด Ctrl+C เพื่อออกจากโหมด watch)&lt;/span&gt;
kubectl get pod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vllm-llama31-8b &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm &lt;span class="nt"&gt;-w&lt;/span&gt; 

&lt;span class="c"&gt;# ดู Log การทำงานของ vLLM แบบ Real-time&lt;/span&gt;
kubectl logs &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vllm-llama31-8b &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อดู pod status สถานะของ Pod จะค่อยๆ เปลี่ยนตามลำดับดังนี้: &lt;br&gt;
&lt;code&gt;Pending&lt;/code&gt; ➔ &lt;code&gt;ContainerCreating&lt;/code&gt; ➔ &lt;code&gt;Running (0/1 Ready)&lt;/code&gt; ➔ &lt;code&gt;Running (1/1 Ready)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F354bnavacqnqx4g58w28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F354bnavacqnqx4g58w28.png" alt=" " width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏱️ สิ่งที่เกิดขึ้นในช่วง &lt;code&gt;Running (0/1 Ready)&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
เมื่อ Pod เปลี่ยนเป็น Running แต่สถานะ &lt;code&gt;Ready&lt;/code&gt; ยังเป็น &lt;code&gt;0/1&lt;/code&gt; แปลว่า Karpenter ได้ Provision ตัว GPU Node และ Schedule Pod ลงเครื่องเรียบร้อยแล้ว ในช่วงนี้ระบบกำลังทำขั้นตอนสำคัญคือ&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ดาวน์โหลด Weights ของโมเดลจาก Hugging Face ลง Storage Cache&lt;/li&gt;
&lt;li&gt;โหลด Model Weights ทั้งหมดขึ้นไปยัง GPU VRAM (NVIDIA L4)&lt;/li&gt;
&lt;li&gt;เริ่มต้นเปิดบริการ OpenAI-compatible API Server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เมื่อระบบพร้อมใช้งาน Pod จะเปลี่ยนสถานะเป็น &lt;code&gt;Ready 1/1&lt;/code&gt; และใน Log จะแสดงข้อความการตอบรับ Health Check จาก Kubernetes ดังภาพ:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9czsl4ra9ob960bvw038.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9czsl4ra9ob960bvw038.png" alt=" " width="799" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Troubleshooting Tips:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;หาก Pod ค้างที่สถานะ &lt;code&gt;Pending&lt;/code&gt; นานเกินไป: ให้เช็กว่า nodeSelector / tolerations ถูกต้องหรือไม่ หรือ Karpenter ติด Quota ในการสร้าง GPU Node&lt;/li&gt;
&lt;li&gt;หาก Pod มีการ Restart หรือ CrashLoopBackOff: ให้เช็ก Log ของ vLLM ลำดับแรก มักเกิดจาก &lt;code&gt;HF_TOKEN&lt;/code&gt; ไม่ถูกต้อง หรือการตั้งค่า vLLM Arguments เช่น &lt;code&gt;--max-model-len&lt;/code&gt; สูงเกินกว่า VRAM ที่มี&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Route สำคัญที่ควรรู้จัก
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/health&lt;/code&gt; : readiness/liveness probe&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/metrics&lt;/code&gt; : Prometheus scrape (มี TTFT, TPOT, queue size, KV cache usage)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1/models&lt;/code&gt; : ตรวจว่า served_model_name ถูกต้อง&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1/chat/completions&lt;/code&gt; : OpenAI-compatible endpoint หลัก&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1/messages&lt;/code&gt; : Anthropic-compatible endpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ✨ ตอนนี้เราได้ Local LLM Server ที่พร้อมใช้งานเรียบร้อยแล้วครับ! 👏👏
&lt;/h3&gt;


&lt;h2&gt;
  
  
  ขั้นตอนที่ 5 :  Provision Chat Interface (Open WebUI)
&lt;/h2&gt;

&lt;p&gt;เพื่อให้ทดสอบและใช้งานโมเดลได้เห็นภาพชัดเจนยิ่งขึ้น ผมจะ Deploy Web Chat Platform อย่าง Open WebUI มาทำหน้าที่เป็น Client สำหรับเรียกใช้งาน OpenAI-compatible API ที่รันอยู่บน vLLM ครับ&lt;/p&gt;

&lt;p&gt;เรามาเริ่ม Deploy Open WebUI กันเลย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | envsubst | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-webui
  namespace: local-llm
  labels:
    app: open-webui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: open-webui
  template:
    metadata:
      labels:
        app: open-webui
    spec:
      containers:
        - name: open-webui
          image: ghcr.io/open-webui/open-webui:v0.9.2
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 500m
              memory: 500Mi
            limits:
              cpu: "1"
              memory: 1Gi
          env:
            - name: OPENAI_API_BASE_URLS
              value: "http://vllm-llama31-8b:8000/v1"
            - name: OPENAI_API_KEY
              value: "dummy"        # lab only
            - name: WEBUI_AUTH
              value: "False"        # lab only
            - name: ENABLE_OLLAMA_API
              value: "False"
            - name: ENABLE_EVALUATION_ARENA_MODELS
              value: "False"
            - name: RAG_EMBEDDING_ENGINE
              value: ""
          volumeMounts:
            - name: webui-volume
              mountPath: /app/backend/data
      volumes:
        - name: webui-volume
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: open-webui
  namespace: local-llm
  labels:
    app: open-webui
spec:
  type: ClusterIP
  selector:
    app: open-webui
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Output:&lt;/span&gt;
&lt;span class="c"&gt;# deployment.apps/open-webui created&lt;/span&gt;
&lt;span class="c"&gt;# service/open-webui created&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📌 &lt;u&gt;สรุปรายละเอียดคอนฟิกสำคัญ&lt;/u&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OPENAI_API_BASE_URLS: "http://vllm-llama31-8b:8000/v1"&lt;/code&gt;: ชี้ endpoint ไปยัง vLLM Service ภายใน EKS Cluster &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OPENAI_API_KEY: "dummy"&lt;/code&gt;: เนื่องจากใน vLLM Deployment ของเราไม่ได้ตั้งค่าใส่ API Key ไว้ จึงใส่ค่าอะไรก็ได้เพื่อให้ Open WebUI ส่ง Request ผ่านได้&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WEBUI_AUTH: "False"&lt;/code&gt;: ปิดระบบ Login/Register เพื่อให้เข้าใช้งานหน้าเว็บแชทได้ทันทีโดย authentication (เหมาะสำหรับทดสอบใน Lab เท่านั้น)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ENABLE_OLLAMA_API: "False"&lt;/code&gt;: ปิดฟีเจอร์การเชื่อมต่อ Ollama เนื่องจากเราใช้ vLLM เป็น Inference Engine หลักเพียงตัวเดียว&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;จากนั้นลองตรวจสอบสถานะการรันของ Open WebUI Pod ด้วยคำสั่ง:&lt;br&gt;
 &lt;code&gt;kubectl get pod -l app=open-webui -n local-llm -w&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj3wtr4hyvk4lcuwcnfy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj3wtr4hyvk4lcuwcnfy9.png" alt=" " width="796" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;เมื่อ Pod แสดงสถานะ &lt;code&gt;Ready 1/1&lt;/code&gt; แปลว่าตัว Application ทำงานเรียบร้อยแล้วครับ!&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;🌐 สร้าง Ingress (AWS ALB) เพื่อเปิดให้เข้าใช้งานจากภายนอก&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;เนื่องจากตอนนี้ Stack ทั้งหมดของเราทำงานอยู่ภายใน VPC ของ EKS Cluster เราจึงจำเป็นต้องสร้าง Ingress เพื่อสั่งให้ EKS (AWS ALB Controller) ทำการ Provision &lt;strong&gt;Application Load Balancer (ALB)&lt;/strong&gt; แบบ Public ให้อัตโนมัติครับ&lt;/p&gt;

&lt;p&gt;รันคำสั่งด้านล่างนี้บน CloudShell เพื่อสร้างทั้ง &lt;code&gt;IngressClassParams&lt;/code&gt;, &lt;code&gt;IngressClass&lt;/code&gt; และ &lt;code&gt;Ingress&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. สร้าง IngressClassParams และ IngressClass สำหรับ ALB&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: eks.amazonaws.com/v1        
kind: IngressClassParams
metadata:
  name: alb
spec:
  scheme: internet-facing
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: alb
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: eks.amazonaws.com/alb     
  parameters:
    apiGroup: eks.amazonaws.com
    kind: IngressClassParams
    name: alb
&lt;/span&gt;&lt;span class="no"&gt;EOF


&lt;/span&gt;&lt;span class="c"&gt;# 2. สร้าง Ingress Resource เพื่อ Provision Public ALB&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: open-webui
  namespace: local-llm
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing   
    alb.ingress.kubernetes.io/target-type: ip           
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80}]'
    alb.ingress.kubernetes.io/healthcheck-path: /health
    alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=300
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: open-webui
                port:
                  number: 80
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลังจากสร้าง Ingress เรียบร้อยแล้ว ให้รอสักครู่ (ประมาณ 1–2 นาที) แล้วรันคำสั่งตรวจสอบสถานะของ Ingress เพื่อเอา Public DNS URL ของ ALB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress/open-webui &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ในช่อง ADDRESS จะเห็น URL ของ AWS ALB ขึ้นมา (เช่น &lt;code&gt;k8s-localllm-openwebu-xxx.us-east-1.elb.amazonaws.com&lt;/code&gt;) ซึ่งเราจะใช้ URL นี้ในการเข้าใช้งาน Chat Platform ผ่าน Web Browser ในขั้นตอนถัดไปครับ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzcaxneyp1mp8jis8arlr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzcaxneyp1mp8jis8arlr.png" alt=" " width="800" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ คำเตือนเรื่องความปลอดภัย (Security Alert):&lt;/strong&gt;&lt;br&gt;
ในบทความนี้เราสร้าง Public ALB แบบให้เข้าถึงผ่านอินเทอร์เน็ตได้โดยไม่ได้จำกัด Source IP Address เพื่อความสะดวกในการทดสอบ Lab สำหรับใครนำไปประยุกต์ใช้ในองค์กรหรือ Production ควรกำหนด Security Group หรือใช้ WAF/Inbound CIDR IP Restriction เพิ่มเติม เพื่อความปลอดภัยครับ&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 6: ทดสอบใช้งานจริงผ่าน Web Browser
&lt;/h2&gt;

&lt;p&gt;คัดลอก ALB URL Address ที่ได้จากขั้นตอนก่อนหน้า นำมาเปิดบน Web Browser ได้เลยครับ&lt;/p&gt;

&lt;p&gt;เมื่อหน้าเว็บ Open WebUI โหลดขึ้นมา สังเกตที่ด้านบนของช่องแชทจะเห็นชื่อโมเดล &lt;code&gt;llama31-8b&lt;/code&gt; แสดงอยู่อย่างถูกต้อง (ซึ่งเป็นชื่อเดียวกับที่เรากำหนดผ่าน &lt;code&gt;--served-model-name&lt;/code&gt; ใน vLLM)&lt;/p&gt;

&lt;p&gt;ลองพิมพ์คำถามหรือเริ่มส่ง Prompt ทดสอบได้เลย!&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz88xxnis1gz61b52dl21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz88xxnis1gz61b52dl21.png" alt=" " width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;จะเห็นว่าตัวโมเดลตอบกลับได้อย่างรวดเร็วผ่าน vLLM Engine ที่รันอยู่บน GPU L4 บน Amazon EKS ครับ&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff4hht3tzh8fkz0rrc5ek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff4hht3tzh8fkz0rrc5ek.png" alt=" " width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  ขั้นตอนที่ 7 :  Cleanup / Uninstall Resource
&lt;/h2&gt;

&lt;p&gt;เมื่อทดสอบเสร็จเรียบร้อยแล้ว อย่าลืมลบ Resource ทั้งหมดที่สร้างขึ้นด้วยนะครับ ไม่งั้น Cost พุ่งแน่นอน &lt;/p&gt;

&lt;p&gt;คำสั่งในการ Cleanup Resource ทั้งหมด&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# 1. ลบ Deployments ทั้งหมด&lt;/span&gt;
kubectl delete deployment/open-webui &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm
kubectl delete deployment/vllm-llama31-8b &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm

&lt;span class="c"&gt;# 2. ลบ Services ทั้งหมด&lt;/span&gt;
kubectl delete service/open-webui &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm
kubectl delete service/vllm-llama31-8b &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm

&lt;span class="c"&gt;# 3. ลบ Ingress (เพื่อสั่งลบ AWS ALB)&lt;/span&gt;
kubectl delete ingress/open-webui &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm

&lt;span class="c"&gt;# 4. ลบ Kubernetes Secrets &lt;/span&gt;
kubectl delete secret hf-secret &lt;span class="nt"&gt;-n&lt;/span&gt; local-llm

&lt;span class="c"&gt;# 5. Karpenter GPU NodePool&lt;/span&gt;
kubectl delete nodepool/gpu

&lt;span class="c"&gt;# 6. ลบ EKS Cluster ทั้งหมดผ่าน eksctl&lt;/span&gt;
eksctl delete cluster llm-eks-lab &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;u&gt;💳 ประมาณการค่าใช้จ่าย (Cost Estimates) สำหรับ Lab นี้:&lt;/u&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EKS Cluster Control Plane (Auto Mode):&lt;/strong&gt;  &lt;code&gt;$0.1&lt;/code&gt; / ชั่วโมง &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 System Node (1 Instance):&lt;/strong&gt;  &lt;code&gt;$0.1075&lt;/code&gt; / ชั่วโมง &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 General-Purpose Node (1 Instance):&lt;/strong&gt;  &lt;code&gt;$0.2150&lt;/code&gt; / ชั่วโมง &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 GPU Node &lt;code&gt;g6.2xlarge&lt;/code&gt; (1 Instance):&lt;/strong&gt;  &lt;code&gt;$1.0539&lt;/code&gt; / ชั่วโมง &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Application Load Balancer:&lt;/strong&gt;  &lt;code&gt;$0.0405&lt;/code&gt; / ชั่วโมง &lt;/li&gt;
&lt;li&gt;และมีค่าใช้จ่ายแฝงอื่นๆ อีกเช่น &lt;strong&gt;NAT Gateway&lt;/strong&gt; , &lt;strong&gt;EBS&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;รวมค่าใช้จ่ายทั้งหมดโดยประมาณ:&lt;/strong&gt;  &lt;code&gt;~$1.6&lt;/code&gt; / ชั่วโมง หรือ &lt;code&gt;$1,600&lt;/code&gt; ต่อเดือน&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Tip: ค่าใช้จ่ายส่วนที่มากที่สุดจะตกอยู่กับ GPU Node หากมีแผนการใช้งานอย่างจริงจังบน Production เราสามารถซื้อแผน Reserved Instance หรือ Saving Plan เพื่อลดค่าใช้จ่ายลงได้ 30-35% ครับ&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🎯 สรุปท้ายบทความ
&lt;/h2&gt;

&lt;p&gt;เป็นอย่างไรบ้างครับสำหรับ EP.1 Serving LLM บน EKS Platform ด้วย vLLM&lt;/p&gt;

&lt;p&gt;เพียงไม่กี่ขั้นตอน เราสามารถสร้างโครงสร้างพื้นฐานระดับ Production บน Amazon EKS ตั้งแต่การใช้ EKS Auto Mode + Karpenter ในการจัดการ GPU Node, การรัน vLLM เป็น Inference Engine ไปจนถึงการเปิด OpenAI-compatible API และต่อหน้าจอ Chat ด้วย Open WebUI ได้สำเร็จ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;สำหรับซีรีส์นี้ ใน EP ถัดไปเราจะมาเจาะลึกในหัวข้อเหล่านี้กันต่อครับ:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🛠️ Best Practices: Serving LLM on EKS&lt;/li&gt;
&lt;li&gt;💻 LLM on CPU EKS: ทางเลือกราคาประหยัดสำหรับ Small-Scale Model&lt;/li&gt;
&lt;li&gt;📊 LLM Observability: ติดตามประสิทธิภาพ TTFT, TPOT และ GPU Metrics&lt;/li&gt;
&lt;li&gt;📈 LLM Multi-Node &amp;amp; Dynamic Scale: การทำ Auto-scaling ตามปริมาณ Request&lt;/li&gt;
&lt;li&gt;📦 Quantization (FP8/AWQ): บีบอัดโมเดลเพื่อประหยัด VRAM และเพิ่ม Throughput&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ฝากกด Like หรือพิมพ์ Comment พูดคุยติชมกันได้เลยนะครับ แล้วพบกันใหม่ใน EP ถัดไปครับ! 👋✨&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>kubernetes</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Building a Multi-Region Failover System with Amazon EKS (Step-By-Step) [Thai language]</title>
      <dc:creator>Mongkol Thongkraikaew</dc:creator>
      <pubDate>Wed, 05 Nov 2025 05:03:23 +0000</pubDate>
      <link>https://dev.to/mongkol_tho/building-a-multi-region-failover-system-with-amazon-eks-step-by-step-thai-language-aoo</link>
      <guid>https://dev.to/mongkol_tho/building-a-multi-region-failover-system-with-amazon-eks-step-by-step-thai-language-aoo</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/mongkol_tho" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2442353%2Fa247a8f1-4d52-4284-940a-656afc6475aa.JPG" alt="mongkol_tho"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/mongkol_tho/maalngsraangrabb-failover-aebb-multi-region-kab-amazon-eks-aebb-step-by-step-51c6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;มาลองสร้างระบบ Failover แบบ Multi-Region กับ Amazon EKS (แบบ Step-by-step)&lt;/h2&gt;
      &lt;h3&gt;Mongkol Thongkraikaew ・ Nov 5&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#eks&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#aws&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#failover&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>eks</category>
      <category>aws</category>
      <category>failover</category>
      <category>devops</category>
    </item>
    <item>
      <title>มาลองสร้างระบบ Failover แบบ Multi-Region กับ Amazon EKS (แบบ Step-by-step)</title>
      <dc:creator>Mongkol Thongkraikaew</dc:creator>
      <pubDate>Wed, 05 Nov 2025 05:01:33 +0000</pubDate>
      <link>https://dev.to/mongkol_tho/maalngsraangrabb-failover-aebb-multi-region-kab-amazon-eks-aebb-step-by-step-51c6</link>
      <guid>https://dev.to/mongkol_tho/maalngsraangrabb-failover-aebb-multi-region-kab-amazon-eks-aebb-step-by-step-51c6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;มีใครได้ลองคิดหรือเตรียมตัวเผื่อไว้หรือยังหาก Region ที่เราใช้งานอยู่ ล่มไปในช่วงเวลาที่มีผู้ใช้งานระบบเราอยู่จำนวนมาก เราจะทำอย่างไร?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ช่วงนี้หลายคนน่าจะได้เห็นข่าวหรือเจอเหตุการณ์ AWS ในบาง Region เกิดปัญหาจนระบบต่าง ๆ ใช้งานไม่ได้ ซึ่งเป็นอีกหนึ่ง Reminder ว่าระบบที่เราทำงานอยู่จะมองข้ามเรื่อง Availability หรือการเตรียมพร้อมรับมือกับปัญหาลักษณะแบบนี้ไม่ได้เลย &lt;/p&gt;

&lt;p&gt;ในบทความนี้ ผมจะพามาลองตั้งค่าระบบ Failover แบบ Multi-Region กับ Amazon EKS แบบ Step-by-step ให้เห็นกันชัด ๆ ว่าทำอย่างไร เหมาะสำหรับเอาไปปรับใช้กับระบบงานที่ทุกคนใช้กันอยู่ได้ เพื่อเพิ่ม resiliency ให้กับระบบของเรามากขึ้น&lt;/p&gt;

&lt;h2&gt;
  
  
  เครื่องมือที่จำเป็นสำหรับ workshop นี้
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS Account
&lt;/li&gt;
&lt;li&gt;Route 53 (Public Hosted Zone)
&lt;/li&gt;
&lt;li&gt;AWS CloudShell
&lt;/li&gt;
&lt;li&gt;CLI ที่ต้องใช้: &lt;code&gt;aws&lt;/code&gt;, &lt;code&gt;envsubst&lt;/code&gt;, &lt;code&gt;eksctl&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;kubectx&lt;/code&gt;, &lt;code&gt;kubens&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เมื่อพร้อมแล้ว มาลองลงมือสร้างระบบไปพร้อม ๆ กันได้เลยครับ ทุกคนสามารถรันคำสั่งตามขั้นตอนที่ผมโชว์ไว้ได้ทันที&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhvvgd1pb84hfbfw7dy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhvvgd1pb84hfbfw7dy0.png" alt="Diagram Workshop" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 1 : ติดตั้งและตั้งค่า EKS Cluster
&lt;/h2&gt;

&lt;p&gt;1.1 เปิด CloudShell ขึ้นมาก่อน&lt;br&gt;
&lt;em&gt;***ในบทความนี้ ผมจะรันทุกคำสั่งจาก CloudShell ที่ Region: Singapore เท่านั้น เนื่องจากตอนนี้ CloudShell ยังไม่มีให้บริการที่ Region: Thailand&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;1.2 ตั้งค่าพื้นฐานและติดตั้งเครื่องมือที่ต้องใช้งาน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
export Region1=ap-southeast-7
export Region2=ap-southeast-1
export Region1ClusterName=eks-cluster-th
export Region2ClusterName=eks-cluster-sg
export ALBName=web-alb

# เปลี่ยนตาม domain ของแต่ละคน
export apphostname=web-demo.cloudation101.net
export HostedZoneName=cloudation101.net
export HostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name $HostedZoneName --query 'HostedZones[0].Id' --output text |  cut -d'/' -f3)

# Install envsubst cli 
sudo yum install gettext -y 

# Install eksctl
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp &amp;amp;&amp;amp; rm eksctl_$PLATFORM.tar.gz
sudo install -m 0755 /tmp/eksctl /usr/local/bin &amp;amp;&amp;amp; rm /tmp/eksctl

# Install kubectx, kubens cli
sudo git clone https://github.com/ahmetb/kubectx /opt/kubectx
sudo ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx
sudo ln -s /opt/kubectx/kubens /usr/local/bin/kubens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1.3 สร้าง EKS Cluster ในทั้ง 2 Region&lt;br&gt;
ดำเนินการสร้าง EKS Cluster ใน Region หลักและ Region สำรอง เตรียมพร้อมสำหรับการทำ Multi-Region&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create EKS cluster auto mode in Region: Thailand
eksctl create cluster --name=$Region1ClusterName --enable-auto-mode --region=$Region1

# Create EKS cluster auto mode in Region: Singapore
eksctl create cluster --name=$Region2ClusterName --enable-auto-mode --region=$Region2

# Validate cluster status (Status: Active)
aws eks describe-cluster \--name $Region1ClusterName \--region $Region1 \--output json \--query 'cluster.status'

aws eks describe-cluster \--name $Region2ClusterName \--region $Region2 \--output json \--query 'cluster.status'

# รอประมาณ 15 นาทีในการสร้างแต่ละ cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
เมื่อ EKS Cluster สร้างแล้ว เราจะพบว่ามี EKS Cluster ถูกสร้างขึ้นในแต่ละ Region&lt;/p&gt;

&lt;p&gt;Region: Thailand&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jurf433rgenukbbxqd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jurf433rgenukbbxqd4.png" alt="EKS Cluster Region: Thailand" width="800" height="198"&gt;&lt;/a&gt;&lt;br&gt;
Region: Sigapore&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzr8nsuhqpqza7wshbje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzr8nsuhqpqza7wshbje.png" alt="EKS Cluster Region: Singapore" width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
1.4 ทดสอบเชื่อมต่อกับ EKS Cluster ด้วย &lt;code&gt;kubectl&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectx $(kubectx | grep "eks-cluster-th")
kubectl get node

kubectx $(kubectx | grep "eks-cluster-sg")
kubectl get node 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างผลลัพธ์การทดสอบเรียก EKS API&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza6xtfa26177htqjakxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza6xtfa26177htqjakxf.png" alt="Kubectl get node result" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  ขั้นตอนที่ 2 : Deploy Web Application
&lt;/h2&gt;

&lt;p&gt;2.1 สร้าง IngressClass &lt;code&gt;alb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Config ingressclassconfiguration for Thailand
kubectx $(kubectx | grep "eks-cluster-th")
curl -s https://raw.githubusercontent.com/aws-samples/multi-region-ingress/refs/heads/main/ingressclassconfiguration.yaml | kubectl apply -f -
kubectl get ingressclass,ingressclassparams

# Config ingressclassconfiguration for Singapore
kubectx $(kubectx | grep "eks-cluster-sg")
curl -s https://raw.githubusercontent.com/aws-samples/multi-region-ingress/refs/heads/main/ingressclassconfiguration.yaml | kubectl apply -f -
kubectl get ingressclass,ingressclassparams
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.2 สร้าง ServiceAccount, Clusterrole, Service และ Deploy Web App Demo&lt;br&gt;
&lt;strong&gt;Deploy Web App @ Region: Thailand&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Switch EKS cluster
kubectx $(kubectx | grep "eks-cluster-th")

cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: webapp-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: webapp-clusterrole
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: webapp-clusterrolebinding
subjects:
  - kind: ServiceAccount
    name: webapp-sa
    namespace: default
roleRef:
  kind: ClusterRole
  name: webapp-clusterrole
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      serviceAccountName: webapp-sa
      containers:
      - image: dumlutimuralp/demoapp
        name: webapp
        env:
        - name: APP_NAME
          value: "WebApp_Demo_TH"
        - name: BG_COLOR
          value: "green" 
        - name: HEALTH
          value: "webapphealth"  
        - name: MY_NODENAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
---
apiVersion: v1
kind: Service
metadata:
  name: webappservice
spec:
  selector:
    app: webapp
  ports:
    - protocol: TCP
      port: 80
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Deploy Web App @ Region: Singapore&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Switch EKS cluster
kubectx $(kubectx | grep "eks-cluster-sg")

cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: webapp-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: webapp-clusterrole
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: webapp-clusterrolebinding
subjects:
  - kind: ServiceAccount
    name: webapp-sa
    namespace: default
roleRef:
  kind: ClusterRole
  name: webapp-clusterrole
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      serviceAccountName: webapp-sa
      containers:
      - image: dumlutimuralp/demoapp
        name: webapp
        env:
        - name: APP_NAME
          value: "WebApp_Demo_SG"
        - name: BG_COLOR
          value: "red" 
        - name: HEALTH
          value: "webapphealth"  
        - name: MY_NODENAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
---
apiVersion: v1
kind: Service
metadata:
  name: webappservice
spec:
  selector:
    app: webapp
  ports:
    - protocol: TCP
      port: 80
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.3 สร้าง Ingress สำหรับ Web App ทั้ง Thailand และ Singapore Region&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Switch EKS cluster to Thailand
kubectx $(kubectx | grep "eks-cluster-th")

cat &amp;lt;&amp;lt;EOF | envsubst | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp-ingress 
  annotations:
    alb.ingress.kubernetes.io/load-balancer-name: $ALBName
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb 
  rules:
  - host: $apphostname
    http:
      paths:
      - path: / 
        pathType: Prefix
        backend:
          service:
            name: webappservice 
            port:
               number: 80 
  - http:
      paths:
      - path: /webapphealth
        pathType: Prefix
        backend:
          service:
            name: webappservice
            port:
               number: 80 
EOF

# Switch EKS cluster to Singapore
kubectx $(kubectx | grep "eks-cluster-sg")

cat &amp;lt;&amp;lt;EOF | envsubst | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp-ingress 
  annotations:
    alb.ingress.kubernetes.io/load-balancer-name: $ALBName
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb 
  rules:
  - host: $apphostname
    http:
      paths:
      - path: / 
        pathType: Prefix
        backend:
          service:
            name: webappservice 
            port:
               number: 80 
  - http:
      paths:
      - path: /webapphealth
        pathType: Prefix
        backend:
          service:
            name: webappservice
            port:
               number: 80 
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.4 ตรวจสอบ Resource ที่ถูกสร้างในทั้ง 2 Region ขั้นตอนนี้ เราควรจะเห็น resource อย่างเช่น Deployment และ Ingress ถูกสร้างขึ้นครบถ้วนทั้ง 2 Region&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectx $(kubectx | grep "eks-cluster-th")
kubectl get all,ingress

kubectx $(kubectx | grep "eks-cluster-sg")
kubectl get all,ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างผลลัพธ์ Kubernetes resource&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4tvz42ap9o99ayvuiyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4tvz42ap9o99ayvuiyq.png" alt="kubectl get all,ingress result" width="800" height="474"&gt;&lt;/a&gt;&lt;br&gt;
ทดสอบเข้าถึง website ทั้งสอง region ด้วย ALB domain&lt;br&gt;
Region: Thailand (สีเขียว)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5avv8bcf9peh020kq1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5avv8bcf9peh020kq1f.png" alt="Example website of thailand region" width="751" height="139"&gt;&lt;/a&gt;&lt;br&gt;
Region: Singapore (สีแดง)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flscc12okbl06h1q2wbzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flscc12okbl06h1q2wbzd.png" alt="Example website of singapore region" width="743" height="167"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ขั้นตอนที่ 3 : ตั้งค่า Route 53 Health Check และ Record
&lt;/h2&gt;

&lt;p&gt;3.1 ตั้งค่า Health Check เพื่อคอยตรวจสอบสถานะ web application ในทั้ง 2 Region ว่ายังทำงานปกติหรือไม่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Find ALB Domain
export Region1ALB=$(aws elbv2 describe-load-balancers --region $Region1 --query "LoadBalancers[?contains(LoadBalancerName, '$ALBName')].DNSName | [0]" --output text)
export Region2ALB=$(aws elbv2 describe-load-balancers --region $Region2 --query "LoadBalancers[?contains(LoadBalancerName, '$ALBName')].DNSName | [0]" --output text)

# Create Route 53 health check for Thailand region
aws route53 create-health-check --caller-reference "RegionTH-WebApp-$(date +%s)" \
--health-check-config "{\"Port\":80,\"Type\":\"HTTP\",\"ResourcePath\":\"/webapphealth\",\"FullyQualifiedDomainName\":\"$Region1ALB\",\"RequestInterval\":10,\"FailureThreshold\":2,\"MeasureLatency\":true,\"Inverted\":false,\"Disabled\":false,\"EnableSNI\":false}"

# Create Route 53 health check for Singapore region
aws route53 create-health-check --caller-reference "RegionSG-WebApp-$(date +%s)" \
--health-check-config "{\"Port\":80,\"Type\":\"HTTP\",\"ResourcePath\":\"/webapphealth\",\"FullyQualifiedDomainName\":\"$Region2ALB\",\"RequestInterval\":10,\"FailureThreshold\":2,\"MeasureLatency\":true,\"Inverted\":false,\"Disabled\":false,\"EnableSNI\":false}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างผลลัพธ์การสร้าง Route 53 Health Check&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2imhjcetn3ss07ad1w31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2imhjcetn3ss07ad1w31.png" alt=" " width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.2 สร้าง Route 53 Alias Record ซึ่งเราจะสร้าง 2 Alias record สำหรับ domain: web-demo.cloudation101.net ไปยัง ALB ของทั้ง 2 region และผมจะทำการ associate แต่ละ record ด้วย healthcheck ที่ถูกสร้างขึ้นก่อนหน้านี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Find Health Check ID
export HealthCheckRegion1AppId=$(aws route53 list-health-checks \
  --query "HealthChecks[?HealthCheckConfig.FullyQualifiedDomainName=='$Region1ALB' &amp;amp;&amp;amp; HealthCheckConfig.ResourcePath=='/webapphealth'] | [0].Id" \
  --output text)

export HealthCheckRegion2AppId=$(aws route53 list-health-checks \
  --query "HealthChecks[?HealthCheckConfig.FullyQualifiedDomainName=='$Region2ALB' &amp;amp;&amp;amp; HealthCheckConfig.ResourcePath=='/webapphealth'] | [0].Id" \
  --output text)

# Find Hosted Zone ID of your domain
export Region1ALBHostedZoneId=$(aws elbv2 describe-load-balancers --region $Region1 --query "LoadBalancers[?DNSName=='$Region1ALB'].CanonicalHostedZoneId" --output text)
export Region2ALBHostedZoneId=$(aws elbv2 describe-load-balancers --region $Region2 --query "LoadBalancers[?DNSName=='$Region2ALB'].CanonicalHostedZoneId" --output text)

# Create the alias record for ALB's Thailand
aws route53 change-resource-record-sets --hosted-zone-id $HostedZoneId \
  --change-batch "{\"Changes\":[{\"Action\":\"CREATE\",\"ResourceRecordSet\":{\"Name\":\"$apphostname\",\"Type\":\"A\",\"SetIdentifier\":\"Region1-Primary\",\"Weight\":100,\"HealthCheckId\":\"$HealthCheckRegion1AppId\",\"AliasTarget\":{\"HostedZoneId\":\"$Region1ALBHostedZoneId\",\"DNSName\":\"$Region1ALB\",\"EvaluateTargetHealth\":false}}}]}"

# Create the alias record for ALB's Singapore
aws route53 change-resource-record-sets --hosted-zone-id $HostedZoneId \
  --change-batch "{\"Changes\":[{\"Action\":\"CREATE\",\"ResourceRecordSet\":{\"Name\":\"$apphostname\",\"Type\":\"A\",\"SetIdentifier\":\"Region2-Secondary\",\"Weight\":0,\"HealthCheckId\":\"$HealthCheckRegion2AppId\",\"AliasTarget\":{\"HostedZoneId\":\"$Region2ALBHostedZoneId\",\"DNSName\":\"$Region2ALB\",\"EvaluateTargetHealth\":false}}}]}"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;หมายเหตุ:&lt;br&gt;
ผมเลือกใช้ Routing Policy แบบ Weighted เพื่อกำหนดให้ Route 53 ตอบ ALB IP จาก Region: Thailand เป็นลำดับแรกเสมอ ตราบใดที่ Health Check ของ web app ในทั้ง 2 region ยัง healthty ทุกตัว&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ตรวจสอบว่า DNS Record ถูกสร้างใน Hosted Zone ตามที่ต้องการแล้วหรือยัง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws route53 list-resource-record-sets --hosted-zone-id $HostedZoneId --query "ResourceRecordSets[?Name=='$apphostname.']"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างผลลัพธ์ &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1aswc5c99ob9wn3bvsu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1aswc5c99ob9wn3bvsu.png" alt=" " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpq31wq6xzr51v8g6a2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpq31wq6xzr51v8g6a2w.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;หากทำการสร้าง Route 53 record เรียบร้อยแล้ว เราสามารถทดสอบเข้าใช้งาน website ผ่าน URL ที่เรากำหนดได้เลย (ตัวอย่าง &lt;a href="http://web-demo.cloudation101.net" rel="noopener noreferrer"&gt;http://web-demo.cloudation101.net&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds1zga8ofx1z22z1gvmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds1zga8ofx1z22z1gvmz.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 4 : Test application failure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y37nbzhz0pncxauch06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y37nbzhz0pncxauch06.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ในขั้นตอนนี้ เราจะจำลองสถานการณ์ที่ web application ใน Region: Thailand มีปัญหา &lt;/p&gt;

&lt;p&gt;4.1 Scale down web application ในฝั่ง Thailand region&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectx $(kubectx | grep "eks-cluster-th")
kubectl scale deployment webapp --replicas=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลังจากที่เราทำการ scale down (ลดจำนวน pod) ของ web application ใน Region: Thailand แล้ว จะเห็นได้ว่า Health Check ของ Route 53 สำหรับฝั่งนี้จะเปลี่ยนสถานะเป็น Unhealthy ทันที&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdxibht294p4zhu6m7nm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdxibht294p4zhu6m7nm.png" alt=" " width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;เมื่อเราทดสอบเข้าเว็บไซต์ผ่าน URL เดิมอีกครั้ง ระบบ Route 53 จะเปลี่ยนเส้นทางการเข้าถึงไปยัง web application ในฝั่ง Singapore region ให้โดยอัตโนมัติ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1csngl0j7ahrjq4f44e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1csngl0j7ahrjq4f44e.png" alt=" " width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;หมายเหตุ:&lt;br&gt;
ความเร็วในการเปลี่ยนเส้นทาง (redirect) ผู้ใช้ไปยัง Singapore region จะขึ้นอยู่กับหลายปัจจัย เช่น เงื่อนไขของ Health Check ที่ตั้งไว้, ค่า DNS TTL ของฝั่ง client, รวมถึงการตั้งค่า ALB และค่า HTTP Keepalive ของ ALB ด้วย&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ขั้นตอนที่ 5 : Clean up Environment
&lt;/h2&gt;

&lt;p&gt;5.1 Delete Route53 Alias Record&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws route53 change-resource-record-sets --hosted-zone-id $HostedZoneId \
  --change-batch "{\"Changes\":[{\"Action\":\"DELETE\",\"ResourceRecordSet\":{\"Name\":\"$apphostname\",\"Type\":\"A\",\"SetIdentifier\":\"Region1-Primary\",\"Weight\":100,\"HealthCheckId\":\"$HealthCheckRegion1AppId\",\"AliasTarget\":{\"HostedZoneId\":\"$Region1ALBHostedZoneId\",\"DNSName\":\"$Region1ALB\",\"EvaluateTargetHealth\":false}}}]}"

aws route53 change-resource-record-sets --hosted-zone-id $HostedZoneId \
  --change-batch "{\"Changes\":[{\"Action\":\"DELETE\",\"ResourceRecordSet\":{\"Name\":\"$apphostname\",\"Type\":\"A\",\"SetIdentifier\":\"Region2-Secondary\",\"Weight\":0,\"HealthCheckId\":\"$HealthCheckRegion2AppId\",\"AliasTarget\":{\"HostedZoneId\":\"$Region2ALBHostedZoneId\",\"DNSName\":\"$Region2ALB\",\"EvaluateTargetHealth\":false}}}]}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5.2 Delete Route53 Health Check&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws route53 delete-health-check --health-check-id $HealthCheckRegion1AppId
aws route53 delete-health-check --health-check-id $HealthCheckRegion2AppId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5.3 Delete EKS Cluster&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eksctl delete cluster --name=$Region1ClusterName --region=$Region1
eksctl delete cluster --name=$Region2ClusterName --region=$Region2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson learned จาก Workshop
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Granular failover effect:&lt;/strong&gt; หากผูกหลายๆ service กับ ALB ตัวเดียวกัน, Route 53 จะไม่ทำการ failover ไปอีก region ทั้งหมด ถึงแม้ว่าจะมีแค่บาง service unhealthty (เนื่องจากมีการกำหนด Evaluate Target Health : &lt;strong&gt;No&lt;/strong&gt; ใน alias records)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active-active Routing&lt;/strong&gt;: หากต้องการให้ระบบทำงานแบบ &lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-types.html#dns-failover-types-active-active" rel="noopener noreferrer"&gt;Active-active failover&lt;/a&gt; ให้กำหนด routing policy ให้เหมือนกันในทั้งสอง alias record&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Check แบบ HTTPS&lt;/strong&gt;: ถ้าตั้งค่า health check endpoint เป็น HTTPS, Route 53 health checker จะไม่ทำการ validate SSL/TLS Certificate แต่อย่างใด&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring Private IP&lt;/strong&gt;: Route 53 health checker ไม่รองรับการตรวจสอบ endpoint ที่เป็น private IP หากต้องการ monitor private IP แนะนำให้ใช้งาน &lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/monitoring-health-checks.html" rel="noopener noreferrer"&gt;CloudWatch alarms&lt;/a&gt; หรือ &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/performing-route-53-health-checks-on-private-resources-in-a-vpc-with-aws-lambda-and-amazon-cloudwatch/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ค่าใช้จ่าย Health Check&lt;/strong&gt;: ควรระมัดระวังการสร้าง AWS Route 53 Health Check ในปริมาณมาก เนื่องจากอาจเกิดค่าใช้จ่ายที่สูงได้&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnx42ehpv23roknlzi8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnx42ehpv23roknlzi8m.png" alt=" " width="800" height="383"&gt;&lt;/a&gt;&lt;br&gt;
Ref: &lt;a href="https://aws.amazon.com/route53/pricing/" rel="noopener noreferrer"&gt;https://aws.amazon.com/route53/pricing/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What can be improved?
&lt;/h2&gt;

&lt;p&gt;แม้ในบทความนี้จะพูดถึงการทำ Multi-Region Failover สำหรับ workload ที่รันบน EKS เป็นหลัก แต่ในความเป็นจริงเราก็คงไม่ใช้แค่ Kubernetes อย่างเดียวแน่นอน ส่วนใหญ่มักจะมี service อื่น ๆ ที่ต้องเกี่ยวข้องด้วย เช่น RDS, MSK, S3, ไปจนถึง storage อย่าง EBS ด้วย ซึ่งแต่ละ service ก็จะมีเทคนิคหรือ practice ในการเตรียมพร้อมรับมือกรณี Region ล่มที่แตกต่างกันออกไป&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon RDS&lt;/strong&gt;&lt;br&gt;
ถ้าใช้ RDS MySQL, PostgreSQL หรือ Aurora สามารถตั้งค่า “Read Replica” ข้าม Region ได้เลย หรือข้ามไปใช้ Aurora Global Database (ยังไม่รองรับที่ Thailand Region) เลยก็ได้ ขึ้นอยู่ RTO, RPO ที่เราต้องการ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon MSK (Kafka)&lt;/strong&gt;&lt;br&gt;
สำหรับ MSK ยังไม่มี fully managed multi-region replication เหมือน RDS Aurora ดังนั้นจึงจำเป็นต้องใช้เครื่องมือช่วยอย่าง MSK Replicator หรือ Open source อย่าง MirrorMaker2 ในการ replicate ข้อมูลระหว่าง 2 region&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon S3&lt;/strong&gt;&lt;br&gt;
S3 รองรับการทำ “Cross-Region Replication” (CRR) อยู่แล้ว สามารถตั้ง policy ให้ bucket สำคัญ replicate ข้อมูลข้าม Region ได้อัตโนมัติ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon EBS&lt;/strong&gt;&lt;br&gt;
EBS ไม่สามารถ attach ข้าม Region ได้โดยตรง วิธีป้องกันที่ดีที่สุดคือ สร้าง snapshot แล้ว replicate snapshot ไปยัง Region ปลายทาง&lt;/p&gt;

&lt;p&gt;ส่วน Practices อื่นๆ ผมอยากแนะนำให้ลองอ่าน series &lt;a href="https://aws.amazon.com/blogs/architecture/tag/creating-a-multi-region-application-with-aws-services-series/" rel="noopener noreferrer"&gt;Creating a Multi-Region Application with AWS Services series&lt;/a&gt; เพื่อเป็นแนวทาง&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttq0mndfx8wmon4l5ged.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttq0mndfx8wmon4l5ged.png" alt="AWS Services Multi-region pracetics diagram" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;หวังว่าบทความนี้จะช่วยให้ทุกคนเห็นภาพและเข้าใจแนวคิดการออกแบบระบบ Failover แบบ Multi-Region สำหรับ EKS ได้ชัดเจนขึ้นนะครับ ไม่ว่าจะวางแผนสำหรับโปรเจกต์ขนาดใหญ่ หรือเริ่มต้นยกระดับมาตรฐานของระบบที่ดูแลอยู่ แนวทางนี้สามารถนำไปประยุกต์ใช้ได้ในหลากหลายรูปแบบ และผมเชื่อว่าการออกแบบให้ระบบรองรับการ failover ได้ จะช่วยให้เราจัดการกับสถานการณ์ไม่คาดคิดได้ดีขึ้น&lt;/p&gt;

&lt;p&gt;สุดท้ายแล้ว การเลือกว่า​จะออกแบบระบบ failover ของเราให้ละเอียดหรือทำ Multi-Region สำหรับทุก service หรือไม่ อาจไม่มีสูตรสำเร็จตายตัว สิ่งสำคัญคือต้องประเมินทั้งต้นทุนที่ต้องลงทุนเพิ่มเติม (ไม่ว่าจะเป็นค่า infrastructure หรือค่าใช้จ่ายในการดูแล) เทียบกับเป้าหมาย RTO/RPO ที่องค์กรรับได้ รวมถึงผลกระทบต่อธุรกิจหากเกิดเหตุระบบล่มขึ้นมา ซึ่งบางทีเราอาจต้องเลือกแค่ service ที่ critical จริง ๆ หรือข้อมูลที่สำคัญเท่านั้นให้รองรับ Multi-Region ก็พอ ในขณะที่ service อื่น ๆ ที่ business impact ไม่มากอาจไม่ต้องลงทุนสูงขนาดนั้น และอย่าลืมเรื่องการวางแผน ทดลอง และทดสอบ Disaster Recovery (DR) ข้าม region อย่างสม่ำเสมอ เพื่อให้มั่นใจว่าระบบที่ออกแบบมานั้นสามารถใช้รับมือเหตุการณ์ฉุกเฉินได้จริง ไม่ใช่เพิ่งมาพบปัญหาในวันที่เกิดเหตุแล้ว&lt;/p&gt;

&lt;p&gt;ถ้าใครมีคำถามหรืออยากแลกเปลี่ยนประสบการณ์ในการทำ Multi-Region Failover บน EKS สามารถคอมเมนต์พูดคุยกันได้เลยครับ ยินดีแชร์และตอบทุกเคสเหมือนเดิม ขอให้ทุกคนมี Infrastructure ที่พร้อมกับทุกสถานการณ์ครับ&lt;/p&gt;

&lt;p&gt;Original Workshop: &lt;a href="https://aws.amazon.com/blogs/containers/implementing-granular-failover-in-multi-region-amazon-eks/" rel="noopener noreferrer"&gt;https://aws.amazon.com/blogs/containers/implementing-granular-failover-in-multi-region-amazon-eks/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>eks</category>
      <category>aws</category>
      <category>failover</category>
      <category>devops</category>
    </item>
    <item>
      <title>12 เครื่องมือ Debug Kubernetes เจ๋งๆ ที่ควรต้องมีติดมือไว้</title>
      <dc:creator>Mongkol Thongkraikaew</dc:creator>
      <pubDate>Sun, 30 Mar 2025 17:56:51 +0000</pubDate>
      <link>https://dev.to/mongkol_tho/12-ekhruuengmuue-debug-kubernetes-ecchng-thiikhwrtngmiitidmuueaiw-1pla</link>
      <guid>https://dev.to/mongkol_tho/12-ekhruuengmuue-debug-kubernetes-ecchng-thiikhwrtngmiitidmuueaiw-1pla</guid>
      <description>&lt;p&gt;การ Debug Kubernetes อาจเป็นงานยากสำหรับใครหลายๆคน อาจใช้เวลานานในการจะหาสาเหตุของบางปัญหา แต่ถ้าเรามีเครื่องมือดี ๆ อยู่ในมือ มันก็จะช่วยให้เราทำงานกับ Kubernetes ได้ง่ายขึ้น&amp;nbsp;วันนี้ผมจะมาแชร์เครื่องมือที่นิยมที่จะมาช่วยทั้งการแก้ปัญหา, ตรวจสอบประสิทธิภาพ และตรวจจับข้อบกพร่องต่าง ๆ ของ Kubernetes มาลองดูกันครับ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. kubectl debug&lt;/strong&gt;&lt;br&gt;
    CLI ที่ช่วยให้เราสามารถสร้าง ephemeral container เข้าไปยัง Pod ที่กำลังทำงานอยู่ หรือสร้าง Pod จำลองที่ต้องการโดยเปลี่ยน attribute บางอย่างเช่น entrypoint, image version&lt;br&gt;
    ยกตัวอย่างสถานการณ์ที่เราอยากนำเครื่องมือ network troubleshooting เช่น ping, traceroute, nc, tcpdump ไปช่วย investigate ปัญหา network ของ Pod application กับปลายทาง ก็สามารถรันคำสั่ง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl debug app-Pod -it —image=nicolaka/netshoot&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/kubectl/generated/kubectl_debug" rel="noopener noreferrer"&gt;Document&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. kubectl top&lt;/strong&gt;&lt;br&gt;
   CLI สำหรับดูการใช้งาน resource (CPU/Memory) ของแต่ละ Pod หรือแต่ละ Node (ต้องมี Metrics Server ทำงานอยู่บน cluster ที่เราต้องการตรวจสอบด้วย)&lt;br&gt;
    ตัวอย่าง:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl top node&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl top pod&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/kubectl/generated/kubectl_top" rel="noopener noreferrer"&gt;Document&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Ktop&lt;/strong&gt;&lt;br&gt;
   Kubectl plugin สำหรับดูการใช้งาน resource เช่นเดียวกับ&amp;nbsp;kubectl top&amp;nbsp;แต่จะสรุปข้อมูล insight บางอย่างเพิ่มเติมและปรับวิธีการแสดงผลให้ดูง่ายขึ้น&lt;/p&gt;

&lt;p&gt;ตัวอย่าง:&lt;br&gt;
    &lt;code&gt;kubectl ktop --namespace cloudation101&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vladimirvivien/ktop" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Kube-capacity&lt;/strong&gt;&lt;br&gt;
   Kubectl plugin ที่รวมผลลัพท์ระหว่าง&amp;nbsp;kubectl top&amp;nbsp;และ&amp;nbsp;kubectl describe&amp;nbsp;เพื่อให้เราเห็น request, limit รวมถึง utilization ของ resource ต่างๆ บน Kubernetes cluster ผ่านแสดงผลในหน้าเดียว&lt;/p&gt;

&lt;p&gt;ตัวอย่าง: &lt;br&gt;
    &lt;code&gt;kubectl resource-capacity --util&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robscott/kube-capacity" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Netshoot&lt;/strong&gt;&lt;br&gt;
   Docker image และ Kubectl plugin สำหรับ troubleshoot ปัญหาที่เกี่ยวกับ container networking เช่น latency, routing, DNS resolving, firewall, ARPs&lt;/p&gt;

&lt;p&gt;ยกตัวอย่างสถานการณ์ที่ใช้บ่อยๆ: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;การดู latency หรือทดสอบ networking performance ระหว่าง container/host ( iperf )&lt;/li&gt;
&lt;li&gt;การ analysis network packet ( tcpdump )&lt;/li&gt;
&lt;li&gt;การ scanning port (nmap)&lt;/li&gt;
&lt;li&gt;monitor container metric (CPU, memory, network, I/O) แบบ real-time (ctop)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolaka/netshoot" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Kubetab&lt;/strong&gt;&lt;br&gt;
&amp;nbsp;  Kubectl plugin สำหรับสร้าง proxy ที่ Kubernetes service เพื่อ intercept หรือ tab request ที่จะถูก forward ไปยัง Pod เหมือนเวลาเราใช้ BurpSuite หรือ Zap ในการ tab request ระหว่าง browser และ server &lt;br&gt;
   หลักการทำงานคือจะทำการรัน proxy container (เริ่มต้นใช้ MITMProxy)ในรูปแบบของ sidecar และคอย intercept request ก่อนส่งต่อไปยัง application container&lt;/p&gt;

&lt;p&gt;ยกตัวอย่างสถานการณ์ที่ใช้บ่อยๆ: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security testing : capture และ modify HTTP request ก่อนที่จะลองส่งไปยัง Pod &lt;/li&gt;
&lt;li&gt;Developer debugging : ใช้สำหรับตรวจสอบดู connection request ที่มีปัญหาในระหว่างการ request ไปยัง service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง:&lt;br&gt;
   &lt;code&gt;kubectl tap on app-service -p443 --https --browser&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://soluble-ai.github.io/kubetap/" rel="noopener noreferrer"&gt;Document&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Kubeshark&lt;/strong&gt;&lt;br&gt;
    CLI สำหรับ capture real-time traffic ทั้ง API Call และข้อมูลที่รับส่งกันใน Kubernetes cluster (เหมือน TCPDump หรือ Wireshark สำหรับ Kubernetes) จุดเด่นคือ มี UI Console ให้กดดูได้อย่างสะดวก&lt;/p&gt;

&lt;p&gt;ตัวอย่าง:&lt;br&gt;
   &lt;code&gt;kubeshark tap --set headless=true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kubeshark/kubeshark" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Kubectl-trace&lt;/strong&gt;&lt;br&gt;
   Kubectl plugin ที่ทำให้เราส่ง bpftrace script เข้าไปรันบน node เพื่อ probe ข้อมูลจาก Linux kernel โดยตรงทั้ง Userspace (uprobe) และ kernel space (kprobe) ไม่จำเป็นต้องติดตั้งอะไรเพิ่มเติม โดยจะ run Pod "trace-runner" บน node ที่ต้องการ และรัน bpftrace เพื่อ compile script เป็น eBPF byte-code จากนั้นติดตั้งลงไปใน Linux kernel เพื่อ probe ข้อมูลตามที่เราต้องการ&lt;/p&gt;

&lt;p&gt;ยกตัวอย่าง use case: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trace ปัญหา OOM killed&lt;/li&gt;
&lt;li&gt;ดูการทำงานของ CPU Scheduler เพื่อตรวจสอบการ throttle CPU&lt;/li&gt;
&lt;li&gt;ตรวจสอบหาการ deadlocks ของ running process&lt;/li&gt;
&lt;li&gt;ตรวจสอบหาทำงานของ disk ว่าเกิดจากไฟล์ไหน process ใดที่ช้า&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/iovisor/kubectl-trace" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Inspektor-gadget&lt;/strong&gt; &lt;br&gt;
   Kubectl plugin  สำหรับ probe ข้อมูลต่างๆ Linux kernel ด้วยความสามารถของ eBPF เช่นเดียวกับ “Kubectl-trace” แต่ที่แตกต่างจาก Kubectl-trace คือ Inspektor-gadget จะ pack bpf script ต่างๆมาให้แล้ว ไม่จำเป็นต้องมาเข้าใจ มาเขียน script ทำให้สามารถเรียกใช้งานแบบง่ายๆผ่าน plugin ได้เลย&lt;/p&gt;

&lt;p&gt;ตัวอย่าง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl gadget run trace_exec:latest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl gadget run trace_open:latest -n default -c myapp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://inspektor-gadget.io/" rel="noopener noreferrer"&gt;Document&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. kubectl tree&lt;/strong&gt;&lt;br&gt;
    Kubectl plugin สำหรับแสดง dependency หรือความสัมพันธ์ระหว่าง resource ต่างๆ เช่น ตรวจสอบว่าภายใต้ deployment มี replicaset และ Pod ใดบ้าง รวมถึงสถานะของแต่ละ Pod ภายใต้ deployment นั้นๆด้วย&lt;/p&gt;

&lt;p&gt;ตัวอย่าง:&lt;br&gt;
   &lt;code&gt;kubectl tree deployment nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ahmetb/kubectl-tree" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. kubectl spy&lt;/strong&gt;&lt;br&gt;
    CLI สำหรับดูการเปลี่ยนแปลงของ resource ต่างๆบน Kubernetes แบบ real-time&lt;/p&gt;

&lt;p&gt;ยกตัวอย่างสถานการณ์ที่ใช้บ่อยๆ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; ตรวจสอบสถานะการ rollout deployment &lt;/li&gt;
&lt;li&gt; ตรวจสอบการเปลี่ยนแปลง Pod status&lt;/li&gt;
&lt;li&gt; ตรวจสอบการเปลี่ยนแปลง IP Endpoint ของ service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/pulumi/kubespy" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. K8sGPT&lt;/strong&gt;&lt;br&gt;
    CLI สำหรับสแกนข้อมูลและวิเคราะห์ปัญหาต่างๆบน Kubernetes cluster ร่วมกับ AI Model พร้อมแนะนำวิธีการแก้ไขแต่ละปัญหา โดยเริ่มต้นใช้ “OpenAI” สำหรับการวิเคราะห์ข้อมูล แต่เราสามารถเปลี่ยนเป็น model อื่นๆได้ เช่น ollama , bedrock, Gemini, Azure OpenAI หรือจะเป็น local model ของเราเองก็ได้เช่นกัน&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/k8sgpt-ai/k8sgpt" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;สุดท้ายแล้วเครื่องมือเหล่านี้เป็นแค่ตัวช่วยให้เราจัดการ Kubernetes ได้สะดวกมากขึ้นนะครับ ซึ่งสิ่งสำคัญที่สุดคือเราต้องเข้าใจการทำงานของ Kubernetes ก่อน แล้วเลือกใช้เครื่องมือให้เหมาะกับสถานการณ์ ถึงจะถือว่าเป็นการจัดการ Kubernetes ได้อย่างมีประสิทธิภาพ&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>kubernetes</category>
      <category>awscommunity</category>
      <category>awscommunitybuilder</category>
      <category>tooling</category>
    </item>
    <item>
      <title>จัดการ Kubernetes Resources ด้วย kro (Kube Resource Orchestrator)</title>
      <dc:creator>Mongkol Thongkraikaew</dc:creator>
      <pubDate>Sat, 16 Nov 2024 16:48:11 +0000</pubDate>
      <link>https://dev.to/mongkol_tho/cchadkaar-kubernetes-resources-dwy-kro-kube-resource-orchestrator-1g6h</link>
      <guid>https://dev.to/mongkol_tho/cchadkaar-kubernetes-resources-dwy-kro-kube-resource-orchestrator-1g6h</guid>
      <description>&lt;p&gt;&lt;strong&gt;kro (Kube Resource Orchestrator)&lt;/strong&gt; เป็น​ Open source จาก awslabs ที่มาช่วยให้การจัดการ Kubernetes Resources ทำได้สะดวกมากขึ้น&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡อธิบายให้เข้าใจง่ายๆเลยนะครับ :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;เมื่อเราจะ Provision หรือรัน Application ใดๆ ใน Kubernetes แน่นอนว่าเราจำเป็นต้องสร้าง Resource ต่างๆ เช่น Deployment, ServiceAccount, Service, Ingress, PV, PVC ใช่ไหมครับ ซึ่ง Resource เหล่านี้อาจจะต้องสร้างซ้ำๆ ในทุก Application ที่รันบนคลัสเตอร์ และสำหรับมือใหม่อาจจะมีความสับสนว่าเราควรสร้าง Resource อะไรก่อนดี ความยุ่งยากนี้แหละครับที่ kro จะเข้ามาช่วยเรา&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ResourceGroup (RG) เป็น key ของ kro ครับ จริงๆแล้วมันคือ  Custom Resource Definitions (CRDs) สำหรับกำหนดกลุ่มของ Resource ที่เราต้องการ เช่น หากเราต้องการให้ Application ที่จะรันบนคลัสเตอร์มี Deployment, ServiceAccount, Service และ Ingress รูปแบบไหน เราก็สามารถกำหนดลงไปใน RG ได้เลย&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;หลังจากที่เราสร้าง RG เสร็จแล้ว เราจะได้ API และ Kind API ใหม่ของเราเอง ในตัวอย่างนี้เราจะได้ Kind ที่ชื่อว่า “ApplicationStack”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;สำหรับการใช้งานนั้น End User หรือ Developer (Dev Team A, Team B) ก็เพียงแค่เรียกใช้งาน “ApplicationStack” ที่ได้ถูกกำหนดไว้แล้ว โดยไม่จำเป็นต้องรู้รายละเอียดทั้งหมดของ Kubernetes Resources หลังจาก Developer ได้สร้าง ApplicationStack ของตัวเอง, kro ก็จะทำการสร้าง Deployment, ServiceAccount, Service และ Ingress ให้ตามที่ได้กำหนดไว้ใน RG&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqhyy0cwvgjxuafyov41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqhyy0cwvgjxuafyov41.png" alt="Image description" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡ฟีเจอร์และประโยชน์ของ kro:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ลดความซับซ้อนในการจัดการ Kubernetes Resources&lt;/li&gt;
&lt;li&gt;สนับสนุนการทำงานตาม Platform Engineering Practice, ทำให้ทีม Platform สามารถควบคุม standard, compliant, security best practices ได้ง่ายขึ้น&lt;/li&gt;
&lt;li&gt;สามารถตรวจสอบสถานะของ Resources ทั้งหมดได้ผ่าน ResourceGroup ได้&lt;/li&gt;
&lt;li&gt;รองรับ Resources ที่เป็น Native ของ Kubernetes และ Custom Resource Definitions (CRDs) ที่ติดตั้งอยู่บนคลัสเตอร์&lt;/li&gt;
&lt;li&gt;และอื่นๆ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;จากการทดสอบที่ผมได้ลองเล่นดู เราสามารถนำ kro ไปต่อยอดได้หลายอย่างครับ เช่น:&lt;br&gt;
&lt;strong&gt;Ex.1:&lt;/strong&gt; ทำให้การทำงานของ Platform Engineering ง่ายขึ้น โดยที่หน้าที่ของทีม Platform คือการกำหนดมาตรฐานของ ResourceGroup ออกมา และให้ผู้ใช้สามารถ Self-Service ในการ Provision สิ่งที่ต้องการได้ด้วยตัวเอง นอกจากนี้ทีม Platform อาจจะเสริมด้วยการ control permission โดยจะอนุญาตให้ user interact กับ ResourceGroup ได้เท่านั้น จะไม่อนุญาตให้ user สร้าง Deployment หรือ Ingress ได้ตรงๆ เป็นต้น&lt;br&gt;
🔗&lt;a href="https://kro.run/examples/web-app-ingress" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ex.2:&lt;/strong&gt; ช่วยในการ Provision Kubernetes Resources พร้อมกับ Cloud Resources ได้ง่ายขึ้น ในตัวอย่างนี้ Pod หรือ Application จำเป็นต้องใช้งาน RDS และต้องนำ IP ของ RDS ไปใช้งานใน Application ด้วย เราสามารถทำสิ่งเหล่านี้ได้เพียงไฟล์ YAML ไฟล์เดียว&lt;br&gt;&lt;br&gt;
🔗&lt;a href="https://kro.run/examples/pod-rds-dbinstance" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ex.3:&lt;/strong&gt; ทีม SRE อาจสร้าง ResourceGroup สำหรับ Observability Tools เช่น Logging Stack, Monitoring Stack, และ Tracing Stack หากต้องการสร้าง Stack ใหม่ ก็ไม่จำเป็นต้องประกอบร่าง Kubernetes Resources ใหม่ทั้งหมด&lt;/p&gt;

&lt;p&gt;Ps. This project is in active development and not yet intended for production use&lt;br&gt;
&lt;a href="https://kro.run/docs/overview" rel="noopener noreferrer"&gt;Official Doc&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/awslabs/kro" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
