테라폼 프로비저너
Terraform 카테고리는 CloudNet 가시다 님 기획으로 진행되는
<Terraform101 스터디 2기>
공부 내용과 과제 수행을 기록하기 위해 마련되었습니다.
스터디 일람
주차 | 주제 | 과제 내용 | 깃허브 |
1주차 (23.07.03 ~ 09) | 테라폼 기본 사용 1/3 | - | 링크 |
2주차 (23.07.10 ~ 16) | 테라폼 기본 사용 2/3 data, locals, variable, for loops |
커스텀 VPC에 EC2 띄어보기 | 링크 |
⛳ 3주차 (23.07.17 ~ 23) | 테라폼 기본 사용 3/3 provisioner, provider |
프로비저너 | - |
개요
금주는 별도 연구 주제를 선정하고 테스트 할 경황이 없어서 provisioner에 관한 Terraform 공식 문서를 읽어보고 정리해 보는 시간을 가졌습니다.
프로비저너 타입
- provisioner "file": 파일 복사
- provisioner "local_exec": local 머신에서 명령어 실행
- provisioner "remote_exec": 원격지 머신에서 명령어 실행
부모 자원 참조 (self)
resource "aws_instance" "web" {
# ...
provisioner "local-exec" {
command = "echo The server's IP address is ${self.private_ip}"
}
}
proviosioner는 자신을 포함하고 있는 부모 자원을 참조할 때, self를 사용한다.
provisioner "file"
file 프로비저너는 Terraform을 실행하고 있는 시스템에 존재하는 파일이나 폴더를 생성하는 리소스로 복사하는 데 이용된다.
file 프로비저너는 ssh 및 winrm 연결을 지원한다.
인수
- source - 원본 파일 또는 폴더이다. 현재 모듈 위치에 대한 상대 경로나, 절대 경로로 파일이나 디렉토리를 지정한다. content 속성과 함께 쓰지 않는다.
- content - 목적지로 복사할 내용이다. source와 같이 쓰지 않는다. 대상이 파일이면 content 내용이 해당 파일로 기록된다. 대상이 디렉토리이면 경우 tf-file-content 파일이 생성된다.
- destination - 목적지 경로이다. 절대 경로를 작성해야 한다. (필수)
resource "aws_instance" "web" {
# ...
# Copies the myapp.conf file to /etc/myapp.conf
provisioner "file" {
source = "conf/myapp.conf"
destination = "/etc/myapp.conf"
}
# Copies the string in content into /tmp/file.log
provisioner "file" {
content = "ami used: ${self.ami}"
destination = "/tmp/file.log"
}
# Copies the configs.d folder to /etc/configs.d
provisioner "file" {
source = "conf/configs.d"
destination = "/etc"
}
# Copies all files and folders in apps/app1 to D:/IIS/webapp1
provisioner "file" {
source = "apps/app1/"
destination = "D:/IIS/webapp1"
}
}
provisioner "local_exec"
local-exec 프로비저너는 리소스가 생성된 후 스크립트를 수행한다. Terraform을 실행하는 로컬 시스템의 프로세스를 호출하는 것이다.
인수
- command - 실행할 명령어이다. 현재 모듈에 대한 상대 경로 또는 절대 경로이다. Shell 명령어로서 평가되며 환경변수와 Terraform 변수 역시 활용 가능하다. (필수)
- working_dir - 명령이 실행될 워킹 디렉터리를 지정한다. 상대 경로 또는 절대 경로로 제공될 수 있다.
- interpreter - 명령을 실행하는 인터프리터에게 추가 인수를 전달할 목적으로 사용한다. 예를 들어 ["/bin/bash", "-c", "echo foobar"] 명령줄을 작성할 수 있다. 선택 인수이므로, 따로 명시하지 않으면 OS에 따라 기본적인 인터프리터가 선택된다.
- environment - 환경 변수를 전달한다. 현재 프로세스의 환경변수를 상속 받는다. (관련해서 테스트 해보아야 겠다..)
- when - 언제 명령을 실행할지 결정한다. destroy | on_failure
resource "aws_instance" "web" {
# ...
provisioner "local-exec" {
command = "echo $FOO $BAR $BAZ >> env_vars.txt"
environment = {
FOO = "bar"
BAR = 1
BAZ = "true"
}
}
}
provisioner "remote_exec"
remote-exec 프로비저너는 리소스가 생성된 이후 원격에서 스크립트를 호출한다. Ansible 같은 구성관리 도구를 실행하고 초기환경을 부트스트랩하는 등의 작업에 사용할 수 있다.
인수
- inline - 실행할 명령어들을 나열할 경우 inline 속성에 리스트로 작성한다.
- script - 명령어를 담은 하나의 스크립트 파일을 실행할 경우이다. 스크립트 위치를 현재 모듈에 대한 상대 경로 또는 절대 경로를 작성한다.
- scripts - 여러 스크립트 파일을 실행하는 것도 가능하다!
resource "aws_instance" "web" {
# ...
provisioner "file" { # 원격지로 스크립트 파일을 전송함.
source = "script.sh"
destination = "/tmp/script.sh"
}
provisioner "remote-exec" { # 원격지에서 전송한 스크립트를 실행함.
inline = [
"chmod +x /tmp/script.sh",
"/tmp/script.sh args",
]
}
}
프로비저너 연결 설정
Provisioner Connection Settings
- 프로비저너 특성을 보았듯이 file과 remote-exec 프로비저너는 원격지로 파일을 전송하거나 명령을 실행하기 때문에, 원격 호스트와 연결이 필요하다.
- 이런 연결에 관한 명세는 자원 내부에 connection 블럭을 통한다.
connection {
type = "ssh"
user = "root"
password = "${var.root_password}"
host = "${var.host}"
}
인수
인수명 | type | 설명 | 기본값 |
type | 둘다 | The connection type. Valid values are "ssh" and "winrm". Provisioners typically assume that the remote system runs Microsoft Windows when using WinRM. Behaviors based on the SSH target_platform will force Windows-specific behavior for WinRM, unless otherwise specified. | ssh |
user | 둘다 | The user to use for the connection. | - ssh이면 root - winrm이면 Administrator |
password | 둘다 | The password to use for the connection. | |
host | 둘다 | The address of the resource to connect to. (필수) | |
port | 둘다 | The port to connect to. | - ssh이면 22 - winrm이면 5985 |
timeout | 둘다 | The timeout to wait for the connection to become available. Should be provided as a string (e.g., "30s" or "5m".) | 5m (5분) |
script_path | 둘다 | The path used to copy scripts meant for remote execution. Refer to How Provisioners Execute Remote Scripts below for more details. | |
private_key | SSH | The contents of an SSH key to use for the connection. These can be loaded from a file on disk using the file function. This takes preference over password if provided. | |
certificate | SSH | The contents of a signed CA Certificate. The certificate argument must be used in conjunction with a private_key. These can be loaded from a file on disk using the the file function. | |
agent | SSH | Set to false to disable using ssh-agent to authenticate. On Windows the only supported SSH authentication agent is Pageant. | |
agent_identity | SSH | The preferred identity from the ssh agent for authentication. | |
host_key | SSH | The public key from the remote host or the signing CA, used to verify the connection. | |
target_platform | SSH | The target platform to connect to. Valid values are "windows" and "unix". If the platform is set to windows, the default script_path is c:\windows\temp\terraform_%RAND%.cmd, assuming the SSH default shell is cmd.exe. If the SSH default shell is PowerShell, set script_path to "c:/windows/temp/terraform_%RAND%.ps1" | unix |
https | WinRM | Set to true to connect using HTTPS instead of HTTP. | |
insecure | WinRM | Set to true to skip validating the HTTPS certificate chain. | |
use_ntlm | WinRM | Set to true to use NTLM authentication rather than default (basic authentication), removing the requirement for basic authentication to be enabled within the target guest. Refer to Authentication for Remote Connections in the Windows App Development documentation for more details. | |
cacert | WinRM | The CA certificate to validate against. |
각 프로비저너에 대한 연결 설정
provisioner "file" {
connection {
type = "ssh"
user = "root"
password = var.root_password
host = self.public_ip
}
}
위 스니펫은 file 프로비저너에 대한 연결을 명세하고 있다.
자원 수준에서의 연결 설정
provisioner "file" {
}
provisioner "remote-exec" {
}
connection {
}
connection 블록을 자원 수준에서 선언하면, 모든 프로비저너에게 같은 연결 설정을 적용한다.
SSH & Key 인증으로 EC2 연결해 보기
키 기반 인증으로 SSH 접속을 명세하기 위해 connection 블록을 작성해 보겠다.
일단 aws_key_pair 자원을 생성해 준다. AWS 키-페어를 만드는 과정을 이 문서에서 참고할 수 있다.
퍼블릭 키 내용을 문자열로 직접 입력하거나, file 데이터 소스를 쓰거나, file() 함수를 사용해 가져온다.
resource "aws_key_pair" "kepr" {
key_name = "kepr-temp"
public_key = "<퍼블릭 키 내용>"
}
# 또는
resource "aws_key_pair" "kepr" {
key_name = "kepr-temp"
public_key = file("~/.ssh/mykey.pub")
}
resource "aws_instance" "ec2" {
key_name = aws_key_pair.kepr.key_name
connection {
user = "ec2-user"
host = self.public_ip
private_key = file("~/.ssh/mykey.pem")
}
#...
}
이제 apply를 실행하고 key pair의 생성 현황을 살펴 본다.
+ resource "aws_key_pair" "kepr" {
+ arn = (known after apply)
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "kepr-temp"
+ key_name_prefix = (known after apply)
+ key_pair_id = (known after apply)
+ public_key = "<퍼블릭 키 내용>"
+ tags_all = (known after apply)
}
Plan: 2 to add, 1 to change, 1 to destroy.
╷
│ Error: file provisioner error
│
│ with aws_instance.ec2,
│ on main.tf line 28, in resource "aws_instance" "instance":
│ 28: provisioner "file" {
│
│ timeout - last error: dial tcp 21.231.101.71:22: i/o timeout
╵
Terraform apply 시점에 EC2 인스턴스의 보안그룹 인바운드가 22번 접속을 허용하지 않는다면 에러를 마주칠 수 있다.
인스턴스는 생성됐으나 프로비저닝 중 ssh 접속이 막혔기 때문이다. 아마존 리눅스의 Timeout은 기본 설정 5분으로 설정되어 있어 Terraform apply 후 5분 정도의 시간이 지나 오류가 발생할 것이다.
terraform show
aws_instance.ec2: (tainted)
tainted?
Tainted 리소스란 결함이 생긴 리소스를 지칭한다. 이후 terraform apply는 해당 자원을 대치하기 위해 신규 자원을 만들고자 할 것이다.
사실 EC2 생성은 잘 되었는데 22번 포트가 개방되지 않은 일로 다시 생성해야 하는 것은 억울할 수 있다. terraform untaint를 실행해 해당 자원을 새로 만들지 않도록 설정 가능하다.
$ terraform untaint aws_instance.ec2
Resource instance aws_instance.ec2 has been successfully untainted.
반대로 terraform taint도 존재한다. 다음 번 terraform apply에서 해당 자원을 새로 만들도록 설정한다.
$ terraform taint aws_instance.ec2
Resource instance aws_instance.ec2 has been marked as tainted.
'컴퓨터공학 > IaC' 카테고리의 다른 글
[Terraform] 설치형 Grafana 인스턴스 1대 띄우기 (0) | 2023.07.15 |
---|---|
[AWS][CloudFormation] CFN 스택 자원 보호하기 (0) | 2022.09.23 |