Provision AWS EKS Cluster by Terraform.

Pao Payungsak Klinchampa
Next-Hop Co., Ltd.
Published in
4 min readJul 5, 2020
Ref : https://aws.amazon.com/blogs/opensource/improvements-eks-worker-node-provisioning/

สวัสดีทุกๆท่านนะครับ ในบทความนี้เราจะมา Provision AWS EKS Cluster เพื่อใช้งานกัน

สำหรับ AWS EKS นั้น เป็น Managed Kubernetes ที่ให้บริการโดย AWS นั่นเองครับ ซึ่งมันก็สามารถเอามาทำงานร่วมกับ Load Balance , EFS , EBS , Auto Scale ได้ และยังมีเเบบ Fargate ซึ่งทำให้เราไม่ต้องสร้าง EC2 เพื่อ Run Workload

ส่วนเจ้า Terraform นั้นเป็นเครื่องมือที่ช่วยให้เราสามารถสร้าง Resource ต่างๆบน Cloud Provider ได้ ไม่เฉพาะ AWS นะครับ ค่ายอื่นก็ใช้ได้ด้วย อย่างเช่น Google Cloud โดยเราจะต้องเขียน Code เพื่อใช้ในการสั่งการครับ มันก็เลยเรียกว่า Infrastructure as a Code นั่นเอง

มาเริ่มกันเลยดีกว่าครับผม !!

  1. อันดับเเรกเราต้องมี Access Key + Secret Key ที่สร้างจาก AWS IAM ซะก่อน โดยต้องมี Policy ที่สามารถเข้ามาจัดการ AWS EKS, EC2 ได้ เเนะนำเลือกเป็น Admin ไปเลยก็ได้ครับ ง่ายดี เเต่ถ้า Account ใช้กันหลายคน ผมเเนะนำให้มอบ Permission เท่าที่จำเป็นก็พอนะ ส่วนวิธีการหาได้จาก Google เลยครับ ผมขอข้ามขั้นตอนนี้นะ
  2. ติดตั้ง AWS CLI เเละสั่ง $ aws configure เพื่อกรอกค่า Access Key + Secret Key ที่ได้มาจากขั้นตอนที่ 1 ให้เรียบร้อย วิธีการไปหาจาก Google ดูเเล้วกันนะครับเพราะค่อนข้างเป็นเรื่องพื้นฐานมากๆในการใช้ AWS ในระดับที่เขียน Code สั่งการ 555+
  3. และขั้นตอนที่ 3 ให้เราติดตั้ง Terrafrom ให้เรียบร้อยครับ วิธีการก็ดูจาก Google อีกเช่นกัน

จากนั้น เราจะเริ่มลงมือเขียน Code กันเเล้ว โดยเริ่มจากสร้าง Directory ขึ้นมาก่อน ผมใช้ macOS ก็ใช้คำสั่ง ตามนี้

$ mkdir esk-cluster-terraform/
$ cd esk-cluster-terraform/

จากนั้นก็สร้าง File ขึ้นมา 1 File ตั้งชื่อเป็น eks.tf จะใช้ชื่ออื่นก็ได้นะครับ ตามความเหมาะสม

$ touch eks.tf

และก็ใช้ Text Editor ตามใจชอบเพื่อเขียน Code กัน ตามนี้ครับ มาดูกันทีละส่วนเลย

provider "aws" {  region = "ap-southeast-1"}

ส่วนเเรก ให้เราระบุ Provider เป็น “aws” เเละตั้งค่า region ที่เราต้องการ ในที่นี้ผมใช้เป็น ap-southeast-1 นะครับ

resource "aws_iam_role" "paocloud-eks-cluster" {name = "paocloud-eks-cluster"assume_role_policy = <<POLICY{  "Version": "2012–10–17",  "Statement": [{"Effect": "Allow","Principal": {"Service": "eks.amazonaws.com"},"Action": "sts:AssumeRole"}]}POLICY}

และเราก็สร้าง Role ขึ้นมาเพื่อใช้กับ Cluster ของเราครับ โดยให้กำหนด Policy เป็น JSON หน้าตาประมาณนี้ได้เลย

และเราก็สั่ง Attach Role เข้ากับ Policy ที่เราสร้าง ซึ่งต้อง Attach เข้าไป 2 Role ตามนี้ครับ

resource "aws_iam_role_policy_attachment" "AmazonEKSClusterPolicy" {  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"  role = aws_iam_role.paocloud-eks-cluster.name}resource "aws_iam_role_policy_attachment" "AmazonEKSServicePolicy" {  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"  role = aws_iam_role.paocloud-eks-cluster.name}

