[이렇게 사용하세요!]네이버 클라우드 플랫폼에서 terraform 활용[1] : ansible 연동

NAVER Cloud
NAVER Cloud
Published in
34 min readAug 31, 2020
  • 본 콘텐츠는 네이버 클라우드 플랫폼 Tech Evangelist 송창안 님이 작성하셨습니다.

안녕하세요 네이버 클라우드 플랫폼입니다!

이번 시간은 네이버 클라우드 플랫폼에서 terraform과 ansible을 연동하여 서비스를 생성 하는 시간을 가져보겠습니다.

그럼 시작해볼까요?

[사전 준비 사항]

* 네이버 클라우드 플랫폼 가입

  • 네이버 클라우드 플렛폼에서 vm을 하나 생성하여 ansible 설치까지 확인(아래 내용 참조)
# yum install epel-release
# yum install ansible -y

그러면, Terraform 은 무엇인지 알고 가볼까요?

Q. Terraform 은 무엇인가요?

Terraform은 특정 클라우드 플랫폼에 종속되지 않고 멀티 클라우드 환경에서 사용이 가능하며, HashiCorp Configuration Language 문법을 사용하여 인프라 구성을 안전하고 예측한 대로 생성, 변경 및 프로비저닝을 할 수 있습니다.

​- Execution Plans : 다른 코드처럼 git 등을 이용해 리얼 인프라 적용 전 사전 테스트가 가능합니다.

- Change Automation : 수동이 아닌 코드로 서버를 생성하기 때문에 서버 운영 및 관리가 자동화됩니다.

- Resource Graph : 디펜던시 관련해서 Terraform에서 자체적으로 그래프를 이용해 생성하는데 문제없이 인프라를 디플로이 합니다.

Terraform에서 다루어 지는 IAC 라는 개념은 무엇일까요?

IAC(Infrastructure as a Code)란?

IAC는 Infrastructure as a Code의 줄임말로 인프라를 코드로 표현한다는 의미이며, 명시적인 코드 형태로 인프라를 프로비저닝하고 관리하는 방식입니다. 인프라가 코드를 통해 정의되므로 인프라와 서버를 표준화된 패턴을 사용하여 배포하고, 최신 패치와 버전으로 업데이트하거나, 다양한 플랫폼 및 환경에 동일한 인프라 구성 매칭이 가능합니다.

​기존 SW 기업들은 많은 리소스를 서버와 같은 하드웨어 빌드에 사용하였습니다. 개발자들이 빌드한 애플리케이션을 OPS 팀이라 불리는 서버 관리팀에 넘기면 OPS 팀은 서버에 디플로이하는 과정을 담당했습니다. 하지만 클라우드 서비스가 퍼지면서 기업들은 점차 서버를 직접 관리하지 않게 되었고, 개발자가 코딩부터 디플로이까지 하게 되는 DevOps 분야가 생겨났습니다. 이러한 DevOps 분야가 발전하면서 IAC 분야도 각광을 받게 된 것입니다.

​이러한 IAC로 인프라 리소스 구성이 자동화하였을 때, 빠르고 안전하게 리소스를 증설하거나 복구가 가능합니다. 또한 명시적인 코드 형태 관리를 통해 문서화와 버전 관리가 수월하여 변경 이력 및 서비스 영향에 대해 명확한 파악이 가능해집니다.

아래 동영상에서 전체 과정을 살펴보실 수 있습니다.

간단히 terraform을 설치 하여, 예제 파일을 통해 서버 1대 생성 및 public ip 구성하고 ngnix 설치 후 서비스를 확인 할 수 있는 시나리오를 구성 하였습니다.

1. terraform 0.13.0 버젼을 설치 합니다

# wget https://releases.hashicorp.com/terraform/0.13.0/terraform_0.13.0_linux_amd64.zip
# unzip terraform_0.13.0_linux_amd64.zip
Archive: terraform_0.13.0_linux_amd64.zip
inflating: terraform
# mv terraform /usr/bin/

2. 아래와 같이 디렉토리를 생성 합니다.

# mkdir ~/terraform_example
# mkdir ~/terraform_example/ncloud
# mkdir ~/terraform_example/ncloud/ansible

3. main.tf 파일을 생성 하고 아래의 내용을 구현 합니다.

