JUST WRITE

명령어 한 번에 Kubernetes 설치하기 - Terraform으로 Kubernetes 설치 본문

MLOps/Kubernetes

명령어 한 번에 Kubernetes 설치하기 - Terraform으로 Kubernetes 설치

천재보단범재 2023. 5. 23. 23:48

명령어 한번에 Kubernetes 설치하기

 

명령어 한 번에 Kubernetes 설치하기

개발 환경을 자주 구성하다 보니 Kubernetes Cluster를 구성하는 일이 많았습니다.

Kubernetes Cluster 구성은 단계도 많고 쉽지 않아 할 때마다 새로웠습니다.

구성을 간편하게 할 수 있는 방법이 없을까 고민하다가 Terraform을 알게 되었습니다.

Terraform을 활용하여 간편하게 Kubernetes Cluster를 구성하는 것을 정리해보려 합니다.

(Terraform이 아닌 AWS EC2 다수의 인스턴스로 Kubernetes를 구성하는 것은 아래 포스팅 참조)

 

AWS EC2 Kubernetes Cluster 설치(1) Kubeadm - containerd 설치

AWS EC2 Kubernetes Cluster 설치 이번 포스팅에서는 AWS EC2 인스턴스 4개에 Kubernetes Cluster를 구성해보았다. 각 인스턴스는 Ubuntu Sever 22.04에 t3.large로 구성하였다. 1개의 Master와 3개의 Worker로 구성하였다. K

developnote-blog.tistory.com

What is Terraform?

Terraform오픈 소스로 IaC(Infrastructure as Code) Tool입니다.

IaC는 Storage, Network 등 Infra를 Code로 관리하는 것을 의미합니다.

Terraform을 통해서 Cloud나 On-premise 환경의 Resouce들을 Code로 관리할 수 있습니다.

https://developer.hashicorp.com/terraform/intro

Terraform은 Provider를 통해서 해당 Resource를 관리합니다.

작성한 Terraform Code를 실행하며 Provider가 Resource의 API를 통해 Resource에 반영합니다.

Provider들은 Terraform Registry에서 확인할 수 있습니다. 

AWS, GCP, Kubernetes, Helm, DataDog 등 다양한 Provider들을 제공합니다.

Terraform 설치

일단 Terraform 설치를 진행해 보겠습니다.

AWS EC2, Amazon Linux 2023 AMI 인스턴스에 설치를 진행하였습니다.

Terraform bin 파일을 Download 합니다.

$ wget https://releases.hashicorp.com/terraform/1.4.6/terraform_1.4.6_linux_amd64.zip
$ unzip terraform_1.4.6_linux_amd64.zip
$ ll
total 83408
-rwxr-xr-x. 1 ec2-user ec2-user 64626688 Apr 26 17:54 terraform
-rw-r--r--. 1 ec2-user ec2-user 20779821 Apr 26 18:26 terraform_1.4.6_linux_amd64.zip

bin 파일을 PATH에 위치시켜 어디에서든 command를 실행할 수 있도록 합니다.

$ mkdir -p ~/.local/bin
$ mv terraform ~/.local/bin
$ terraform
Usage: terraform [global options] <subcommand> [args]

The available commands for execution are listed below.
The primary workflow commands are given first, followed by
less common or more advanced commands.

Main commands:
  init          Prepare your working directory for other commands
  validate      Check whether the configuration is valid
  plan          Show changes required by the current configuration
  apply         Create or update infrastructure
  destroy       Destroy previously-created infrastructure

All other commands:
  console       Try Terraform expressions at an interactive command prompt
  fmt           Reformat your configuration in the standard style
  force-unlock  Release a stuck lock on the current workspace
  get           Install or upgrade remote Terraform modules
  graph         Generate a Graphviz graph of the steps in an operation
  import        Associate existing infrastructure with a Terraform resource
  login         Obtain and save credentials for a remote host
  logout        Remove locally-stored credentials for a remote host
  metadata      Metadata related commands
  output        Show output values from your root module
  providers     Show the providers required for this configuration
  refresh       Update the state to match remote systems
  show          Show the current state or a saved plan
  state         Advanced state management
  taint         Mark a resource instance as not fully functional
  test          Experimental support for module integration testing
  untaint       Remove the 'tainted' state from a resource instance
  version       Show the current Terraform version
  workspace     Workspace management

Global options (use these before the subcommand, if any):
  -chdir=DIR    Switch to a different working directory before executing the
                given subcommand.
  -help         Show this help output, or the help for a specified subcommand.
  -version      An alias for the "version" subcommand.

AWS Config 설정

Terraform으로 Kubernetes 구성은 AWS EC2 인스턴스들을 띄워서 구성할 예정입니다.

Terraform AWS Provider를 통해서 구성합니다.

AWS EC2 인스턴스를 시작할 수 있는 권한을 가진 IAM User가 필요합니다.

IAM에서 AmazonEC2FullAccess 권한을 가진 User를 생성하였습니다.

