이전 글에서 Terraform의 provisioner를 설명했는데 간단한 프로비저닝은 local-exec
나 remote-exec
를 사용하면 되지만 보통은 프로비저닝할 때 더 많은 작업을 해야 하므로 이 둘만으로는 충분하지 않고 개인적으로 Terraform에서 전부 다 하는 게 좋다고 보지도 않는다. 프로비저닝을 할 수 있는 도구가 많지만, 최근에 내가 많이 써보려고 하는 Ansible과 연동을 해보고 있다.
일단 EC2 인스턴스를 생성해야 하므로 다음과 같은 간단한 tf 파일을 만든다.
resource "aws_instance" "demo" {
ami = "ami-d39a02b5" # ubuntu 16.04
instance_type = "t2.nano"
subnet_id = "subnet-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
key_name = "your-key-pair"
connection {
user = "ubuntu"
type = "ssh"
private_key = "${file("~/.ssh/your_private_key.pem")}"
timeout = "2m"
}
provisioner "remote-exec" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y python",
]
}
}
이전 글에서 본 내용과 거의 같으므로 자세한 내용은 이전 글을 참고한다. 여기서는 Ubuntu를 사용했는데 접속한 뒤 remote-exec
로 Python만 설치했다. Ansible을 사용할 때 타겟 머신에 Python은 설치되어 있어야 한다. 없으면 MODULE FAILURE
오류가 발생한다.
resource "aws_instance" "demo" {
# 생략
provisioner "remote-exec" {
# 생략
}
provisioner "local-exec" {
command = <<EOF
echo "[demo]" > inventory
echo "${aws_instance.demo.public_ip} ansible_ssh_user=ubuntu ansible_ssh_private_key_file=~/.ssh/your_private_key.pem" >> inventory
EOF
}
provisioner "local-exec" {
command = <<EOF
ANSIBLE_HOST_KEY_CHECKING=False \
ansible-playbook -i inventory playbook.yml
EOF
}
}
원격 서버 설정은 끝났으므로 이번에는 local-exec
를 사용했다. 2번 사용한 것은 그냥 긴 명령어를 보기 좋게 작성하기 위해서다. 로컬에서 Ansible을 실행해서 원격 서버에 접속하는 것이므로 local-exec
를 사용한 것이다. 이 말은 로컬 머신에는 Ansible이 설치되어 있어야 한다는 의미이다.
위 명령어를 좀 더 설명하면 Ansible이 서버를 인식할 수 있도록 inventory
파일을 생성한 것이다. 서버를 생성하면서 만들어진 퍼블릭 IP를 이용해서 필요한 파라미터를 지정해서 인벤토리 파일을 만드는데 아래와 같은 형태가 된다. 서버를 만들 때마다 IP가 바뀌므로 자동으로 생성되게 한 것이다.
[demo]
54.95.180.208 ansible_ssh_user=ubuntu ansible_ssh_private_key_file=~/.ssh/your_private_key.pem
두 번째로 나온 local-exec
에서 실제로 ansible-playbook
을 실행하는데 ANSIBLE_HOST_KEY_CHECKING=False
환경변수는 SSH로 접속할 때 호스트 서버를 확인하는 프롬프트가 나오지 않도록 지정한 것이다. 이게 있으면 terraform apply
중에 프롬프트를 기다리느라 결국 실패하거나 사용자가 입력을 해야 하게 된다. ansible-playbook -i inventory playbook.yml
에서 앞에서 만든 인벤토리 파일을 지정하고 실제 프로비저닝의 내용이 있는 playbook.yml
을 사용하게 했다. 이 글에서 playbook.yml
의 내용은 중요치 않지만, 예제를 위해 다음과 같이 git과 nginx를 설치하도록 간단히 작성했다.
---
- hosts: demo
tasks:
- name: ping
ping:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
become: true
- name: install nginx
apt: name={{ item }} update_cache=yes state=latest
with_items:
- nginx
become: true
이 테라폼 파일을 실행하면 아래와 같이 Ansible과 자동으로 연동되어 git과 nginx를 설치하는 것을 볼 수 있다.
$ terraform apply
aws_instance.demo: Creating...
ami: "" => "ami-d39a02b5"
associate_public_ip_address: "" => "<computed>"
availability_zone: "" => "<computed>"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_state: "" => "<computed>"
instance_type: "" => "t2.nano"
ipv6_address_count: "" => "<computed>"
ipv6_addresses.#: "" => "<computed>"
key_name: "" => "outsider-aws"
network_interface.#: "" => "<computed>"
network_interface_id: "" => "<computed>"
placement_group: "" => "<computed>"
primary_network_interface_id: "" => "<computed>"
private_dns: "" => "<computed>"
private_ip: "" => "<computed>"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "1"
security_groups.541019735: "" => "sg-247b2042"
source_dest_check: "" => "true"
subnet_id: "" => "subnet-2784b551"
tenancy: "" => "<computed>"
volume_tags.%: "" => "<computed>"
vpc_security_group_ids.#: "" => "<computed>"
aws_instance.demo: Still creating... (10s elapsed)
aws_instance.demo: Provisioning with 'remote-exec'...
aws_instance.demo (remote-exec): Connecting to remote host via SSH...
aws_instance.demo (remote-exec): Host: 54.95.180.208
aws_instance.demo (remote-exec): User: ubuntu
aws_instance.demo (remote-exec): Password: false
aws_instance.demo (remote-exec): Private key: true
aws_instance.demo (remote-exec): SSH Agent: true
aws_instance.demo (remote-exec): Connected!
aws_instance.demo (remote-exec): Setting up libpython2.7-stdlib:amd64 (2.7.12-1ubuntu0~16.04.3) ...
aws_instance.demo (remote-exec): Setting up python2.7 (2.7.12-1ubuntu0~16.04.3) ...
aws_instance.demo (remote-exec): Setting up libpython-stdlib:amd64 (2.7.11-1) ...
aws_instance.demo (remote-exec): Setting up python (2.7.11-1) ...
aws_instance.demo: Provisioning with 'local-exec'...
aws_instance.demo (local-exec): Executing: ["/bin/sh" "-c" " echo \"[demo]\" > inventory\n echo \"54.95.180.208 ansible_ssh_user=ubuntu ansible_ssh_private_key_file=~/.ssh/outsider-aws.pem\" >> inventory\n "]
aws_instance.demo: Provisioning with 'local-exec'...
aws_instance.demo (local-exec): Executing: ["/bin/sh" "-c" " ANSIBLE_HOST_KEY_CHECKING=False \\\n ansible-playbook -i inventory playbook.yml\n "]
aws_instance.demo: Still creating... (40s elapsed)
aws_instance.demo (local-exec): PLAY [demo] ********************************************************************
aws_instance.demo (local-exec): TASK [Gathering Facts] *********************************************************
aws_instance.demo (local-exec): ok: [54.95.180.208]
aws_instance.demo (local-exec): TASK [ping] ********************************************************************
aws_instance.demo (local-exec): ok: [54.95.180.208]
aws_instance.demo (local-exec): TASK [install packages] ********************************************************
aws_instance.demo (local-exec): ok: [54.95.180.208] => (item=['git'])
aws_instance.demo (local-exec): TASK [install nginx] ***********************************************************
aws_instance.demo (local-exec): changed: [54.95.180.208] => (item=['nginx'])
aws_instance.demo (local-exec): PLAY RECAP *********************************************************************
aws_instance.demo (local-exec): 54.95.180.208 : ok=4 changed=1 unreachable=0 failed=0
aws_instance.demo: Creation complete after 55s (ID: i-0116967d4db9e1946)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
이제 이후부터는 ansible을 어떻게 사용할지만 고민하면 된다.
Comments