압축 파일로 아래의 파일들을 업로드 해두었습니다.

아래와 같이 github에 코드도 업로드 해두었습니다.

main.tf

provider "ncloud" {
access_key = var.access_key
secret_key = var.secret_key
region = var.region
}
resource "random_id" "id" {
byte_length = 4
}
resource "ncloud_login_key" "key" {
key_name = "${var.login_key_name}${random_id.id.hex}"
}
data "ncloud_root_password" "rootpwd" {
server_instance_no = ncloud_server.server.id
private_key = ncloud_login_key.key.private_key
}
data "ncloud_port_forwarding_rules" "rules" {
zone = ncloud_server.server.zone
}
resource "ncloud_server" "server" {
name = "${var.server_name}${random_id.id.hex}"
server_image_product_code = var.server_image_product_code
server_product_code = var.server_product_code
login_key_name = ncloud_login_key.key.key_name
zone = var.zone
}
#port forwarding 22 port for this host
resource "ncloud_port_forwarding_rule" "forwarding" {
port_forwarding_configuration_no = data.ncloud_port_forwarding_rules.rules.id
server_instance_no = ncloud_server.server.id
port_forwarding_external_port = var.port_forwarding_external_port
port_forwarding_internal_port = "22"
}
#public ip service
resource "ncloud_public_ip" "public_ip" {
server_instance_no = ncloud_server.server.id
}
#playbook for ansible
resource "null_resource" "ssh" {
provisioner "local-exec" {
command = <<EOF
echo "[ncloud]" > inventory
echo "${ncloud_server.server.name} ansible_host='${ncloud_port_forwarding_rule.forwarding.port_forwarding_public_ip}' ansible_port='${ncloud_port_forwarding_rule.forwarding.port_forwarding_external_port}' ansible_ssh_user=root ansible_ssh_pass='${data.ncloud_root_password.rootpwd.root_password}'" >> inventory
EOF } provisioner "local-exec" {
command = <<EOF
ANSIBLE_HOST_KEY_CHECKING=False \
ansible-playbook -i inventory playbook.yml
EOF }
}

4. output.tf 파일을 생성 후, 아래 내용을 구현 합니다.

output.tf

output "server_name_list" {
value = join(",", ncloud_server.server.*.name)
}

5. variables.tf 파일을 생성한 후, 인증 부분은 네이버 클라우드 플랫폼 마이페이지> 계정관리> 인증키 관리에서 신규 API 인증키를 생성하여 사용합니다(기존 갖고 있던 인증키를 사용하셔도 됩니다) 이후 variables.tf 파일을 구현 합니다.

인증키 관리 UI

주의 : access_key 와 secret_key는 본인이 생성한 키를 입력 해야 합니다. 아래의 기본값은 예제 이며, 꼭 본인의 인증키로 수정해야 사용이 가능합니다. variables.tf

variable "access_key" { # export TF_VAR_access_key=...
default = "UtklulMqQ9GHldCBhFCa"
}
variable "secret_key" { # export TF_VAR_secret_key=...
default = "VLlAXVlLMlcLxgOW0DYg7TaMDsoLlJNqz0JDo2Do"
}
variable "region" {
default = "KR"
}
variable "zone" {
default = "KR-2"
}
variable "login_key_name" {
default = "tf-test-key"
}
variable "server_name" {
default = "tf-test-vm"
}
variable "server_image_product_code" { # centos-7.3-64
default = "SPSW0LINUX000046"
}
variable "server_product_code" { # vCPU 2EA, Memory 4GB, Disk 50GB
default = "SPSVRSTAND000004" #SPSVRSTAND000056
}
variable "port_forwarding_external_port" {
default = "5088"
}

6. version.tf 파일을 생성 하고, 구현 합니다.

versions.tf

terraform {
required_version = ">= 0.13"
required_providers {
ncloud = {
source = "terraform-providers/ncloud"
}
null = {
source = "hashicorp/null"
}
random = {
source = "hashicorp/random"
}
}
}

7. centos 7에는 nginx 관련 리파지토리가 없기 때문에 자동화로 생성될 서버에 해당 리파지토리를 포함시키기 위해 repo 파일을 생성 합니다.

nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

8. terraform destroy 명령 후, 불필요한 파일을 삭제 하기 위한 스크립트입니다.

