Danh sách bài viết trong series Terraform Associate (003)
- Bài 0: Giới Thiệu Series Và Tổng Quan Về Chứng Chỉ Terraform Associate (003)
- Bài 1: Terraform Là Gì? Tổng Quan Và Vai Trò Trong IaC
- Bài 2: Cài Đặt Terraform Trên Các Hệ Điều Hành
- Bài 3: Terraform Workflow: Init, Plan, Apply, Destroy
- Bải 4: Terraform CLI Nâng Cao: Lệnh Taint, Import, Refresh
- Bài 5: Quản Lý Provider Trong Terraform
- Bài 6: Quản Lý Resource Trong Terraform
- Bài 7: Sử Dụng Biến (Variables) Trong Terraform
- Bài 8: Sử Dụng Output Trong Terraform
- Bài 9: Hiểu Terraform State Quản Lý Trạng Thái Hạ Tầng
- Bài 10: Sử Dụng Remote State Với Backend Như S3 Trong Terraform
- Bài 11: Terraform Workspace Quản Lý Nhiều Môi Trường
- Bài 12: Terraform Module: Mô-đun Hóa Cấu Hình
- Bài 13: Terraform Data Sources Truy Vấn Thông Tin Hạ Tầng
- Bài 14: Quản Lý Vòng Đời Tài Nguyên Với Terraform
- Bài 15: Tự Động Hóa Và Tích Hợp CI/CD Với Terraform
- Bài 16: Xử Lý Lỗi Và Debug Trong Terraform
- Bài 17: Tối Ưu Hóa Hiệu Suất Với Terraform
- Bài 18: Bảo Mật Cấu Hình Terraform
- Bài 19: Triển Khai Hạ Tầng Đa Vùng Với Terraform
- Bài 20: Triển Khai Hạ Tầng Serverless Với Terraform
- Bài 21: Triển Khai Hạ Tầng Container Với Terraform (ECS, EKS)
- Bài 22: Triển Khai Hạ Tầng Multi-Cloud Với Terraform
- Bài 23: Tổng Kết Series Và Chuẩn Bị Cho Kỳ Thi Terraform Associate (003)
Hạ Tầng Container Là Gì?

