✔️ 프로비저너 (Provisioner)
로컬 머신이나 리모트 머신에 특정 액션(주로 명령어 실행)을 할 수 있게 해준다.
AWS 리소스를 정의할 때도 provisioner를 정의할 수 있다.
테라폼에서 제공하는 공통 argument이다.
기본적인 사용법은 다음과 같다.
resource "aws_instance" "web" {
# ...
provisioner "local-exec" {
command = "echo The server's IP address is ${self.private_ip}"
}
}
✔️ 프로비저너 종류
- file : 파일 복사
- local_exec : 로컬 머신에서 명령 실행
- remote_exec : 원격 머신에 명령 실행
✔️ file
file
프로비저닝 도구는 파일 또는 디렉토리를 Terraform을 실행중인 시스템에서 새로 생성된 리소스로 복사하는 데 사용된다.file
프로비저너는 ssh
및 winrm
연결을 모두 지원한다.
✔️ argument
- source - 소스 파일 또는 폴더이다.
현재 작업 디렉토리에 대한 상대 경로 또는 절대 경로로 지정할 수 있다.
이 속성은 content와 함께 지정할 수 없다. - content - 대상에 복사할 내용이다.
대상이 파일이면 내용이 해당 파일에 기록되고 디렉토리의 경우 tf-file-content라는 파일이 생성된다.
파일을 대상으로 사용하는 것이 좋다. template_file은 여기 또는 모든 interpolation syntax에서 참조될 수 있다.
이 속성은 source와 함께 지정할 수 없다. - 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"
}
}
✔️ local_exec
local-exec 프로비저너는 리소스가 생성된 후 로컬 실행 파일을 호출한다.
이것은 리소스가 아닌 Terraform을 실행하는 시스템에서 프로세스를 호출한다.
✔️ argument
- command - (필수) 실행할 명령어이다.
현재 작업 디렉토리에 대한 상대 경로 또는 절대 경로로 제공될 수 있다.
셸에서 평가되며 환경 변수 또는 Terraform 변수를 사용할 수 있다. - working_dir - (선택 사항) 제공된 경우 명령이 실행될 작업 디렉터리를 지정한다.
현재 작업 디렉토리에 대한 상대 경로 또는 절대 경로로 제공될 수 있다.
디렉토리가 존재해야 한다. - interpreter - (선택 사항) 제공된 경우 명령을 실행하는 데 사용되는 인터프리터 인수 목록다.
첫 번째 인수는 인터프리터 자체이다. 현재 작업 디렉토리에 대한 상대 경로 또는 절대 경로로 제공될 수 있다.
나머지 인수는 명령 앞에 추가되며 이를 통해 "/bin/bash", "-c", "echo foo" 형식의 명령줄을 작성할 수 있다.
인터프리터가 지정되지 않은 경우 시스템 OS에 따라 합리적인 기본값이 선택된다. - environment - (선택 사항) 실행된 명령의 환경을 나타내는 키 값 쌍의 블록이다.
현재 프로세스 환경을 상속한다.
resource "aws_instance" "web" {
# ...
provisioner "local-exec" { # 쌍따옴표 안에서 변수를 참조할 때
command = "echo ${self.private_ip} >> private_ips.txt"
}
}
self는 자기 자신을 의미한다.
✔️ remote_exec
remote-exec 프로비저너는 원격 리소스가 생성된 후 스크립트를 호출한다.
이것은 구성 관리 도구를 실행하고 클러스터로 부트스트랩하는 등의 작업에 사용할 수 있다.
✔️ argument
- 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",
]
}
}
✔️ 프로비저너 연결
프로비저너가 실행되기 위해서 file, remote-exec 에서는 SSH 연결이 필요하다.
파일을 복사할 때, 원격에서 명령을 실행할 때 SSH 연결이 필요하다.
- file
- remote_exec
프로비저너가 연결하기 위한 정보를 주는 argument인 connection 블록이 필요하다.
connection {
type = "ssh"
user = "root"
password = "${var.root_password}"
host = "${var.host}"
}
✔️ argument
- type - ssh/winRM
- user - ssh 계정
- password
- host (필수)
- port
✔️ 프로비저너 연결 방법 1)
provisioner "file" {
connection {
type = "ssh"
user = "root"
password = var.root_password
host = self.public_ip
}
}
하나의 file 프로비저너에 대한 연결이다.
✔️ 프로비저너 연결 방법 2)
provisioner "file" {
}
provisioner "file" {
}
connection { # 모든 프로비저너에게 공통적으로 연결하는 방식
}
connection 블록을 별도로 선언하면 모든 프로비저너에게 공통적으로 적용된다.
각각의 프로비저너의 연결 방식이 다를 일은 없으므로 후자를 많이 사용한다.
✔️ connection 실습
인스턴스를 생성할 때 key 기반 인증 SSH 접속을 위한 connection 블록을 작성해본다.
다음은 key를 생성하는 방법이다.
resource "aws_key_pair" "deployer" {
key_name = "deployer-key"
public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 email@example.com"
}
resource "aws_key_pair" "app_server_key" {
key_name = "app_server_key"
public_key = file("/home/vagrant/.ssh/id_rsa.pub")
}
resource "aws_instance" "app_server" {
.........리소스 정의........
connection {
user = "ec2-user"
host = self.public_ip
private_key = file("/home/vagrant/.ssh/id_rsa")
}
.........리소스 정의........
}
ssh-keygen을 사용해 키 쌍을 생성하거나 이미 만들어 놓은 키 쌍이 존재한다면
다음과 같이 file(path) 함수를 이용해 public_key로 공개키를 가져온다.
연결을 위해 connection 블록도 작성한다.
사용자명은 "ec2-user" 이며 host는 인스턴스 resource 자신의 public_ip이다.
비밀키도 마찬가지로 file 함수를 이용해 가져온다.
키를 만들었으면 이제 키를 인스턴스에 할당해줘야 한다.
SSH 연결을 위해서는 Key_name을 가져와야 한다.
key_name = aws_key_pair.app_server_key.key_name
apply 하면 key pair를 새로 생성한다고 출력한다.
# aws_key_pair.app_server_key will be created
+ resource "aws_key_pair" "app_server_key" {
+ arn = (known after apply)
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "app_server_key"
+ key_name_prefix = (known after apply)
+ key_pair_id = (known after apply)
+ public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2YV/nHQ7ITrE5ZFVsYmds4YbKdi2lVcXWVg/Vh8r5RaYX8zw28lVBWOtNafLJXP+vRkhHyf9p7/GpgebZum9CwEZ1XFfESvSnLA78DNU5SCF2TNglFoqeub5BXlY3eLokle4PEjOl9L2f2PKK4D8FDTBPM7lT9qcD3dqdupcsvyRtGu2Ba/cXI4FGgKEZYMfU49xUhzOUnH1vxm5kvh3Rgh21qLUK+hL1xeYfTctVtZA9escphXuqd8XU4IMtb6PX6cfGXSqonLwbAM1xjK7HidTI28lfLyO3xDoeUHNfYKkj2csq0Jw7dfjNfBihAhoEVzTot28+e49OsiKuPt6n vagrant@controller"
+ tags_all = (known after apply)
}
Plan: 2 to add, 1 to change, 1 to destroy.
╷
│ Error: file provisioner error
│
│ with aws_instance.app_server,
│ on main.tf line 28, in resource "aws_instance" "app_server":
│ 28: provisioner "file" {
│
│ timeout - last error: dial tcp 52.79.186.246:22: i/o timeout
╵
인스턴스 생성 중간에 에러가 나서 더 이상 작업이 진행되지 않는다.
문제 발생 이유는 terraform을 실행할 때 보안 그룹 설정에서 22번 포트의 접속을 허용하지 않아서
인스턴스는 생성됐으나 프로비저닝 중 ssh 접속이 막혔기 때문이다.
ssh는 보안을 위해서 일정 시간동안 사용이 없으면 자동으로 세션을 종료하는 세션 타임아웃(session timeout) 기능이 있다.
amazon linux ami로 인스턴스를 생성하면 기본 timeout 은 5분(300초)이다.
정리하자면 ssh 서버 포트인 22번이 막혀있어 인스턴스로 접속이 안되며 timeout은 기본 설정인 5분으로 설정되어 있어 5분 정도의 시간이 지난 후 다음과 같은 에러 메세지가 출력된다.
terraform show로 확인하면 tainted 라고 출력된다.
# aws_instance.app_server: (tainted)
따라서 SSH 접속을 위해서는 반드시 22번 포트를 열어줘야 한다.
✔️ Taint
문제가 발생했다는 의미이다.
Tainted 상태가 된 리소스는 다음번 apply 시에 '무조건' 새롭게 만들어진다.
테라폼 입장에서는 자기가 해야되는 작업을 완전하게 못했기 때문에 taint라고 하는 것이며
그래서 다시 apply 했을 때 무조건 새로 만든다.
untaint를 걸어 다음번에 새로 만들지 않도록 설정할 수도 있으며
[vagrant@controller 01]$ terraform untaint aws_instance.app_server
Resource instance aws_instance.app_server has been successfully untainted.
역으로 taint를 걸어 새로 만들도록 설정할 수도 있다.
[vagrant@controller 01]$ terraform taint aws_instance.app_server
Resource instance aws_instance.app_server has been marked as tainted.
'DevOps > Terraform' 카테고리의 다른 글
[Terraform] Count (0) | 2022.04.25 |
---|---|
[Terraform] 모듈 (Module) (0) | 2022.04.23 |
[Terraform] ec2 인스턴스 생성시 사용자 데이터 실행하기 (0) | 2022.04.22 |
[Terraform] 출력값(Output Value), 로컬값(Local Value) (0) | 2022.04.22 |
[Terraform] 연관된 변수들을 연쇄적으로 참조하기 (0) | 2022.04.22 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!