destory_clean.sh

rm -rf inventory terraform.tfstate terraform.tfstate.backup

9. playbook.yml 파일을 생성 하여 구현하며, git과 nginx 파일을 설치 하기 위해 구성한 ansible playbook 입니다.

playbook.yml

---
- hosts: ncloud
become: true
tasks:
- name: ping
ping:
- name: enable ngnix repo
copy:
src: nginx.repo
dest: /etc/yum.repos.d/nginx.repo
owner: root
group: root
mode: '0644'
backup: yes
- name: install packages
yum:
name: "{{ packages }}"
state: latest
update_cache: yes
vars:
packages:
- git
- nginx
- name: Make sure a service is running
systemd:
state: started
name: nginx
enabled: yes
- name: Download the nginx package for backup version but do not install it
yum:
name: "{{ packages }}"
state: latest
download_only: true
vars:
packages:
- git
- nginx

파일을 다 구현하면 디렉토리에는 아래와 같은 파일이 구성됩니다.

# ls 
destory_clean.sh main.tf nginx.repo outputs.tf playbook.yml variables.tf versions.tf

10. terraform init 명령을 통해, 네이버 클라우드 플랫폼에서 사용할 수 있도록 플러그인들을 다운 받아 현재 디렉토리에서 진행 합니다.

# terraform initInitializing the backend...Initializing provider plugins...
- Finding latest version of hashicorp/null...
- Finding latest version of hashicorp/random...
- Finding latest version of terraform-providers/ncloud...
- Installing terraform-providers/ncloud v1.3.1...
- Installed terraform-providers/ncloud v1.3.1 (signed by HashiCorp)
- Installing hashicorp/null v2.1.2...
- Installed hashicorp/null v2.1.2 (signed by HashiCorp)
- Installing hashicorp/random v2.3.0...
- Installed hashicorp/random v2.3.0 (signed by HashiCorp)
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, we recommend adding version constraints in a required_providers block
in your configuration, with the constraint strings suggested below.
* hashicorp/null: version = "~> 2.1.2"
* hashicorp/random: version = "~> 2.3.0"
* terraform-providers/ncloud: version = "~> 1.3.1"
Warning: Additional provider information from registryThe remote registry returned warnings for
registry.terraform.io/terraform-providers/ncloud:
- For users on Terraform 0.13 or greater, this provider has moved to
NaverCloudPlatform/ncloud. Please update your source in required_providers.
Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

11. terraform plan 명령을 통해 HCL 로 구성된 내용이 네이버 클라우드 플랫폼 자원에 적용이 가능한지 여부를 확인합니다. plan이라 실제 적용은 현재 단계에서 진행되지 않습니다.

# terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions: # data.ncloud_port_forwarding_rules.rules will be read during apply
# (config refers to values not yet known)
<= data "ncloud_port_forwarding_rules" "rules" {
+ id = "59497"
+ port_forwarding_configuration_no = "59497"
+ port_forwarding_rule_list = [
+ {
+ port_forwarding_external_port = "9987"
+ port_forwarding_internal_port = "22"
+ port_forwarding_public_ip = "106.10.55.207"
+ server_instance_no = "4544974"
},
+ {
+ port_forwarding_external_port = "9986"
+ port_forwarding_internal_port = "22"
+ port_forwarding_public_ip = "106.10.55.207"
+ server_instance_no = "4533453"
},
+ {
+ port_forwarding_external_port = "9981"
+ port_forwarding_internal_port = "22"
+ port_forwarding_public_ip = "106.10.55.207"
+ server_instance_no = "4087698"
},
+ {
+ port_forwarding_external_port = "2002"
+ port_forwarding_internal_port = "22"
+ port_forwarding_public_ip = "106.10.55.207"
+ server_instance_no = "2975238"
},
+ {
+ port_forwarding_external_port = "9980"
+ port_forwarding_internal_port = "22"
+ port_forwarding_public_ip = "106.10.55.207"
+ server_instance_no = "2952586"
},
]
+ zone = "KR-2"
}
# data.ncloud_root_password.rootpwd will be read during apply
# (config refers to values not yet known)
<= data "ncloud_root_password" "rootpwd" {
+ id = (known after apply)
+ private_key = (sensitive value)
+ root_password = (sensitive value)
+ server_instance_no = (known after apply)
}
# ncloud_login_key.key will be created
+ resource "ncloud_login_key" "key" {
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = (known after apply)
+ private_key = (sensitive value)
}
# ncloud_port_forwarding_rule.forwarding will be created
+ resource "ncloud_port_forwarding_rule" "forwarding" {
+ id = (known after apply)
+ port_forwarding_configuration_no = "59497"
+ port_forwarding_external_port = 5088
+ port_forwarding_internal_port = 22
+ port_forwarding_public_ip = (known after apply)
+ server_instance_no = (known after apply)
+ zone = (known after apply)
}
# ncloud_public_ip.public_ip will be created
+ resource "ncloud_public_ip" "public_ip" {
+ id = (known after apply)
+ instance_no = (known after apply)
+ instance_operation = (known after apply)
+ instance_status = (known after apply)
+ instance_status_name = (known after apply)
+ internet_line_type = (known after apply)
+ kind_type = (known after apply)
+ public_ip = (known after apply)
+ server_instance_no = (known after apply)
+ zone = (known after apply)
}
# ncloud_server.server will be created
+ resource "ncloud_server" "server" {
+ base_block_storage_disk_detail_type = (known after apply)
+ base_block_storage_disk_type = (known after apply)
+ base_block_storage_size = (known after apply)
+ cpu_count = (known after apply)
+ id = (known after apply)
+ instance_no = (known after apply)
+ instance_operation = (known after apply)
+ instance_status = (known after apply)
+ instance_status_name = (known after apply)
+ internet_line_type = (known after apply)
+ is_fee_charging_monitoring = (known after apply)
+ login_key_name = (known after apply)
+ memory_size = (known after apply)
+ name = (known after apply)
+ platform_type = (known after apply)
+ port_forwarding_external_port = (known

12. terraform apply -auto-approve 명령을 실행하여, 실제 네이버 클라우드 플랫폼에 HCL 내용을 반영 합니다.

# terraform apply -auto-approve
random_id.id: Creating...
random_id.id: Creation complete after 0s [id=tlVNwg]
ncloud_login_key.key: Creating...
ncloud_login_key.key: Creation complete after 1s [id=tf-test-keyb6554dc2]
ncloud_server.server: Creating...
ncloud_server.server: Still creating... [10s elapsed]
ncloud_server.server: Still creating... [20s elapsed]
ncloud_server.server: Still creating... [30s elapsed]
ncloud_server.server: Still creating... [40s elapsed]
ncloud_server.server: Still creating... [50s elapsed]
ncloud_server.server: Still creating... [1m0s elapsed]
ncloud_server.server: Still creating... [1m10s elapsed]
ncloud_server.server: Still creating... [1m20s elapsed]
ncloud_server.server: Still creating... [1m30s elapsed]
ncloud_server.server: Still creating... [1m40s elapsed]
ncloud_server.server: Still creating... [1m50s elapsed]
ncloud_server.server: Still creating... [2m0s elapsed]
ncloud_server.server: Still creating... [2m10s elapsed]
ncloud_server.server: Still creating... [2m20s elapsed]
ncloud_server.server: Still creating... [2m30s elapsed]
ncloud_server.server: Still creating... [2m40s elapsed]
ncloud_server.server: Still creating... [2m50s elapsed]
ncloud_server.server: Still creating... [3m0s elapsed]
ncloud_server.server: Still creating... [3m10s elapsed]
ncloud_server.server: Still creating... [3m20s elapsed]
ncloud_server.server: Still creating... [3m30s elapsed]
ncloud_server.server: Still creating... [3m40s elapsed]
ncloud_server.server: Creation complete after 3m46s [id=4984486]
data.ncloud_port_forwarding_rules.rules: Reading...
data.ncloud_port_forwarding_rules.rules: Read complete after 0s [id=59497]
data.ncloud_root_password.rootpwd: Reading...
ncloud_port_forwarding_rule.forwarding: Creating...
ncloud_public_ip.public_ip: Creating...
data.ncloud_root_password.rootpwd: Read complete after 0s [id=4984486]
ncloud_port_forwarding_rule.forwarding: Creation complete after 1s [id=59497:3:5088]
null_resource.ssh: Creating...
null_resource.ssh: Provisioning with 'local-exec'...
null_resource.ssh (local-exec): Executing: ["/bin/sh" "-c" " echo \"[ncloud]\" > inventory\n echo \"tf-test-vmb6554dc2 ansible_host='106.10.55.207' ansible_port='5088' ansible_ssh_user=root ansible_ssh_pass='U7rN%GM6B8e'\" >> inventory\n \n"]
null_resource.ssh: Provisioning with 'local-exec'...
null_resource.ssh (local-exec): Executing: ["/bin/sh" "-c" " ANSIBLE_HOST_KEY_CHECKING=False \\\n ansible-playbook -i inventory playbook.yml\n \n"]
null_resource.ssh (local-exec): PLAY [ncloud] ******************************************************************
null_resource.ssh (local-exec): TASK [Gathering Facts] *********************************************************
ncloud_public_ip.public_ip: Creation complete after 3s [id=4984491]
null_resource.ssh (local-exec): ok: [tf-test-vmb6554dc2]
null_resource.ssh (local-exec): TASK [ping] ********************************************************************
null_resource.ssh (local-exec): ok: [tf-test-vmb6554dc2]
null_resource.ssh (local-exec): TASK [enable ngnix repo] *******************************************************
null_resource.ssh (local-exec): changed: [tf-test-vmb6554dc2]
null_resource.ssh (local-exec): TASK [install packages] ********************************************************
null_resource.ssh: Still creating... [10s elapsed]
null_resource.ssh: Still creating... [20s elapsed]
null_resource.ssh: Still creating... [30s elapsed]
null_resource.ssh (local-exec): changed: [tf-test-vmb6554dc2]
null_resource.ssh (local-exec): TASK [Make sure a service is running] ******************************************
null_resource.ssh (local-exec): changed: [tf-test-vmb6554dc2]
null_resource.ssh (local-exec): TASK [Download the nginx package for backup version but do not install it] *****
null_resource.ssh (local-exec): ok: [tf-test-vmb6554dc2]
null_resource.ssh (local-exec): PLAY RECAP *********************************************************************
null_resource.ssh (local-exec): tf-test-vmb6554dc2 : ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
null_resource.ssh: Creation complete after 40s [id=1216997761449594906]
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
server_name_list = tf-test-vmb6554dc2

13. 공인 ip를 확인한 후, http 가 연결 되는지 확인합니다.

14. 자원을 회수하기 위해서 terraform destroy -auto-approve 명령을 통하여, 네이버 클라우드 플랫폼 자원을 반환합니다.

# terraform destroy -auto-approve
random_id.id: Refreshing state... [id=tlVNwg]
ncloud_login_key.key: Refreshing state... [id=tf-test-keyb6554dc2]
ncloud_server.server: Refreshing state... [id=4984486]
data.ncloud_port_forwarding_rules.rules: Refreshing state... [id=59497]
data.ncloud_root_password.rootpwd: Refreshing state... [id=4984486]
ncloud_public_ip.public_ip: Refreshing state... [id=4984491]
ncloud_port_forwarding_rule.forwarding: Refreshing state... [id=59497:3:5088]
null_resource.ssh: Refreshing state... [id=1216997761449594906]
null_resource.ssh: Destroying... [id=1216997761449594906]
null_resource.ssh: Destruction complete after 0s
ncloud_public_ip.public_ip: Destroying... [id=4984491]
ncloud_port_forwarding_rule.forwarding: Destroying... [id=59497:3:5088]
ncloud_port_forwarding_rule.forwarding: Destruction complete after 1s
ncloud_public_ip.public_ip: Destruction complete after 5s
ncloud_server.server: Destroying... [id=4984486]
ncloud_server.server: Still destroying... [id=4984486, 10s elapsed]
ncloud_server.server: Destruction complete after 18s
ncloud_login_key.key: Destroying... [id=tf-test-keyb6554dc2]
ncloud_login_key.key: Destruction complete after 3s
random_id.id: Destroying... [id=tlVNwg]
random_id.id: Destruction complete after 0s
Destroy complete! Resources: 6 destroyed.

구성에 대한 자세한 설명은 아래의 링크를 참조 바랍니다.

--

--

NAVER Cloud
NAVER Cloud

We provide cloud-based information technology services for industry leaders from startups to enterprises.