Hạ tầng container là mô hình triển khai ứng dụng sử dụng các container (VD: Docker) để đóng gói mã và phụ thuộc, đảm bảo ứng dụng chạy nhất quán trên mọi môi trường. AWS cung cấp hai dịch vụ phổ biến để quản lý container: ECS (Elastic Container Service) cho việc quản lý container đơn giản và EKS (Elastic Kubernetes Service) cho các hệ thống phức tạp hơn với Kubernetes. Terraform giúp triển khai và quản lý các dịch vụ container này dưới dạng mã (Infrastructure as Code), đảm bảo tính tự động hóa và nhất quán.
Tại Sao Sử Dụng Terraform Cho Container?
- Tự động hóa triển khai: Tạo và quản lý ECS/EKS cluster, task, và node group bằng mã.
- Tính nhất quán: Đảm bảo cấu hình giống nhau giữa các môi trường (dev, prod).
- Tích hợp với hạ tầng khác: Dễ dàng kết hợp với VPC, IAM, và các dịch vụ AWS khác.
- Quản lý dễ dàng: Cập nhật hoặc xóa tài nguyên container chỉ với vài lệnh Terraform.
- Tích hợp CI/CD: Tự động triển khai container thông qua pipeline.
Triển Khai Container Với Terraform
Triển Khai ECS (Elastic Container Service)
- Các bước chính:
- Tạo ECS cluster.
- Định nghĩa task definition (mô tả container).
- Tạo service để chạy task trên ECS.
- Cấu hình VPC và IAM role.
Triển Khai EKS (Elastic Kubernetes Service)
- Các bước chính:
- Tạo EKS cluster.
- Tạo node group để chạy worker nodes.
- Cấu hình VPC, IAM role, và kubectl để quản lý cluster.
- Triển khai ứng dụng lên Kubernetes.
Ví Dụ Thực Tế: Triển Khai ECS Và EKS Với Terraform
Phần 1: Triển Khai ECS
-
Chuẩn bị:
- Đảm bảo bạn có một container image (VD:
nginx
) được đẩy lên Amazon ECR (Elastic Container Registry). - Giả sử image:
123456789012.dkr.ecr.us-east-1.amazonaws.com/my-nginx:latest
.
- Đảm bảo bạn có một container image (VD:
-
File
ecs.tf
:terraform { backend "s3" { bucket = "my-terraform-state" key = "state/ecs.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } } provider "aws" { region = "us-east-1" } # VPC và Subnets resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "ecs-vpc" } } resource "aws_subnet" "public" { count = 2 vpc_id = aws_vpc.main.id cidr_block = "10.0.${count.index}.0/24" availability_zone = element(["us-east-1a", "us-east-1b"], count.index) map_public_ip_on_launch = true tags = { Name = "public-subnet-${count.index}" } } resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.main.id tags = { Name = "ecs-igw" } } resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } tags = { Name = "public-route-table" } } resource "aws_route_table_association" "public" { count = 2 subnet_id = aws_subnet.public[count.index].id route_table_id = aws_route_table.public.id } # ECS Cluster resource "aws_ecs_cluster" "main" { name = "my-ecs-cluster" } # IAM Role cho ECS Task resource "aws_iam_role" "ecs_task_execution" { name = "ecs_task_execution_role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ecs-tasks.amazonaws.com" } } ] }) } resource "aws_iam_role_policy_attachment" "ecs_task_execution_policy" { role = aws_iam_role.ecs_task_execution.name policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" } # Task Definition resource "aws_ecs_task_definition" "nginx" { family = "nginx-task" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = "256" memory = "512" execution_role_arn = aws_iam_role.ecs_task_execution.arn container_definitions = jsonencode([ { name = "nginx" image = "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-nginx:latest" essential = true portMappings = [ { containerPort = 80 hostPort = 80 } ] } ]) } # ECS Service resource "aws_ecs_service" "nginx" { name = "nginx-service" cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.nginx.arn desired_count = 1 launch_type = "FARGATE" network_configuration { subnets = aws_subnet.public[*].id assign_public_ip = true } } output "ecs_cluster_name" { value = aws_ecs_cluster.main.name } output "ecs_service_name" { value = aws_ecs_service.nginx.name }
-
Quy trình ECS:
-
Khởi tạo backend:
terraform init
Output:
Initializing the backend... Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes. Terraform has been successfully initialized!
-
Áp dụng cấu hình:
terraform apply -auto-approve
Output:
aws_vpc.main: Creating... aws_vpc.main: Creation complete after 3s [id=vpc-12345678] aws_subnet.public[0]: Creating... aws_subnet.public[1]: Creating... aws_subnet.public[0]: Creation complete after 2s [id=subnet-12345678] aws_subnet.public[1]: Creation complete after 2s [id=subnet-87654321] aws_internet_gateway.igw: Creating... aws_internet_gateway.igw: Creation complete after 1s [id=igw-12345678] aws_route_table.public: Creating... aws_route_table.public: Creation complete after 1s [id=rtb-12345678] aws_route_table_association.public[0]: Creating... aws_route_table_association.public[1]: Creating... aws_route_table_association.public[0]: Creation complete after 1s aws_route_table_association.public[1]: Creation complete after 1s aws_ecs_cluster.main: Creating... aws_ecs_cluster.main: Creation complete after 1s [id=my-ecs-cluster] aws_iam_role.ecs_task_execution: Creating... aws_iam_role.ecs_task_execution: Creation complete after 2s [id=ecs_task_execution_role] aws_iam_role_policy_attachment.ecs_task_execution_policy: Creating... aws_iam_role_policy_attachment.ecs_task_execution_policy: Creation complete after 1s aws_ecs_task_definition.nginx: Creating... aws_ecs_task_definition.nginx: Creation complete after 1s [id=nginx-task] aws_ecs_service.nginx: Creating... aws_ecs_service.nginx: Creation complete after 5s [id=nginx-service] Apply complete! Resources: 10 added, 0 changed, 0 destroyed. Outputs: ecs_cluster_name = "my-ecs-cluster" ecs_service_name = "nginx-service"
-
Phần 2: Triển Khai EKS
-
File
eks.tf
:terraform { backend "s3" { bucket = "my-terraform-state" key = "state/eks.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } } provider "aws" { region = "us-east-1" } # VPC và Subnets (tương tự như ECS, tái sử dụng VPC nếu cần) resource "aws_vpc" "eks_vpc" { cidr_block = "10.1.0.0/16" tags = { Name = "eks-vpc" } } resource "aws_subnet" "eks_public" { count = 2 vpc_id = aws_vpc.eks_vpc.id cidr_block = "10.1.${count.index}.0/24" availability_zone = element(["us-east-1a", "us-east-1b"], count.index) map_public_ip_on_launch = true tags = { "Name" = "eks-public-subnet-${count.index}" "kubernetes.io/cluster/my-eks-cluster" = "shared" } } resource "aws_internet_gateway" "eks_igw" { vpc_id = aws_vpc.eks_vpc.id tags = { Name = "eks-igw" } } resource "aws_route_table" "eks_public" { vpc_id = aws_vpc.eks_vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.eks_igw.id } tags = { Name = "eks-public-route-table" } } resource "aws_route_table_association" "eks_public" { count = 2 subnet_id = aws_subnet.eks_public[count.index].id route_table_id = aws_route_table.eks_public.id } # EKS Cluster resource "aws_eks_cluster" "main" { name = "my-eks-cluster" role_arn = aws_iam_role.eks_cluster.arn vpc_config { subnet_ids = aws_subnet.eks_public[*].id } depends_on = [ aws_iam_role_policy_attachment.eks_cluster_policy ] } # IAM Role cho EKS Cluster resource "aws_iam_role" "eks_cluster" { name = "eks_cluster_role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "eks.amazonaws.com" } } ] }) } resource "aws_iam_role_policy_attachment" "eks_cluster_policy" { role = aws_iam_role.eks_cluster.name policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" } # Node Group resource "aws_eks_node_group" "main" { cluster_name = aws_eks_cluster.main.name node_group_name = "my-node-group" node_role_arn = aws_iam_role.eks_node.arn subnet_ids = aws_subnet.eks_public[*].id scaling_config { desired_size = 2 max_size = 3 min_size = 1 } depends_on = [ aws_iam_role_policy_attachment.eks_node_policy ] } # IAM Role cho EKS Node Group resource "aws_iam_role" "eks_node" { name = "eks_node_role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } } ] }) } resource "aws_iam_role_policy_attachment" "eks_node_policy" { role = aws_iam_role.eks_node.name policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" } resource "aws_iam_role_policy_attachment" "eks_cni_policy" { role = aws_iam_role.eks_node.name policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" } resource "aws_iam_role_policy_attachment" "eks_registry_policy" { role = aws_iam_role.eks_node.name policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" } output "eks_cluster_name" { value = aws_eks_cluster.main.name } output "eks_cluster_endpoint" { value = aws_eks_cluster.main.endpoint }
-
Quy trình EKS:
-
Khởi tạo backend:
terraform init
Output:
Initializing the backend... Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes. Terraform has been successfully initialized!
-
Áp dụng cấu hình:
terraform apply -auto-approve
Output:
aws_vpc.eks_vpc: Creating... aws_vpc.eks_vpc: Creation complete after 3s [id=vpc-87654321] aws_subnet.eks_public[0]: Creating... aws_subnet.eks_public[1]: Creating... aws_subnet.eks_public[0]: Creation complete after 2s [id=subnet-abcdef12] aws_subnet.eks_public[1]: Creation complete after 2s [id=subnet-fedcba21] aws_internet_gateway.eks_igw: Creating... aws_internet_gateway.eks_igw: Creation complete after 1s [id=igw-87654321] aws_route_table.eks_public: Creating... aws_route_table.eks_public: Creation complete after 1s [id=rtb-87654321] aws_route_table_association.eks_public[0]: Creating... aws_route_table_association.eks_public[1]: Creating... aws_route_table_association.eks_public[0]: Creation complete after 1s aws_route_table_association.eks_public[1]: Creation complete after 1s aws_iam_role.eks_cluster: Creating... aws_iam_role.eks_cluster: Creation complete after 2s [id=eks_cluster_role] aws_iam_role_policy_attachment.eks_cluster_policy: Creating... aws_iam_role_policy_attachment.eks_cluster_policy: Creation complete after 1s aws_eks_cluster.main: Creating... aws_eks_cluster.main: Creation complete after 8m [id=my-eks-cluster] aws_iam_role.eks_node: Creating... aws_iam_role.eks_node: Creation complete after 2s [id=eks_node_role] aws_iam_role_policy_attachment.eks_node_policy: Creating... aws_iam_role_policy_attachment.eks_cni_policy: Creating... aws_iam_role_policy_attachment.eks_registry_policy: Creating... aws_iam_role_policy_attachment.eks_node_policy: Creation complete after 1s aws_iam_role_policy_attachment.eks_cni_policy: Creation complete after 1s aws_iam_role_policy_attachment.eks_registry_policy: Creation complete after 1s aws_eks_node_group.main: Creating... aws_eks_node_group.main: Creation complete after 5m [id=my-eks-cluster:my-node-group] Apply complete! Resources: 12 added, 0 changed, 0 destroyed. Outputs: eks_cluster_name = "my-eks-cluster" eks_cluster_endpoint = "https://my-eks-cluster.yl4.us-east-1.eks.amazonaws.com"
- Cấu hình
kubectl
để quản lý EKS:aws eks --region us-east-1 update-kubeconfig --name my-eks-cluster
Output:
Added new context arn:aws:eks:us-east-1:123456789012:cluster/my-eks-cluster to /Users/user/.kube/config
- Sau đó, bạn có thể triển khai ứng dụng lên EKS bằng
kubectl
.
- Sau đó, bạn có thể triển khai ứng dụng lên EKS bằng
-
Lưu Ý Quan Trọng Khi Triển Khai Container Với Terraform
- Quyền IAM: Đảm bảo các role cho ECS và EKS có quyền cần thiết (VD: truy cập ECR, CloudWatch).
- VPC cấu hình đúng: Subnet cần có internet access để ECS Fargate hoặc EKS node group hoạt động.
- Chi phí container: Theo dõi chi phí ECS Fargate hoặc EKS node group, đặc biệt với quy mô lớn.
- Tích hợp CI/CD: Dùng pipeline để tự động triển khai container image và cập nhật task definition.
- Debug container: Sử dụng CloudWatch Logs hoặc
kubectl logs
để kiểm tra lỗi nếu container không chạy.
Liên Hệ Với Chứng Chỉ Terraform Associate (003)
Kỳ thi Terraform Associate (003) không kiểm tra trực tiếp triển khai container, nhưng hiểu cách quản lý tài nguyên ECS/EKS sẽ giúp bạn áp dụng kiến thức thực tiễn vào mục tiêu 7 và 8. Bạn cần nắm:
- Khái niệm liên quan:
- Quản lý tài nguyên container (ECS task, EKS node group).
- Tích hợp tài nguyên với VPC và IAM role.
- Thực hành: Biết cách triển khai container sẽ giúp bạn xử lý tốt hơn trong các tình huống thực tế.
Kết Luận
Triển khai hạ tầng container với Terraform giúp quản lý ECS và EKS hiệu quả, đảm bảo tính tự động hóa và mở rộng. Sử dụng Terraform để tạo cluster, task definition, và node group sẽ giúp bạn xây dựng hệ thống container mạnh mẽ. Dù không phải trọng tâm của kỳ thi Terraform Associate (003), kỹ năng này rất hữu ích trong thực tế. Ở bài tiếp theo, chúng ta sẽ tìm hiểu cách sử dụng Terraform để triển khai hạ tầng đa đám mây (multi-cloud).