K8S cluster on AWS EC2
使用說明
建置架構

目錄結構
Terraform-Bulding-K8S
├── main.tf                                                     
├── outputs.tf                 
├── variables.tf                 
└── script  
    ├── install_k8s_msr.sh                                  
    └── install_k8s_wrk.sh            
組態檔內容
main.tf
provider "aws" {
  region     = var.region
}
#****** VPC Start ******#
resource "aws_vpc" "some_custom_vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "K8S VPC"
  }
}
resource "random_shuffle" "az" {
  input        = ["${var.region}a", "${var.region}c", "${var.region}d"]
  result_count = 1
}
resource "aws_subnet" "some_public_subnet" {
  vpc_id            = aws_vpc.some_custom_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = random_shuffle.az.result[0]
  tags = {
    Name = "K8S Subnet"
  }
}
resource "aws_internet_gateway" "some_ig" {
  vpc_id = aws_vpc.some_custom_vpc.id
  tags = {
    Name = "K8S Internet Gateway"
  }
}
resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.some_custom_vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.some_ig.id
  }
  route {
    ipv6_cidr_block = "::/0"
    gateway_id      = aws_internet_gateway.some_ig.id
  }
  tags = {
    Name = "Public Route Table"
  }
}
resource "aws_route_table_association" "public_1_rt_a" {
  subnet_id      = aws_subnet.some_public_subnet.id
  route_table_id = aws_route_table.public_rt.id
}
resource "aws_security_group" "k8s_sg" {
  name   = "K8S Ports"
  vpc_id = aws_vpc.some_custom_vpc.id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 6443
    to_port     = 6443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  ingress {
    from_port   = 2379
    to_port     = 2380
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 10250
    to_port     = 10250
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 30000
    to_port     = 32767
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = -1
    cidr_blocks = ["0.0.0.0/0"]
  }
}
#****** VPC END ******#
resource "random_string" "s3name" {
  length = 9
  special = false
  upper = false
  lower = true
}
resource "aws_s3_bucket_acl" "s3_bucket_acl" {
  bucket = aws_s3_bucket.s3buckit.id
  acl    = "private"
  depends_on = [aws_s3_bucket_ownership_controls.s3_bucket_acl_ownership]
}
resource "aws_s3_bucket_ownership_controls" "s3_bucket_acl_ownership" {
  bucket = aws_s3_bucket.s3buckit.id
  rule {
    object_ownership = "ObjectWriter"
  }
}
resource "aws_s3_bucket" "s3buckit" {
  bucket = "k8s-${random_string.s3name.result}"
  force_destroy = true
 depends_on = [
    random_string.s3name
  ]
}
resource "aws_iam_role" "k8s_s3_role" {
  name = "k8s_s3_role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
  tags = {
      tag-key = "tag-value"
  }
}
resource "aws_iam_instance_profile" "k8s_s3_profile" {
  name = "k8s_s3_profile"
  role = "${aws_iam_role.k8s_s3_role.name}"
}
resource "aws_iam_role_policy" "k8s_s3_policy" {
  name = "k8s_s3_policy"
  role = "${aws_iam_role.k8s_s3_role.id}"
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}
resource "aws_instance" "ec2_instance_msr" {
    ami = var.ami_id
    subnet_id = aws_subnet.some_public_subnet.id
    instance_type = var.instance_type
    key_name = var.ami_key_pair_name
    associate_public_ip_address = true
    iam_instance_profile = "${aws_iam_instance_profile.k8s_s3_profile.name}"
    security_groups = [ aws_security_group.k8s_sg.id ]
    root_block_device {
    volume_type = "gp2"
    volume_size = "8"
    delete_on_termination = true
    }
    tags = {
        Name = "k8s_msr_1"
    }
    user_data_base64 = base64encode("${templatefile("scripts/install_k8s_msr.sh", {
    region = var.region
    s3buckit_name = "k8s-${random_string.s3name.result}"
    })}")
    depends_on = [
    aws_s3_bucket.s3buckit,
    random_string.s3name
  ]
    
} 
resource "aws_instance" "ec2_instance_wrk" {
    ami = var.ami_id
    count = var.number_of_worker
    subnet_id = aws_subnet.some_public_subnet.id
    instance_type = var.instance_type
    key_name = var.ami_key_pair_name
    associate_public_ip_address = true
    iam_instance_profile = "${aws_iam_instance_profile.k8s_s3_profile.name}"
    security_groups = [ aws_security_group.k8s_sg.id ]
    root_block_device {
    volume_type = "gp2"
    volume_size = "8"
    delete_on_termination = true
    }
    tags = {
        Name = "k8s_wrk_${count.index + 1}"
    }
    user_data_base64 = base64encode("${templatefile("scripts/install_k8s_wrk.sh", {
    region = var.region
    s3buckit_name = "k8s-${random_string.s3name.result}"
    worker_number = "${count.index + 1}"
    })}")
  
    depends_on = [
      aws_s3_bucket.s3buckit,
      random_string.s3name,
      aws_instance.ec2_instance_msr
  ]
}
variables.tf
  variable "access_key" { #Todo: uncomment the default value and add your access key.
          description = "Access key to AWS console"
          default = "" 
  }
  
  variable "secret_key" {  #Todo: uncomment the default value and add your secert key.
          description = "Secret key to AWS console"
          default = "" 
  }
  
  variable "ami_key_pair_name" { #Todo: uncomment the default value and add your pem key pair name. Hint: don't write '.pem' exction just the key name
          default = "aws-ec2-apn1-k8s" 
  }
  variable "number_of_worker" {
          description = "number of worker instances to be join on cluster."
          default = 2
  }
  
  variable "region" {
          description = "The region zone on AWS"
          default = "ap-northeast-1" #The zone I selected is us-east-1, if you change it make sure to check if ami_id below is correct.
  }
  
  variable "ami_id" {
          description = "The AMI to use"
          default = "ami-07c589821f2b353aa" #Ubuntu 20.04
  }
  
  variable "instance_type" {
          default = "t2.medium" #the best type to start k8s with it,
  }
