15. เตรียมเครื่องมือ (Lab Setup)
หน้า 15📋 สิ่งที่ต้องเตรียม
my-ai-devops บน Desktop แล้วเปิดด้วย VS Code
16. สร้าง Application
หน้า 16📦สร้าง GitHub Repository
- เข้าไปที่ https://github.com
- กดปุ่ม New Repository
- ตั้งชื่อ Repository เช่น devops-fastapi
- เลือก Public
- ❌ ไม่ต้องติ๊ก README, .gitignore, License
- กด Create repository
⬇️Download code files
⚙️Run code on Localhost
pip install fastapi uvicorn
python app.py
17. Build & Run Local
หน้า 171️⃣ สร้าง Dockerfile
FROM python:3.9-slim WORKDIR /app COPY . . RUN pip install -r requirements.txt CMD ["python", "app.py"]
2️⃣ Build Docker Image
docker build -t my-app .
3️⃣ Run Container
docker run -d -p 8000:8000 my-app
✅ เข้า http://localhost:8000 ดูผลว่า
18. Push Image ไปยัง Registry
หน้า 18ในการทำ DevOps เราต้องเก็บ Image ไว้ที่ส่วนกลางเพื่อให้ระบบอื่น (เช่น Cloud หรือ CI/CD) ดึงไปใช้งานได้
เหมาะสำหรับการแชร์ Image แบบสาธารณะ หรือโปรเจกต์ทั่วไป
Login ไปที่ Docker Hub
docker login
Tag Image ให้ตรงกับ Username
docker tag my-app username/my-app:v1
Push ขึ้น Docker Hub
docker push username/my-app:v1
19. ติดตั้ง Terraform (Installation)
หน้า 19ต้องติดตั้ง Terraform ลงในเครื่องก่อนจึงจะสั่งงาน AWS ได้
เปิด PowerShell แบบ Administrator แล้วรัน:
- ไปที่ Terraform Downloads
- โหลดเวอร์ชัน Windows (AMD64)
- แตกไฟล์
terraform.exeไปไว้ที่C:\Windows\System32
✅ ตรวจสอบว่าติดตั้งสำเร็จหรือไม่
terraform -version
ถ้าขึ้นเลขเวอร์ชัน (เช่น v1.6.x) แปลว่าพร้อมลุย!
เปิด Terminal แล้วรัน:
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
✅ ตรวจสอบว่าติดตั้งสำเร็จหรือไม่
terraform -version
ถ้าขึ้นเลขเวอร์ชัน (เช่น v1.6.x) แปลว่าพร้อมลุย!
20. Terraform Config & Auth
หน้า 20📂 1. provider.tf (กำหนดผู้ให้บริการ)
บอก Terraform ว่าเราจะใช้ Cloud เจ้าไหน (ในที่นี้คือ aws) และจะ Login เข้าไปจัดการทรัพยากรด้วย User ไหน (ผ่าน Access Key/Secret Key ที่รับค่ามาจากตัวแปร)
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
access_key = var.aws_access_key
secret_key = var.aws_secret_key
}
# Data Source: ดึงข้อมูล Availability Zones ที่ใช้ได้จริงมาเก็บไว้
data "aws_availability_zones" "available" {
state = "available"
}
📝 2. variables.tf (ประกาศตัวแปร)
เหมือนสมุดจดชื่อตัวแปรและประเภทของข้อมูลที่ต้องใช้
- sensitive = true: บอก Terraform ว่าห้ามโชว์ค่านี้ใน
Log (เช่น รหัสผ่าน)
- default: ค่าเริ่มต้นถ้าเราไม่ได้ระบุค่าใหม่
variable "aws_access_key" {
description = "AWS Access Key ID"
type = string
sensitive = true
}
variable "aws_secret_key" {
description = "AWS Secret Access Key"
type = string
sensitive = true
}
variable "aws_region" {
description = "AWS region"
type = string
default = "ap-southeast-1"
}
variable "project_name" {
description = "Project Name"
type = string
default = "bio-vanta"
}
variable "vpc_cidr" { default = "10.0.0.0/16" }
variable "cluster_version" { default = "1.29" }
variable "node_instance_type" { default = "t3.small" }
variable "node_desired_count" { default = 1 }
variable "node_min_count" { default = 1 }
variable "node_max_count" { default = 1 }
🔑 3. terraform.tfvars (ไฟล์ความลับ)
สำคัญมาก! นี่คือไฟล์ที่เราจะใส่ Key จริงๆ ลงไป
ห้าม Push ไฟล์นี้ขึ้น Git เด็ดขาด (ควรเพิ่มใน .gitignore)
ถ้าไม่มีไฟล์นี้ Terraform จะถามหาค่าตัวแปรตอนรัน
# ใส่ Access Key ของคุณที่นี่ aws_access_key = "" aws_secret_key = " " aws_region = "ap-southeast-1" project_name = "bio-vanta" vpc_cidr = "10.0.0.0/16" cluster_version = "1.33" node_instance_type = "t3.medium" node_desired_count = 1 node_min_count = 1 node_max_count = 1
21. Networking (VPC Setup)
หน้า 21🌐 vpc.tf (โครงสร้างเครือข่าย)
เราใช้ Module มาตรฐาน ของ AWS เพื่อสร้าง VPC (Virtual Private Cloud)
แบบครบวงจร
- cidr: ช่วง IP Address ทั้งหมดของระบบ (10.0.x.x)
- private_subnets: สำหรับวาง EKS Nodes (ปลอดภัย
เข้าถึงจากเน็ตโดยตรงไม่ได้)
- public_subnets: สำหรับวาง Load Balancer
(เพื่อให้คนภายนอกเข้าถึง App ได้)
- Tags: สำคัญมาก! EKS ใช้ Tags เหล่านี้เพื่อรู้ว่าจะวาง Load
Balancer ไว้ที่ไหน
# ============================================
# VPC (using official AWS module)
# ============================================
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "${var.project_name}-vpc"
cidr = var.vpc_cidr
# ใช้ 3 Availability Zones (Data Center) เพื่อความเสถียร
azs = slice(data.aws_availability_zones.available.names, 0, 3)
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true # ให้ Private Subnet ออกเน็ตได้ (โหลด Docker Image)
single_nat_gateway = true # ประหยัดงบ (ใช้ตัวเดียวแชร์กัน)
enable_dns_hostnames = true
enable_dns_support = true
# Tags ที่จำเป็นสำหรับ EKS (บอกว่า Subnet นี้ใช้ทำ Load Balancer ได้)
public_subnet_tags = {
"kubernetes.io/role/elb" = 1
"kubernetes.io/cluster/${var.project_name}-eks" = "owned"
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = 1
"kubernetes.io/cluster/${var.project_name}-eks" = "owned"
}
tags = {
Project = var.project_name
Environment = "production"
ManagedBy = "terraform"
}
}
22. Compute & Storage (EKS & ECR)
หน้า 22📦 1. ecr.tf (ที่เก็บ Image)
สร้าง Repository ส่วนตัวบน AWS เพื่อเก็บ Docker Image ของเรา
- scan_on_push:
สแกนหาช่องโหว่ความปลอดภัยทุกครั้งที่อัปโหลด
- lifecycle_policy: กฎอัตโนมัติ ลบ Image เก่าทิ้ง
(เก็บแค่ 10 อันล่าสุด) เพื่อไม่ให้เปลืองพื้นที่และเงิน
resource "aws_ecr_repository" "app" {
name = "${var.project_name}-web"
image_tag_mutability = "MUTABLE"
force_delete = true
image_scanning_configuration {
scan_on_push = true
}
tags = {
Project = var.project_name
Environment = "production"
ManagedBy = "terraform"
}
}
# ECR Lifecycle Policy – keep only last 10 images
resource "aws_ecr_lifecycle_policy" "app" {
repository = aws_ecr_repository.app.name
policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Keep last 10 images"
selection = {
tagStatus = "any"
countType = "imageCountMoreThan"
countNumber = 10
}
action = {
type = "expire"
}
}
]
})
}
☸️ 2. eks.tf (Kubernetes Cluster)
สร้าง EKS Cluster พร้อม Worker Nodes
- vpc_id / subnet_ids: บอก EKS ว่าให้ไปอยู่ใน VPC
ที่เราสร้างในหน้า 21
- eks_managed_node_groups: สร้างกลุ่มเครื่อง Server
(EC2) มาเป็นลูกน้อง (Nodes) โดย AWS ช่วยดูแลการอัปเดตให้
- public_access = true: เพื่อให้เราใช้คำสั่ง kubectl
จากเครื่องตัวเองได้
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "${var.project_name}-eks"
cluster_version = var.cluster_version
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
# Allow public access to the API server
cluster_endpoint_public_access = true
# Disable internal KMS/Logging to save cost
create_kms_key = false
cluster_encryption_config = {}
create_cloudwatch_log_group = false
# EKS Managed Node Group (เครื่อง Worker)
eks_managed_node_groups = {
main = {
name = "${var.project_name}-node-group"
ami_type = "AL2023_x86_64_STANDARD"
instance_types = [var.node_instance_type]
min_size = var.node_min_count
max_size = var.node_max_count
desired_size = var.node_desired_count
labels = {
role = "general"
}
tags = {
Project = var.project_name
}
}
}
# Cluster access for the creator
enable_cluster_creator_admin_permissions = true
tags = {
Project = var.project_name
Environment = "production"
ManagedBy = "terraform"
}
}
23. Outputs & Run (สรุปผลและสั่งรัน)
หน้า 23📤 outputs.tf (ผลลัพธ์)
เมื่อ Terraform สร้างเสร็จ มันจะ "ปริ้นท์" ข้อมูลสำคัญออกมา
- ecr_repository_url: URL สำหรับ Push Docker Image
- configure_kubectl: คำสั่งสำหรับเชื่อมต่อเครื่องเรากับ
EKS Cluster
output "vpc_id" {
description = "The ID of the VPC"
value = module.vpc.vpc_id
}
output "eks_cluster_name" {
description = "EKS Cluster name"
value = module.eks.cluster_name
}
output "eks_cluster_endpoint" {
description = "EKS Cluster API server endpoint"
value = module.eks.cluster_endpoint
}
output "ecr_repository_url" {
description = "ECR Repository URL"
value = aws_ecr_repository.app.repository_url
}
output "configure_kubectl" {
description = "Command to configure kubectl"
value = "aws eks update-kubeconfig --region ${var.aws_region} --name ${module.eks.cluster_name}"
}
🚀 สั่งรัน Terraform (Deploy)
1. เตรียมระบบ & โหลด Modules
terraform init
2. ตรวจสอบแผนการสร้าง (Dry Run)
terraform plan
3. สร้างจริง (ใช้เวลา 10-15 นาที)
terraform apply --auto-approve
configure_kubectl ใน
Terminal ของคุณเพื่อเชื่อมต่อกับ Cluster
24. ตั้งค่า GitHub Secrets (กุญแจลับ)
หน้า 24ทำไมต้องใช้ Secrets?
เราห้ามเก็บรหัสผ่านหรือ Key ไว้ในโค้ด (Hardcode) เด็ดขาด!
GitHub Secrets ช่วยให้เราส่งค่าความลับเหล่านี้ไปให้ CI/CD Pipeline ใช้งานได้อย่างปลอดภัย
ไปที่ Repository ของคุณบน GitHub แล้วทำตามนี้:
🐳 Docker Hub Config
ex: devops_student
******
ex: devops_student/my-ai-app
☁️ AWS EKS Config
ex: bio-vanta-eks-cluster
ap-southeast-1
ex: AKIAIOSFODNN7EXAMPLE
ex: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
✅ เมื่อเพิ่มครบทั้ง 6 ตัวแล้ว เราก็พร้อมที่จะสร้าง Pipeline ในหน้าถัดไป!
25. สร้าง CI/CD Pipeline
หน้า 25สร้างไฟล์ .github/workflows/deploy.yml:
# ============================================
# Bio Vanta – CI/CD Pipeline
# Build → Push to ECR → Deploy to EKS
# ============================================
name: CI/CD Pipeline - Build & Deploy to EKS
on:
push:
branches: [main]
workflow_dispatch:
env:
AWS_REGION: ${{ secrets.AWS_REGION }}
ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }}
EKS_CLUSTER_NAME: ${{ secrets.EKS_CLUSTER_NAME }}
NAMESPACE: bio-vanta
jobs:
# ===========================================
# Job 1: Build and Push Docker Image to ECR
# ===========================================
build-and-push:
name: 🏗️ Build & Push to ECR
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.image_tag }}
image_uri: ${{ steps.meta.outputs.image_uri }}
steps:
- name: 📥 Checkout code
uses: actions/checkout@v4
- name: 🔐 Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: 🔑 Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: 🏷️ Generate image metadata
id: meta
run: |
IMAGE_TAG="${{ github.sha }}"
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
IMAGE_URI="${ECR_REGISTRY}/${{ env.ECR_REPOSITORY }}:${IMAGE_TAG}"
echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
echo "image_uri=${IMAGE_URI}" >> $GITHUB_OUTPUT
echo "📦 Image URI: ${IMAGE_URI}"
- name: 🐳 Build Docker image
run: |
docker build -t ${{ steps.meta.outputs.image_uri }} .
docker tag ${{ steps.meta.outputs.image_uri }} ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
- name: 📤 Push Docker image to ECR
run: |
docker push ${{ steps.meta.outputs.image_uri }}
docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
echo "✅ Image pushed successfully!"
# ===========================================
# Job 2: Deploy to EKS
# ===========================================
deploy:
name: 🚀 Deploy to EKS
runs-on: ubuntu-latest
needs: build-and-push
steps:
- name: 📥 Checkout code
uses: actions/checkout@v4
- name: 🔐 Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: 🏷️ Generate image metadata
id: meta
run: |
IMAGE_TAG="${{ github.sha }}"
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
IMAGE_URI="${ECR_REGISTRY}/${{ env.ECR_REPOSITORY }}:${IMAGE_TAG}"
echo "image_uri=${IMAGE_URI}" >> $GITHUB_OUTPUT
echo "📦 Image URI: ${IMAGE_URI}"
- name: 🔧 Configure kubectl
run: |
aws eks update-kubeconfig --region ${{ env.AWS_REGION }} --name ${{ env.EKS_CLUSTER_NAME }}
- name: 📦 Apply Kubernetes manifests
run: |
echo "🔄 Applying K8s manifests..."
echo "🐳 Injecting image: ${{ steps.meta.outputs.image_uri }}"
sed -i "s|IMAGE_PLACEHOLDER|${{ steps.meta.outputs.image_uri }}|g" k8s/deployment.yaml
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/hpa.yaml
- name: ⏳ Wait for rollout
run: |
echo "⏳ Waiting for deployment rollout..."
kubectl rollout status deployment/bio-vanta-web -n ${{ env.NAMESPACE }} --timeout=300s
echo "✅ Deployment rollout complete!"
- name: 📊 Show deployment status
run: |
echo "========================================"
echo "📊 Deployment Status"
echo "========================================"
kubectl get deployments -n ${{ env.NAMESPACE }}
echo ""
echo "📦 Pods:"
kubectl get pods -n ${{ env.NAMESPACE }}
echo ""
echo "🌐 Services:"
kubectl get svc -n ${{ env.NAMESPACE }}
echo ""
echo "📈 HPA:"
kubectl get hpa -n ${{ env.NAMESPACE }}
🚀 Lab 3 เสร็จสมบูรณ์!
ไปต่อที่ Module 4 เพื่อเรียนรู้วิธีเล่น K8s บนเครื่องตัวเอง