ก็มีอยู่ 2 ตัวนะครับ ชื่อว่า AmazonEKSClusterPolicy กับ AmazonEKSServicePolicy นั่นเอง มาดูกันต่อดีกว่าว่าต้องทำอะไรอีกบ้าง

resource "aws_eks_cluster" "paocloud-eks" {  name = "paocloud-eks"  role_arn = aws_iam_role.paocloud-eks-cluster.arn  vpc_config {    subnet_ids = ["subnet-xxxx", "subnet-yyyy"]  }  tags = {    Name = "paocloud-eks"  }}

และขั้นตอนนี้ก็คือ การสร้าง Cluster นั่นเองครับ ตั้งค่าชื่อ Cluster และกำหนด Subnet อย่างน้อย 2 Subnet โดยใช้ AZ ต่างกัน อย่างของผมเองจะใช้ AZ A กับ AZ B นะครับ ตรงส่วนนี้เพื่อที่จะทำให้เราใช้ Multi AZ เพื่อให้ระบบของเรามีความเป็น HA ได้นั่นเอง

จากนั้น เราก็ต้องสร้าง Role ให้กับ Node Group ตามนี้ครับ

resource "aws_iam_role" "paocloud-eks-nodes" {name = "paocloud-eks-nodes-group"assume_role_policy = <<POLICY{"Version": "2012–10–17","Statement": [{"Effect": "Allow","Principal": {"Service": "ec2.amazonaws.com"},"Action": "sts:AssumeRole"}]}POLICY}

และจับเอา Policy 3 ตัว Attach เข้ากับ Role ที่เราสร้าง ตามด้านล่างนี้เลย