해당 User의 access-key, secret-key를 Terraform 실행할 Server에 등록합니다.

aws cli를 통해서 등록하거나 credentials 파일을 직접 생성합니다.

# 1. aws command
$ aws configure
AWS Access Key ID [None]: 
AWS Secret Access Key [None]: 
Default region name [None]: 
Default output format [None]:

# 2. credentials 파일 생성
$ vi ~/.aws/credentials 
[default]
aws_access_key_id = ${access-key}
aws_secret_access_key = ${secret-key}

이제 Terraform을 사용할 준비는 마쳤습니다.

Kubernetes 설치

솔직히 말하면 commad 하나로 Kubernetes Cluster 구성을 하지 못했습니다.

Terramform으로 구성 후 몇 가지 추가 작업이 필요합니다.

하지만 Terraform으로 통한 Kubernetes 구성 작업량은 상당히 줄어들었습니다.

일단 Terraform Code를 살펴보도록 하겠습니다.

Terraform Code

Terraform을 통해 AWS EC2 Instance 4개, Elastic IP, EBS(Elastic Block Store)가 설치됩니다.

EC2 Instance 4개는 Kuberentes Master Node 1개, Worker Node 3개로 구성됩니다.

Terraform 전체 Code는 아래와 같습니다.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws" 
      version = "~> 4.16" 
    }
  }

  required_version = ">= 1.2.0" 
}

provider "aws" {
  region = "ap-northeast-2" 
}

variable "nodes" {
  type   = map(object({
    name = string
    type = string
    size = number
  }))
  default = {
    "k8smaster" = {
      name = "k8smaster" 
      type = "t3.large" 
      size = "20" 
    },
    "k8sworker1" = {
      name = "k8sworker1" 
      type = "t3.xlarge" 
      size = "40" 
    },
    "k8sworker2" = {
      name = "k8sworker2" 
      type = "t3.xlarge" 
      size = "40" 
    },
    "k8sworker3" = {
      name = "k8sworker3" 
      type = "t3.xlarge" 
      size = "40" 
    }
  }
}

resource "aws_instance" "instances" {
  for_each = var.nodes

  availability_zone = "ap-northeast-2c" 
  ami               = "ami-0c9c942bd7bf113a2" # ubuntu 22.04 LTS
  instance_type     = each.value.type
  key_name          = ${key-name} 
  user_data         = file("./user-data/node-install.sh")
  vpc_security_group_ids = [
    ${security-group-id1},
    ${security-group-id2}
  ]

  root_block_device {
    volume_type = "gp3" 
    volume_size = 10 # GiB
  }

  tags = {
    Name = each.value.name
    provider = "terraform" 
  }
}

resource "aws_ebs_volume" "volumes" {
  for_each = var.nodes

  availability_zone = "ap-northeast-2c" 
  size = each.value.size
  type = "gp3" 

  tags = {
    Name = "${each.value.name}-vol" 
    provider = "terraform" 
  }
}

resource "aws_volume_attachment" "attachements" {
  for_each = var.nodes

  device_name = "/dev/sdh" 
  volume_id   = aws_ebs_volume.volumes[each.value.name].id
  instance_id = aws_instance.instances[each.value.name].id
}

resource "aws_eip" "master_ip" {
  instance = aws_instance.instances["k8smaster"].id
  vpc      = true

  tags = {
    Name     = "k8smaster_ip" 
    provider = "terraform" 
  }
}

Variable을 통해 EC2 Instance로 설치한 Master Node, Worker Node 정보들을 기입하였습니다.

  • Instance 이름
  • Instance Type
  • 추가 EBS Size
variable "nodes" {
  type   = map(object({
    name = string
    type = string
    size = number
  }))
  default = {
    "k8smaster" = {
      name = "k8smaster" 
      type = "t3.large" 
      size = "20" 
    },
    "k8sworker1" = {
      name = "k8sworker1" 
      type = "t3.xlarge" 
      size = "40" 
    },
    "k8sworker2" = {
      name = "k8sworker2" 
      type = "t3.xlarge" 
      size = "40" 
    },
    "k8sworker3" = {
      name = "k8sworker3" 
      type = "t3.xlarge" 
      size = "40" 
    }
  }
}

Terraform에서는 반복문을 사용할 수 있습니다.

for_each라는 구문을 활용하여 반복적인 EC2 Instance 생성 부분을 간략하게 할 수 있었습니다.

위에서 정의한 Instance 정보들을 기입한 Variable으로 for문을 진행하였습니다.

EBS 역시 같은 방식으로 for문을 진행하였습니다.

resource "aws_instance" "instances" {
  for_each = var.nodes

  availability_zone = "ap-northeast-2c" 
  ami               = "ami-0c9c942bd7bf113a2" # ubuntu 22.04 LTS
  instance_type     = each.value.type
  key_name          = ${key-name} 
  user_data         = file("./user-data/node-install.sh")
  vpc_security_group_ids = [
    ${security-group-id1},
    ${security-group-id2}
  ]

  root_block_device {
    volume_type = "gp3" 
    volume_size = 10 # GiB
  }

  tags = {
    Name = each.value.name
    provider = "terraform" 
  }
}

