Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Terraform으로 Digital Ocean의 Droplet 생성하기

Digital Ocean을 쓴지 5년 정도 되었지만 잘 관리하고 있지는 않다. 이번에 AWS에 올렸던 리소스를 다시 Digital Ocean으로 이사할 준비를 하면서 기존에 운영하던 블로그도 새로 세팅해 보려고 하고 있다.

Digital Ocean에서는 서버를 Droplet이라고 부르는데 요즘 Infrastructure as Code에 꽂혀 있어서 Digital Ocean도 Terraform에서 지원하므로 Terraform을 그대로 이용하기로 했다. 그 이전에는 거의 AWS에서만 Terraform을 사용해 봤다.

개인 서버는 회사에서처럼 다수를 띄우는 것도 아니고 누군가와 협업해야 할 필요는 없지만 Infrastructure as Code로 서버를 구성했을 때 가장 좋은 점 중 하나는 재현할 수 있다는 것이다. 서버 설정을 직접 다 했다고 하더라도 항상 외우고 있는 것도 아니므로 이후 변경하거나 개선하기도 쉬워지고 처음 설정할 때는 한 번에 끝까지 설정하기가 어려워서 틈틈이 하게 되는데 Terraform으로 다 관리하고 있으면 Droplet을 띄워서 설정 테스트를 한 후 다음 작업할 때까지 내려놓으면 과금도 안 되고 좋다. 이후 작업할 때도 다시 실행만 하면 되니까... 이렇게 안 하면 Image를 매번 만들어서 띄워두어야 한다.

Digital Ocean 프로바이더 설정

Digital Ocean을 이용하려면 API 토큰을 발급받아야 한다.

Digital Ocean의 API 토큰 생성 화면

위 화면에서 토큰을 생성한 뒤 아래처럼 프로바이더 설정을 한다.

variable "do_token" {}

provider "digitalocean" {
  version = "~> 0.1"
  token   = "${var.do_token}"
}

여기서 API 토큰을 tf 파일에 하드 코딩할 수는 없으므로 환경변수로 설정해 두는 것이 편하다. 위에서 변수 이름이 do_token이므로 TF_VAR_do_token이라는 환경변수로 지정하면 Terraform 변수에 할당된다.

프로바이더 설정이 끝났으므로 terraform init로 초기화한다.(여기서는 Terraform v0.11.1을 사용했다.)

$ terraform init

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "digitalocean" (0.1.3)...

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.


Droplet 구성

AWS에 비해 Digital Ocean은 훨씬 간단하므로 문서를 보면 금방 작성할 수 있다. 아래는 Ubuntu 17.04로 싱가포르 서버에 Droplet을 띄우는 설정이다.

resource "digitalocean_droplet" "demo" {
  image      = "ubuntu-17-04-x64"
  name       = "demo"
  region     = "sgp1"
  size       = "512mb"
  monitoring = true
  ipv6       = true
  ssh_keys   = ["aa:bb:cc:dd:ee"]
}

여기서 지정하는 region이나 size의 이름은 API 문서를 참고해서 여기서 사용하는 값을 쓰면 된다. ssh_keys 키 같은 경우는 이미 Digital Ocean에 등록해 놓은 SSH 키의 핑거프린트(혹은 id)를 지정하면 되는데 이는 SSH 키 조회 API에서 찾을 수 있다. 발급받은 API 키로 아래처럼 조회하면 SSH 키의 핑커프린트나 ID를 확인할 수 있다.

$ curl -X GET \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://api.digitalocean.com/v2/account/keys" | \
  jq .ssh_keys

[
  {
    "id": 1234,
    "fingerprint": "aa:bb:cc:dd:ee",
    "public_key": "ssh-rsa xxxxxxx your-email-address",
    "name": "my key"
  }
]


Droplet 프로비저닝

Droplet을 실행하는 게 끝이 아니므로 서버를 프로비저닝해야 한다. 서버에 환경 설정을 해야 하는데 여기에는 Ansible같은 도구가 더 적합하므로 Terraform에서는 SSH 계정을 추가하는 기본적인 프로비저닝만 하기로 했다.

variable "do_private_key" {}
variable "do_public_key" {}

variable "do_username" {
  default = "demo"
}
variable "do_password" {}