resource "aws_iam_role_policy_attachment" "AmazonEKSWorkerNodePolicy" {policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"role = aws_iam_role.paocloud-eks-nodes.name}resource "aws_iam_role_policy_attachment" "AmazonEKS_CNI_Policy" {policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"role = aws_iam_role.paocloud-eks-nodes.name}resource "aws_iam_role_policy_attachment" "AmazonEC2ContainerRegistryReadOnly" {policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"role = aws_iam_role.paocloud-eks-nodes.name}

จะเห็นว่ามีอยู่ 3 Policy ที่เราต้อง Attach เข้าไป ซึ่งก็คือ AmazonEKSWorkerNodePolicy , AmazonEKS_CNI_Policy และ AmazonEC2ContainerRegistryReadOnly นั่นเองครับ

เมื่อเราเตรียม Role และ Policy ต่างๆเรียบร้อยเเล้ว ก็จัดการสร้าง Node Group กันเลย ด้วย Code หน้าตาเเบบนี้

resource "aws_eks_node_group" "paocloud-eks-node" {  cluster_name = aws_eks_cluster.paocloud-eks.name  node_group_name = "paocloud-node-group"  node_role_arn = aws_iam_role.paocloud-eks-nodes.arn  subnet_ids = ["subnet-xxxx", "subnet-yyyy"]  instance_types = ["t3.small"]  disk_size = "20"  remote_access {   ec2_ssh_key = "paomini"}scaling_config {  desired_size = 3  max_size = 10  min_size = 2}depends_on = [  aws_iam_role_policy_attachment.AmazonEKSWorkerNodePolicy,  aws_iam_role_policy_attachment.AmazonEKS_CNI_Policy,  aws_iam_role_policy_attachment.AmazonEC2ContainerRegistryReadOnly,]tags = {  "k8s.io/cluster-autoscaler/paocloud-eks" = "owned"  "k8s.io/cluster-autoscaler/enabled" = "true"}}

เราก็ตั้งค่าชื่อ Node Group เอา Role ที่เราสร้างเข้ามาใช้ กำหนด Instance Type ที่เราจะสร้าง ของผมเลือกเป็น t3.small นะ เพราะไม่ได้ใช้อะไรหนักมากมาย กำหนด Subnet ให้เหมือนกับที่เคยกำหนดให้ Cluster กำหนด SSH Key ลงไปด้วย เผื่อว่ามีปัญหาอะไรจะได้ Shell ไปหา EC2 เพื่อวิเคราะห์ เเก้ไขปัญหาได้ และก็กำหนดค่า Scale ว่าอยากได้กี่เครื่อง มีมากสุดเท่าไร น้อยสุดเท่าไร ตามเเต่จะอยากได้เลยครับ

สังเกตว่าผมกำหนด Tag เอาไว้ด้วยเพื่อใช้ในการทำ Auto Scale นะ เเต่เเค่นี้ยังไม่สมบูรณ์ เพราะต้องกำหนด Role / Policy เข้าไปเพิ่มอีกหน่อย อันนี้ลองค้นคว้ากันเองดูนะครับ

และจากนั้น เราก็กำหนด Output ซักหน่อย จะได้รู้ว่า Terraform มันสร้าง Cluster ได้เเล้ว ให้มัน Return ค่า Endpoint กับค่า CA ตามนี้ครับ

output "eks_cluster_endpoint" {value = aws_eks_cluster.paocloud-eks.endpoint}output "eks_cluster_certificat_authority" {value = aws_eks_cluster.paocloud-eks.certificate_authority}

Code ทั้งหมดนี้ให้เอามาเขียนเรียต่อกันตามลำดับได้เลย หรือจะมาดูตัวอย่างเต็มๆใน GitHub นี้ก็ได้นะครับ

จากนั้นก็ถึงเวลาอันเป็นมงคลในการ Deploy กันเเล้ว ให้เรารันคำสั่ง

$ terraform init

อันนี้ก็เพื่อให้มันโหลดค่า Module ต่างๆเข้ามา และก็คำสั่ง

$ terraform plan

Terraform ก็จะเเสดงว่า มันจะทำอะไรกับ AWS Account ของเราบ้าง อันนี้มันยังไม่ไปสร้างหรือเเก้อะไรนะ เเค่บอกเฉยๆก่อน

เเละหาก Code เราสมบูรณ์เเล้วนั้น ก็จัดการสั่ง

$ terraform apply 

แล้วก็ตอบ “yes” ได้เลย จากนั้นก็มารอลุ้นกันว่าพังรึเปล่า 5555+

และถ้ามันใช้งานได้ มันก็จะเเสดงค่า Endpoint เป็น URL ยาวๆ กับค่า CA ออกมาให้เราดูเป็นสีเขียวๆ และเพื่อความมั่นใจ จะลองเข้าไปดูใน AWS Management Console ก็ได้นะครับสถานะของ Cluster จะต้องเป็นสีเขียว

จากนั้นเราก็ต้องสร้าง context กันก่อน เพื่อให้เราสามารถรัน kubectl ในการจัดการ Cluster ของเรา ด้วยคำสั่ง

$ aws eks — region ap-southeast-1 update-kubeconfig -name <cluster-name>

และก็ลองรันคำสั่ง

$ kubectl get nodes 

มันจะ Return ค่าออกมาเป็นรายการชื่อของ Node ทุกๆตัวที่อยู่ใน Node Group ของเรา และต้องมีสถานะเป็น Ready ด้วยนะ เพียงเท่านี้ เราก็ได้ EKS Cluster เพื่อเอามา Run App ของเรากันเเล้ว !!!

ส่วน Terraform Code ที่เราเขียนเอาไว้นั้น ก็จับเอาลง Git ได้เลยนะครับ

ก่อนจบบทความ ผมขอเเชร์ Knowledge และประสบการณ์ที่เจอมาหน่อยตามนี้ครับ

  1. ใช้งานกับ EFS ไม่ได้ซะงั้น ก็เลยลอง Shell เข้าไปทุกๆ Node เเล้วติดตั้ง Package AWS EFS เเละก็พบว่า มันใช้ได้ซะงั้น 555+
  2. เเนะนำให้เลือก Subnet เป็น Private Subnet นะครับ เเล้วก็ใช้ NAT Gateway เพื่อทำให้มันต่อเน็ตได้ หรือถ้าไม่อยากใช้ NAT Gateway จะใช้ Mikrotik CHR ซึ่งเป็น Virtual Router แบบที่ผมใช้ก็นะครับ ผมใช้ Instance type เเบบ t2.nano ซึ่งเป็นตัวเล็กสุด กับซื้อ LIC มา 40 กว่าๆ USD ซื้อครั้งเดียวใช้ได้ตลอดไปครับ ซึ่งตัว LIC จะทำให้ CHR ของเราใช้ Bandwidth ได้ 1Gbps เป็นค่า Max สุด ซึ่งผมก็มองว่ามันก็เพียงพอเเล้วล้ะ อีกเหตุผลก้คือถ้า App เราต้องไปคุยกับ API ชาวบ้านเวลาโดนทำ NAT ก็จะเป็น SRC IP เเค่เลขเดียว ซึ่งมันเอาไปจัดการกับการตั้งค่า ACL หรือ Firewall ง่าย จะมี Node ซักกี่ตัวเวลายิง Request ออกไปข้างนอก มันก็ออกไป IP เลขเดียวครับ

ส่วนตัวอย่าง Code ไปดูกันได้ที่นี่ เเต่อาจจะมี Code ในการ Deploy service อื่นๆในอนาคตอีกนะครับ ผมจะ share ไว้ที่ repo นี้

https://github.com/paocloud/paocloud-aws-terraform

--

--