AWS Instance를 실행할 때 user-data를 활용하여 시작 시 script를 실행할 수 있습니다.

user-data를 이용하여 Kubernetes 설치에 필요한 작업들을 script로 정리하여 실행하였습니다.

script에서 진행하는 작업은 아래와 같습니다.

  • swap off
  • EBS mount
  • Docker 설치
  • cri-dockerd 설치
  • kubeadm, kubectl, kubelet 설치
#!/bin/bash

# swap off
sudo swapoff -a

# EBS mount
sudo mkfs.ext4 /dev/nvme1n1
sudo mkdir /data -p
echo '/dev/nvme1n1 /data ext4 defaults 0 0' | sudo tee -a /etc/fstab > /dev/null
sudo mount -a

# network plugin setting
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params setting
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

# docker install
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg -y
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin -y

sudo mkdir /data/docker_dir -p
sudo tee -a /etc/docker/daemon.json > /dev/null << EOT
{ 
   "data-root": "/data/docker_dir" 
}
EOT

sudo systemctl enable docker --now
sudo systemctl restart docker

# cri-dockerd install
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.2/cri-dockerd_0.3.2.3-0.ubuntu-jammy_amd64.deb
sudo dpkg -i cri-dockerd_0.3.2.3-0.ubuntu-jammy_amd64.deb
rm cri-dockerd_0.3.2.3-0.ubuntu-jammy_amd64.deb

# k8s install
sudo apt-get install -y apt-transport-https ca-certificates curl
#sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
#echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

script 작업에 대한 자세한 설명은 아래 포스팅에서 확인할 수 있습니다.

 

AWS EC2 Kubernetes Cluster 설치(1) Kubeadm - containerd 설치

AWS EC2 Kubernetes Cluster 설치 이번 포스팅에서는 AWS EC2 인스턴스 4개에 Kubernetes Cluster를 구성해보았다. 각 인스턴스는 Ubuntu Sever 22.04에 t3.large로 구성하였다. 1개의 Master와 3개의 Worker로 구성하였다. K

developnote-blog.tistory.com

마지막으로 Master Node로 설치한 Instance에 Elastic IP를 연결합니다.

외부에서 Master Node로 통해 Kubernetes에 접근하기 때문에 Master Node에만 연결합니다.

resource "aws_eip" "master_ip" {
  instance = aws_instance.instances["k8smaster"].id
  vpc      = true

  tags = {
    Name     = "k8smaster_ip" 
    provider = "terraform" 
  }
}

Terraform 실행

이제 Terraform 실행을 합니다.

Terraform init command를 통해 AWS Provider를 설치합니다.

$ terraform init
$ cd .terraform
$ tree
.
└── providers
    └── registry.terraform.io
        └── hashicorp
            └── aws
                └── 4.67.0
                    └── linux_amd64
                        └── terraform-provider-aws_v4.67.0_x5

validate command로 작성한 terraform code를 실행 전에 검증합니다.

$ terraform validate
Success! The configuration is valid.

이제 작성한 terraform code를 AWS에 적용해 봅니다.

# 적용, auto-approve 인자를 넣으면 마지막 확인 절차 진행 X
$ terraform apply -auto-approve

AWS Console - EC2

AWS Console에서 EC2 Instance 4개가 생성된 것을 확인할 수 있습니다.

Terraform을 통해서 EC2 Instance를 설치하고 docker, kubeadm까지 설치하였습니다.

남은 작업은 아래와 같습니다.

  • hostname 설정
  • /etc/hosts 세팅 - Master Node, Worker Node Private IP 등록
  • Master Node Kubeadm init
  • 각 Worker Node Kubeadm Join

Node마다 command가 다른 부분,  Join 할 때 Token 기입 부분은 Terrform으로 아직 해결하지 못했습니다.

조금 더 보완해서 해당 부분까지 Terraform으로 해결하도록 Version 2를 만들도록 하겠습니다.

[보완]

추가적으로 이번 포스팅에서 Kubernetes의 Container runtime을 docker로 설치하였습니다.

kubeadm으로 init, join시 해당 parameter를 추가해줘야 합니다.

  • --cri-socket unix:///var/run/cri-dockerd.sock
# kubeadm init(Mater node)
$ sudo kubeadm init --control-plane-endpoint=k8smaster --apiserver-advertise-address=${control_plain_ip} --pod-network-cidr=10.244.0.0/16 --cri-socket unix:///var/run/cri-dockerd.sock

# kubeadm join(Worker node)
$ sudo kubeadm join k8smaster:6443 --token ${token} --discovery-token-ca-cert-hash ${hash} --cri-socket unix:///var/run/cri-dockerd.sock
728x90
반응형
Comments