resource "digitalocean_droplet" "demo" {
  # 앞에서 설정한 부분 생략

  connection {
    user        = "root"
    type        = "ssh"
    private_key = "${file(var.do_private_key)}"
    timeout     = "2m"
  }

  provisioner "remote-exec" {
    inline = [
      "export PATH=$PATH:/usr/bin",
      "adduser --disabled-password --gecos '' ${var.do_username}",
      "echo ${var.do_username}:${var.do_password} | chpasswd",
      "echo '${var.do_username} ALL=(ALL:ALL) ALL' | sudo EDITOR='tee -a' visudo",
      "mkdir /home/${var.do_username}/.ssh",
      "chown ${var.do_username}:${var.do_username} /home/${var.do_username}/.ssh",
      "echo '${file(var.do_public_key)}' > /home/${var.do_username}/.ssh/authorized_keys",
    ]
  }
}

4개의 변수를 추가하고 connectionremote-exec 프로비저너를 추가했다. connection 설정으로 SSH 접속한 뒤에 remote-exec에 지정한 명령어를 실행한다.

do_public_keydo_private_key 환경변수에 사용할 퍼블릭/프라이빗 키의 경로를 지정한다.

export TF_VAR_do_public_key=$HOME/.ssh/id_rsa.pub
export TF_VAR_do_private_key=$HOME/.ssh/id_rsa

${file(var.do_private_key)}처럼 terraform에서 사용하므로 이 파일의 내용을 읽어서 사용하게 된다.

remote-exec에서 지정한 명령어는 SSH 접속 뒤 차례대로 실행되는데 root 계정 대신 새로 만든 계정을 사용하도록 do_username에 지정한 계정을 만들고 /etc/sudoers 파일에 추가하고 퍼블릭 SSH 키를 ~/.ssh/authorized_keys에 추가해서 접속할 수 있게 한 것이다. 인터렉티프 모드로 입력하도록 하면 여기서 프로비저닝을 할 수 없으므로 한 번에 실행되도록 하다 보니 명령어가 좀 복잡해졌다.

이를 실행하면 Droplet 생성 후 프로비저닝까지 하는 것을 볼 수 있다.

$ terraform apply

digitalocean_droplet.demo: Creating...
  disk:                 "" => "<computed>"
  image:                "" => "ubuntu-17-04-x64"
  ipv4_address:         "" => "<computed>"
  ipv4_address_private: "" => "<computed>"
  ipv6:                 "" => "true"
  ipv6_address:         "" => "<computed>"
  ipv6_address_private: "" => "<computed>"
  locked:               "" => "<computed>"
  monitoring:           "" => "true"
  name:                 "" => "demo"
  price_hourly:         "" => "<computed>"
  price_monthly:        "" => "<computed>"
  region:               "" => "sgp1"
  resize_disk:          "" => "true"
  size:                 "" => "512mb"
  ssh_keys.#:           "" => "1"
  ssh_keys.0:           "" => "5c:62:af:d8:28:72:d7:36:eb:29:47:ec:7d:90:8d:28"
  status:               "" => "<computed>"
  vcpus:                "" => "<computed>"
digitalocean_droplet.demo: Still creating... (10s elapsed)
digitalocean_droplet.demo: Provisioning with 'remote-exec'...
digitalocean_droplet.demo (remote-exec): Connecting to remote host via SSH...
digitalocean_droplet.demo (remote-exec):   Host: 174.138.20.103
digitalocean_droplet.demo (remote-exec):   User: root
digitalocean_droplet.demo (remote-exec):   Password: false
digitalocean_droplet.demo (remote-exec):   Private key: true
digitalocean_droplet.demo (remote-exec):   SSH Agent: true
digitalocean_droplet.demo (remote-exec): Connected!
digitalocean_droplet.demo (remote-exec): Adding user `demo' ...
digitalocean_droplet.demo (remote-exec): Adding new group `demo' (1000) ...
digitalocean_droplet.demo (remote-exec): Adding new user `demo' (1000) with group `demo' ...
digitalocean_droplet.demo (remote-exec): Creating home directory `/home/demo' ...
digitalocean_droplet.demo (remote-exec): Copying files from `/etc/skel' ...
digitalocean_droplet.demo (remote-exec): demo ALL=(ALL:ALL) ALL
digitalocean_droplet.demo: Creation complete after 1m4s (ID: 76374504)

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.


Digital Ocean에서 생성된 droplet

Digital Ocean에서 생성된 것을 확인할 수 있다.

$ ssh demo@174.138.20.103
Welcome to Ubuntu 17.04 (GNU/Linux 4.10.0-40-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

31 packages can be updated.
18 updates are security updates.

New release '17.10' available.
Run 'do-release-upgrade' to upgrade to it.


Last login: Mon Dec 25 10:29:36 2017 from 183.98.70.31
demo@demo:~$ sudo -s
[sudo] password for demo:
root@demo:~#

확인한 IP로 접속해 보면 프로비저닝한 계정이 잘 동작하는 것을 확인할 수 있다.

2017/12/25 19:40 2017/12/25 19:40