output.tf
output "instance_msr_public_ip" {
  description = "Public address IP of master"
  value       = aws_instance.ec2_instance_msr.public_ip
}
output "instance_wrks_public_ip" {
  description = "Public address IP of worker"
  value       = aws_instance.ec2_instance_wrk.*.public_ip
}
# output "instance_msr_privte_ip" {
#   description = "Private IP address of master"
#   value       = aws_instance.ec2_instance_msr.private_ip
# }
# output "s3_bucket_name" {
#   description = "The S3 bucket name"
#   value       = "k8s-${random_string.s3name.result}"
# }
install_k8s_msr.sh
#!/bin/bash
hostname k8s-msr-1
echo "k8s-msr-1" > /etc/hostname
export AWS_ACCESS_KEY_ID=${access_key}
export AWS_SECRET_ACCESS_KEY=${private_key}
export AWS_DEFAULT_REGION=${region}
echo "[TASK 1] Disable and turn off SWAP"
sudo sed -i '/swap/d' /etc/fstab
sudo swapoff -a
echo "[TASK 2] Stop and Disable firewall"
sudo systemctl disable --now ufw >/dev/null 2>&1
echo "[TASK 3] Install AWS CLI"
apt update
apt install awscli -y
echo "[TASK 4] Enable and Load Kernel modules"
cat >>/etc/modules-load.d/containerd.conf<<EOF
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
echo "[TASK 5] Add Kernel settings"
cat >>/etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
EOF
sysctl --system >/dev/null 2>&1
echo "[TASK 6] Install containerd runtime"
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt -qq update >/dev/null 2>&1
apt install -qq -y containerd.io >/dev/null 2>&1
containerd config default >/etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd >/dev/null 2>&1
echo "[TASK 7] Add apt repo for kubernetes"
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - >/dev/null 2>&1
apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main" >/dev/null 2>&1
echo "[TASK 8] Install Kubernetes components (kubeadm, kubelet and kubectl)"
apt install -qq -y kubeadm=1.28.0-00 kubelet=1.28.0-00 kubectl=1.28.0-00 >/dev/null 2>&1
echo "[TASK 9] Kubernetes cluster init"
export ipaddr=`ip address|grep eth0|grep inet|awk -F ' ' '{print $2}' |awk -F '/' '{print $1}'`
export pubip=`dig +short myip.opendns.com @resolver1.opendns.com`
kubeadm init --apiserver-advertise-address=$ipaddr --pod-network-cidr=172.16.0.0/16 --apiserver-cert-extra-sans=$pubip > /tmp/restult.out
cat /tmp/restult.out
echo "[TASK 10] to get join commnd"
tail -2 /tmp/restult.out > /tmp/join_command.sh;
aws s3 cp /tmp/join_command.sh s3://${s3buckit_name};
#this adds .kube/config for root account, run same for ubuntu user, if you need it
sudo mkdir -p /root/.kube;
sudo cp -i /etc/kubernetes/admin.conf /root/.kube/config;
sudo cp -i /etc/kubernetes/admin.conf /tmp/admin.conf;
sudo chmod 755 /tmp/admin.conf
echo "[TASK 11] Add kube config to ubuntu user"
sudo mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
#to copy kube config file to s3
# aws s3 cp /etc/kubernetes/admin.conf s3://${s3buckit_name}
echo "[TASK 12] Install Pod Network"
sudo curl -o /root/kube-flannel.yml https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
sleep 5
sudo sed -i "s/10.244.0.0/172.16.0.0/g" /root/kube-flannel.yml
sudo sed -i "/mgr/a\        - --iface=eth0" /root/kube-flannel.yml
sudo kubectl --kubeconfig /root/.kube/config apply -f /root/kube-flannel.yml
sudo systemctl restart kubelet
echo "[TASK 13] Apply kubectl Cheat Sheet Autocomplete"
source <(kubectl completion bash) # set up autocomplete in bash into the current shell, bash-completion package should be installed first.
echo "source <(kubectl completion bash)" >> /home/ubuntu/.bashrc # add autocomplete permanently to your bash shell.
echo "source <(kubectl completion bash)" >> /root/.bashrc # add autocomplete permanently to your bash shell.
alias k=kubectl
complete -o default -F __start_kubectl k
echo "alias k=kubectl" >> /home/ubuntu/.bashrc
echo "alias k=kubectl" >> /root/.bashrc
echo "complete -o default -F __start_kubectl k" >> /home/ubuntu/.bashrc
echo "complete -o default -F __start_kubectl k" >> /root/.bashrc
install_k8s_wrk.sh
    #!/bin/bash
    
    ######### ** FOR WORKER NODE ** #########
    
    hostname k8s-wrk-${worker_number}
    echo "k8s-wrk-${worker_number}" > /etc/hostname
    
    export AWS_ACCESS_KEY_ID=${access_key}
    export AWS_SECRET_ACCESS_KEY=${private_key}
    export AWS_DEFAULT_REGION=${region}
    
    echo "[TASK 1] Disable and turn off SWAP"
    sudo sed -i '/swap/d' /etc/fstab
    sudo swapoff -a
    
    echo "[TASK 2] Stop and Disable firewall"
    sudo systemctl disable --now ufw >/dev/null 2>&1
    
    echo "[TASK 3] Install AWS CLI"
    apt update
    apt install awscli -y
    
    echo "[TASK 4] Enable and Load Kernel modules"
    cat >>/etc/modules-load.d/containerd.conf<<EOF
    overlay
    br_netfilter
    EOF
    modprobe overlay
    modprobe br_netfilter
    
    echo "[TASK 5] Add Kernel settings"
    cat >>/etc/sysctl.d/kubernetes.conf<<EOF
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables  = 1
    net.ipv4.ip_forward                 = 1
    EOF
    sysctl --system >/dev/null 2>&1
    
    echo "[TASK 6] Install containerd runtime"
    mkdir -p /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    echo   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    apt -qq update >/dev/null 2>&1
    apt install -qq -y containerd.io >/dev/null 2>&1
    containerd config default >/etc/containerd/config.toml
    sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
    sudo systemctl restart containerd
    sudo systemctl enable containerd >/dev/null 2>&1
    
    echo "[TASK 7] Add apt repo for kubernetes"
    curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - >/dev/null 2>&1
    apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main" >/dev/null 2>&1
    
    echo "[TASK 8] Install Kubernetes components (kubeadm, kubelet and kubectl)"
    apt install -qq -y kubeadm=1.28.0-00 kubelet=1.28.0-00 kubectl=1.28.0-00 >/dev/null 2>&1
    
    echo "[TASK 9] Join master node"
    sleep 1m
    aws s3 cp s3://${s3buckit_name}/join_command.sh /tmp/.
    chmod +x /tmp/join_command.sh
    bash /tmp/join_command.sh
Terraform 指令
- terraform init
 - terraform validate
 - terraform apply
 - terraform show
 - terraform destroy