참고자료
- Ncloud Provider : https://registry.terraform.io/providers/NaverCloudPlatform/ncloud/latest/docs
- Ncloud Kubernetes Service : https://www.ncloud.com/product/containers/kubernetes
[출처] 테라폼을 통해 Ncloud Kubernetes Service (NKS) 클러스터 구축하기|작성자 NAVER Cloud Platform
ncloud provider를 통한 kubernetes cluster 생성
- API 환경 변수 설정 ncloud API를 사용하는데 필요한 인증 정보와 엔드포인트 정보를 환경 변수로 설정합니다. NCLOUD_API_GW는 테라폼에서 직접적으로 사용되지 않지만 NKS 클러스터의 kubeconfig 파일을 생성하는데 사용됩니다.
export NCLOUD_ACCESS_KEY=ACCESSKEY
export NCLOUD_SECRET_KEY=SECRETKEY
export NCLOUD_API_GW=https://ncloud.apigw.ntruss.com
위 방법으로 API 인증 정보를 환경변수로 지정 가능하지만, 저는 여러개의 Terraform환경을 사용중이기 때문에 아래와 같이 ncloud.tf 를 통해 API 인증 정보를 지정하였습니다.
root@D-choimp:~/terraform/nks_choimp# tree .
.
├── infra.tf
└── ncloud.tf
- ncloud.tf
provider "ncloud" {
region = "KR"
site = "pub"
support_vpc = "true"
access_key = "xx"
secret_key = "xx"
}
terraform {
required_providers {
ncloud = {
source = "NaverCloudPlatform/ncloud"
version = ">= 2.3.19"
}
}
}
이후 CLI에서 terraform init 명령어를 입력하여 테라폼 초기화를 진행합니다. 초기화를 통해 테라폼은 필요한 provider의 플러그인을 다운로드하고 초기화합니다.
명령어 실행 후 로그를 통해 초기화가 정상적으로 진행 되었는지, 플러그인이 올바르게 설치 되었는지 확인할 수 있습니다.
$ terrraform init
Initializing the backend…
Initializing provider plugins…
- Finding navercloudplatform/ncloud versions matching “>= 2.3.19″…
- Installing navercloudplatform/ncloud v2.3.19…
(생략)
Terraform has been successfully initialized!
(생략)
kubernetes cluster 생성을 위한 테라폼 코드 작성
kubernetes cluster를 생성하기 위해서는 상품 별로 아래 리소스가 필요합니다.
- VPC
- Subnet
- Subnet
- LoadBalancer Subnet
- NAT G/W Subnet
- NAT G/W
- Route Table
- Ncloud Kubernetes Service
- Login Key
테스트 환경으로 하나의 파일을 이용하여 단순한 코드로 인프라를 관리할수 있지만,
실무 환경에서는 코드의 재사용성과 유지보수성을 향상시키기 위해 각 리소스를 분리하고 모듈화하여 사용하는 것이 좋습니다.
아래 infra.tf 파일에는 kubernetes cluster를 생성하기 위한 전체 리소스가 기재되어 있으며,
분리된 코드 또한 첨부하였으니 참고하시면 됩니다.
infra.tf
variable "zone" {
type = string
default = "KR-1"
}
resource "ncloud_vpc" "kubernetes_vpc" {
name = "choimp-terraform-nks-vpc"
ipv4_cidr_block = "10.0.0.0/16"
}
resource "ncloud_subnet" "private_node_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.1.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "terraform-private-node-subnet"
usage_type = "GEN"
}
resource "ncloud_subnet" "private_lb_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.11.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "terraform-private-lb-subnet"
usage_type = "LOADB"
}
resource "ncloud_subnet" "public_lb_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.12.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "terraform-public-lb-subnet"
usage_type = "LOADB"
}
resource "ncloud_subnet" "nat_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.3.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "terraform-nat-subnet"
usage_type = "NATGW"
}
resource "ncloud_nat_gateway" "kubernetes_nat_gw" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet_no = ncloud_subnet.nat_subnet.id
zone = var.zone
name = "terraform-kubernetes-nat-gw"
}
resource "ncloud_route_table" "kubernetes_route_table" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
supported_subnet_type = "PRIVATE"
name = "kubernetes-route-table"
}
resource "ncloud_route" "kubernetes_route" {
route_table_no = ncloud_route_table.kubernetes_route_table.id
destination_cidr_block = "0.0.0.0/0"
target_type = "NATGW"
target_name = ncloud_nat_gateway.kubernetes_nat_gw.name
target_no = ncloud_nat_gateway.kubernetes_nat_gw.id
}
resource "ncloud_route_table_association" "kubernetes_route_table_subnet" {
route_table_no = ncloud_route_table.kubernetes_route_table.id
subnet_no = ncloud_subnet.private_node_subnet.id
}
resource "ncloud_login_key" "kubernetes_loginkey" {
key_name = "terraform-kubernetes-loginkey"
}
resource "ncloud_nks_cluster" "terraform_cluster" {
cluster_type = "SVR.VNKS.STAND.C002.M008.NET.SSD.B050.G002"
login_key_name = ncloud_login_key.kubernetes_loginkey.key_name
name = "terraform-cluster"
lb_private_subnet_no = ncloud_subnet.private_lb_subnet.id
lb_public_subnet_no = ncloud_subnet.public_lb_subnet.id
subnet_no_list = [ncloud_subnet.private_node_subnet.id]
vpc_no = ncloud_vpc.kubernetes_vpc.id
zone = var.zone
}
resource "ncloud_nks_node_pool" "node_pool" {
cluster_uuid = ncloud_nks_cluster.terraform_cluster.uuid
node_pool_name = "terraform-node-1"
node_count = 2
product_code = "SVR.VSVR.STAND.C002.M008.NET.SSD.B050.G002"
subnet_no_list = [ncloud_subnet.private_node_subnet.id]
}
코드 분리
ncloud.tf
variable "zone" {
type = string
default = "KR-1"
}
resource "ncloud_vpc" "kubernetes_vpc" {
name = "choimp-terraform-nks-vpc"
ipv4_cidr_block = "10.0.0.0/16"
}
vpc.tf
variable "zone" {
type = string
default = "KR-1"
}
resource "ncloud_vpc" "kubernetes_vpc" {
name = "choimp-terraform-nks-vpc"
ipv4_cidr_block = "10.0.0.0/16"
}
subnet.tf
resource "ncloud_subnet" "private_node_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.1.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "terraform-private-node-subnet"
usage_type = "GEN"
}
resource "ncloud_subnet" "private_lb_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.11.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "terraform-private-lb-subnet"
usage_type = "LOADB"
}
resource "ncloud_subnet" "public_lb_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.12.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "terraform-public-lb-subnet"
usage_type = "LOADB"
}
resource "ncloud_subnet" "nat_subnet" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet = "10.0.3.0/24"
zone = var.zone
network_acl_no = ncloud_vpc.kubernetes_vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "terraform-nat-subnet"
usage_type = "NATGW"
}
route_table.tf
resource "ncloud_route_table" "kubernetes_route_table" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
supported_subnet_type = "PRIVATE"
name = "kubernetes-route-table"
}
resource "ncloud_route" "kubernetes_route" {
route_table_no = ncloud_route_table.kubernetes_route_table.id
destination_cidr_block = "0.0.0.0/0"
target_type = "NATGW"
target_name = ncloud_nat_gateway.kubernetes_nat_gw.name
target_no = ncloud_nat_gateway.kubernetes_nat_gw.id
}
resource "ncloud_route_table_association" "kubernetes_route_table_subnet" {
route_table_no = ncloud_route_table.kubernetes_route_table.id
subnet_no = ncloud_subnet.private_node_subnet.id
}
nks.tf
resource "ncloud_nks_cluster" "terraform_cluster" {
cluster_type = "SVR.VNKS.STAND.C002.M008.NET.SSD.B050.G002"
login_key_name = ncloud_login_key.kubernetes_loginkey.key_name
name = "terraform-cluster"
lb_private_subnet_no = ncloud_subnet.private_lb_subnet.id
lb_public_subnet_no = ncloud_subnet.public_lb_subnet.id
subnet_no_list = [ncloud_subnet.private_node_subnet.id]
vpc_no = ncloud_vpc.kubernetes_vpc.id
zone = var.zone
}
resource "ncloud_nks_node_pool" "node_pool" {
cluster_uuid = ncloud_nks_cluster.terraform_cluster.uuid
node_pool_name = "terraform-node-1"
node_count = 2
product_code = "SVR.VSVR.STAND.C002.M008.NET.SSD.B050.G002"
subnet_no_list = [ncloud_subnet.private_node_subnet.id]
}
nat_gw.tf
resource "ncloud_nat_gateway" "kubernetes_nat_gw" {
vpc_no = ncloud_vpc.kubernetes_vpc.id
subnet_no = ncloud_subnet.nat_subnet.id
zone = var.zone
name = "terraform-kubernetes-nat-gw"
}
login_key.tf
resource "ncloud_login_key" "kubernetes_loginkey" {
key_name = "terraform-kubernetes-loginkey"
}
두 코드는 같은 인프라를 생성하는 코드이지만 코드를 분리하여 사용하는 것에는 몇 가지 이점이 있습니다:
- 모듈화 및 재사용성: 각 상품에 대한 코드를 별도의 파일로 분리하면 해당 기능을 모듈화하여 필요한 곳에서 재사용할 수 있습니다. 예를 들어, 다른 프로젝트나 환경에서 같은 VPC 구성이 필요할 때 해당 모듈을 가져와 사용할 수 있습니다.
- 가독성 및 유지보수: 코드가 각 상품 별로 분리되어 있으면 전체 코드의 가독성이 향상되고 유지보수가 용이해집니다. 특정 상품의 변경 또는 수정이 필요할 때 해당 파일만 수정하면 되므로 다른 부분에 영향을 주지 않습니다.
- 협업과 버전 관리: 코드를 분리하면 여러 명의 개발자가 동시에 작업할 때 충돌을 최소화하고 각자의 역할에 맞게 작업할 수 있습니다. 또한, 각 상품에 대한 코드를 개별적으로 관리함으로써 버전 관리가 용이해집니다.
- 테스트 용이성: 분리된 코드는 개별적으로 테스트하기 쉽습니다. 각 상품에 대한 단위 테스트 또는 통합 테스트를 수행하여 코드의 신뢰성을 높일 수 있습니다.
이러한 이유들로 코드를 분리하여 사용하는 것이 코드의 가독성, 유지보수성, 재사용성 등을 향상시킬 수 있습니다.
terraform plan (infra)
infra.tf 에 생성할 리소스를 모두 기재하였다면 terraform plan 명령어를 입력하여 생성될 리소스 계획을 확인합니다. 작업 검토 목적으로 진행하는 계획 단계에서는 실제 리소스가 생성되지 않습니다.
$ terraform plan … Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- create
Terraform will perform the following actions: … Plan: 12 to add, 0 to change, 0 to destroy.
terraform plan 수행 시 각 리소스에 대한 세부 사항이 출력됩니다. 의도한 대로 리소스가 생성되는지 확인하고, 문제가 있는 경우 수정을 진행합니다. 리소스가 생성되기 전 단계에서 구성의 정확성을 검증하고 예상되는 변경사항을 미리 파악할 수 있습니다.
다음 내용에서는 kubernetes provider를 통한 워크로드 생성을 소개해 보겠습니다.