Trong bài blog này, chúng ta sẽ cùng tìm hiểu về việc triển khai một cụm AWS EKS sử dụng Terraform và tự động hóa việc triển khai bằng GitHub Actions. Mục tiêu là thiết lập một cụm EKS hoạt động đầy đủ, bao gồm các tiện ích bổ sung (add-ons) thiết yếu như CoreDNS, AWS ALB Ingress Controller, và AWS EBS add-on.
Tổng quan các bước
- Tạo một VPC với các Subnet Public và Private — Cụm EKS sẽ được triển khai trong VPC này.
- Triển khai EKS Cluster với các Add-on thiết yếu
- Tận dụng module Terraform AWS EKS, giúp đơn giản hóa việc tạo EKS cluster và tự động thiết lập OIDC provider.
- Cấu hình AWS ALB Ingress Controller, yêu cầu một IAM role với các chính sách cần thiết.
- Cài đặt AWS EBS add-on cho lưu trữ bền vững.
- Tự động hóa triển khai bằng GitHub Actions — Thiết lập các workflow CI/CD để tự động hóa việc triển khai Terraform.
Bước 1: Tạo một VPC với các Subnet Public và Private
Để đảm bảo một thiết lập an toàn và có khả năng mở rộng, chúng ta sẽ tạo một VPC với các subnet public và private. EKS control plane sẽ chạy trong các subnet private, trong khi các subnet public sẽ được sử dụng cho các bộ cân bằng tải (load balancers).
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "eks-vpc1"
cidr = "11.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["11.0.1.0/24", "11.0.2.0/24", "11.0.3.0/24"]
public_subnets = ["11.0.101.0/24", "11.0.102.0/24", "11.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
one_nat_gateway_per_az = false
public_subnet_tags = {
"kubernetes.io/role/elb" = 1
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = 1
}
tags = {
Terraform = "true"
Environment = "dev"
}
}
Bước 2: Triển khai EKS Cluster với Add-ons
Chúng ta sẽ sử dụng module Terraform AWS EKS để tạo EKS cluster cùng với xác thực OIDC cho các IAM role.
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "eks-1"
cluster_version = "1.31"
bootstrap_self_managed_addons = true
cluster_upgrade_policy = {
support_type = "STANDARD"
}
cluster_addons = {
eks-pod-identity-agent = {}
kube-proxy = {}
vpc-cni = {}
}
# Optional
cluster_endpoint_public_access = true
# Optional: Adds the current caller identity as an administrator via cluster access entry
enable_cluster_creator_admin_permissions = true
#enable_irsa Determines whether to create an OpenID Connect Provider for EKS to enable IRSA
enable_irsa = true
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
control_plane_subnet_ids = module.vpc.private_subnets
tags = {
Environment = "dev"
Terraform = "true"
}
}
Bước 3: Cài đặt CoreDNS sau khi tạo Cluster
CoreDNS yêu cầu các node worker phải có mặt. Chúng ta sẽ cài đặt nó bằng Terraform sau khi tạo cluster và các nhóm node được quản lý.
//removing the plugin atthe time of cluster ceration because it need node to be created first
/*resource "aws_eks_addon" "example" {
depends_on = [ module.eks_managed_node_group ]
cluster_name = module.eks.cluster_name
addon_name = "coredns"
}
module "eks_managed_node_group" {
source = "terraform-aws-modules/eks/aws//modules/eks-managed-node-group"
cluster_service_cidr = module.eks.cluster_service_cidr
name = "eks-node"
cluster_name = module.eks.cluster_name
cluster_version = "1.31"
subnet_ids = module.vpc.private_subnets
# cluster_primary_security_group_id = module.eks.cluster_primary_security_group_id
#vpc_security_group_ids = [module.eks.node_security_group_id]
min_size = 1
max_size = 2
desired_size = 1
instance_types = ["t3.large"]
capacity_type = "SPOT"
labels = {
Environment = "test"
GithubRepo = "terraform-aws-eks"
GithubOrg = "terraform-aws-modules"
}
tags = {
Environment = "dev"
Terraform = "true"
}
}
Bước 4: Cấu hình quyền truy cập
Để cho phép người dùng khác truy cập cụm EKS, hãy làm theo các bước sau:
-
Tạo một IAM Group (eks-admin-group)
- Nhóm này sẽ chứa những người dùng cần quyền admin đối với EKS.
-
Tạo một IAM Role (k8s-admin-role)
- Cho phép người dùng trong eks-admin-group đảm nhận (assume) vai trò này cho các tác vụ admin EKS.
- Chính sách tin cậy (Trust policy) đảm bảo chỉ các thành viên của eks-admin-group mới có thể đảm nhận vai trò.
-
Tạo một IAM Policy (eks-assume-role-policy)
- Cấp quyền sts:AssumeRole cho k8s-admin-role.
- Được gắn vào eks-admin-group, cho phép người dùng của nhóm này đảm nhận vai trò.
-
Đăng ký IAM Role với EKS (aws_eks_access_entry)
- Liên kết k8s-admin-role với EKS cluster.
-
Gắn EKS Admin Policy (aws_eks_access_policy_association)
- Cấp cho k8s-admin-role quyền admin EKS đầy đủ
resource "aws_iam_group" "admin_group" {
name = "eks-admin-group"
}
resource "aws_iam_role" "admin_role" {
name = "eks-admin-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
"AWS": "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
},
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy_attachment" "admin_permissions" {
role = aws_iam_role.admin_role.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
# Create IAM Policy for AssumeRole
resource "aws_iam_policy" "eks_assume_role_policy" {
name = "eks-assume-role-policy"
description = "Allows users in the group to assume the eks-admins-role"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "sts:AssumeRole"
Resource = "arn:aws:iam::936379345511:role/${aws_iam_role.admin_role.name}"
}
]
})
}
# Attach Policy to IAM Group
resource "aws_iam_group_policy_attachment" "attach_assume_role_policy" {
group = aws_iam_group.admin_group.name
policy_arn = aws_iam_policy.eks_assume_role_policy.arn
}
resource "aws_eks_access_entry" "example" {
cluster_name = module.eks.cluster_name
principal_arn = aws_iam_role.admin_role.arn
type = "STANDARD"
}
resource "aws_eks_access_policy_association" "example" {
cluster_name = module.eks.cluster_name
policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
principal_arn = aws_iam_role.admin_role.arn
access_scope {
type = "cluster"
}
}
Bước 5: Cài đặt ALB Controller
1. Tạo IAM Role cho ALB Controller Chúng ta cần tạo một IAM role và gắn chính sách AWS cần thiết.
resource "aws_iam_role" "eks-alb-ingress-controller" {
name = "eks-alb-ingress-controller"
assume_role_policy = data.aws_iam_policy_document.alb_controller_assume_role_policy.json
}
resource "aws_iam_role_policy_attachment" "alb_controller_policy_attachment" {
role = aws_iam_role.eks-alb-ingress-controller.name
policy_arn = aws_iam_policy.alb_controller_policy.arn
}
# Define the IAM policy document for the AssumeRole policy
data "aws_iam_policy_document" "alb_controller_assume_role_policy" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]
effect = "Allow"
principals {
type = "Federated"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${module.eks.oidc_provider}"]
}
condition {
test = "StringEquals"
variable = "${module.eks.oidc_provider}:aud"
values = ["sts.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "${module.eks.oidc_provider}:sub"
values = ["system:serviceaccount:kube-system:aws-load-balancer-controller"]
}
}
}
2.2 Triển khai ALB Controller bằng Helm Bây giờ, cài đặt ALB controller bằng Helm.
# Define the Helm provider
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
token = data.aws_eks_cluster_auth.cluster.token
}
}
# Add the Helm chart repository for AWS Load Balancer Controller
# Install the AWS Load Balancer Controller via Helm
resource "helm_release" "aws_load_balancer_controller" {
depends_on = [module.eks_managed_node_group]
name = "aws-load-balancer-controller"
namespace = "kube-system"
chart = "aws-load-balancer-controller"
repository = "https://aws.github.io/eks-charts"
set {
name = "clusterName"
value = module.eks.cluster_name
}
set {
name = "region"
value = "us-east-1"
}
set {
name = "serviceAccount.create"
value = "true"
}
set {
name = "serviceAccount.name"
value = "aws-load-balancer-controller"
}
set {
name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
value = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${aws_iam_role.eks-alb-ingress-controller.name}"
}
}
Cấu hình lưu trữ
Cấu hình terraform dưới đây triển khai AWS EBS CSI Driver dưới dạng EKS add-on và cấu hình IAM role cần thiết để quản lý các volume EBS. Các thành phần chính:
- EKS Add-on (aws-ebs-csi-driver): Được cài đặt trên EKS cluster với một IAM role được chỉ định.
- IAM Role (eks-ebs): Được tạo với chính sách đảm nhận vai trò (assume role policy) để cho phép EBS CSI driver xác thực bằng OIDC.
- IAM Policy Attachment: Cấp cho vai trò các quyền cần thiết thông qua
AmazonEBSCSIDriverPolicy
. - OIDC Trust Policy: Đảm bảo rằng chỉ service account của EBS CSI driver (
ebs-csi-controller-sa
trong namespacekube-system
) mới có thể đảm nhận IAM role.
Thiết lập này cho phép tích hợp liền mạch Amazon EBS làm lưu trữ bền vững cho các khối lượng công việc Kubernetes trên EKS.
// This addon will also create a kubernetes service account with the necessary IAM role attached to managed EBS volumes
resource "aws_eks_addon" "ebs" {
depends_on = [ module.eks_managed_node_group ]
cluster_name = module.eks.cluster_name
addon_name = "aws-ebs-csi-driver"
service_account_role_arn = aws_iam_role.eks-ebs.arn
}
resource "aws_iam_role" "eks-ebs" {
name = "eks-ebs"
assume_role_policy = data.aws_iam_policy_document.ebs_controller_assume_role_policy.json
}
resource "aws_iam_role_policy_attachment" "ebs_controller_policy_attachment" {
role = aws_iam_role.eks-ebs.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
}
# Define the IAM policy document for the AssumeRole policy
data "aws_iam_policy_document" "ebs_controller_assume_role_policy" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]
effect = "Allow"
principals {
type = "Federated"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${module.eks.oidc_provider}"]
}
condition {
test = "StringEquals"
variable = "${module.eks.oidc_provider}:aud"
values = ["sts.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "${module.eks.oidc_provider}:sub"
values = ["system:serviceaccount:kube-system:ebs-csi-controller-sa"]
}
}
}
GitHub Workflow
Chúng ta sẽ thiết lập một GitHub Actions workflow để tự động hóa quá trình triển khai.
name: EKS Terraform Deployment
on:
# push:
#branches:
# - main
# paths:
# - 'terraform/eks_nodegroup/**'
pull_request:
branches:
- main
paths:
- 'terraform/eks_nodegroup/**'
workflow_dispatch:
inputs:
action:
description: "Specify the Terraform action: apply or destroy"
required: true
default: "apply"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: us-east-1
jobs:
terraform:
runs-on: ubuntu-latest
defaults:
run:
working-directory: terraform/eks_nodegroup
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Set up Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_wrapper: true
- name: Initialize Terraform
run: terraform init
- name: Validate Terraform
run: terraform validate
- name: Terraform Plan
run: terraform plan
- name: Execute Terraform Action
run: |
if [ "${{ github.event.inputs.action }}" == "destroy" ]; then
terraform destroy -auto-approve
else
terraform apply -auto-approve
fi
Vậy là chúng ta đã triển khai thành công một cụm AWS EKS bằng Terraform và tự động hóa việc triển khai bằng GitHub Actions. Cụm này hiện đã được cấu hình đầy đủ với CoreDNS, một nhóm node được quản lý và AWS ALB Ingress Controller, sẵn sàng cho việc triển khai khối lượng công việc.
Kết luận
Bằng cách làm theo hướng dẫn này, bạn có thể:
- Triển khai một cụm AWS EKS sử dụng Terraform.
- Thiết lập AWS ALB Ingress Controller để quản lý traffic ingress.
- Cài đặt AWS EBS add-on cho lưu trữ bền vững.
- Cấp quyền truy cập cho người dùng bổ sung vào cụm EKS.
- Tự động hóa việc triển khai bằng GitHub Actions cho một workflow CI/CD liền mạch.