Triển khai AWS EKS Cluster sử dụng Terraform và GitHub Actions

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

  1. 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.
  2. 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.
  3. 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:

  1. 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.
  2. 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ò.
  3. 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ò.
  4. Đăng ký IAM Role với EKS (aws_eks_access_entry)

    • Liên kết k8s-admin-role với EKS cluster.
  5. 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 namespace kube-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.
Article Thumbnail
Datadog Webinar: Modernize AWS Logs at Scale

Sự kiện đang hiện hành

Chia sẻ bài viết:
Theo dõi
Thông báo của
2 Góp ý
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Phản hồi nội tuyến
Xem tất cả bình luận