file Provisioner
Copy ไฟล์/folder จาก local → remote resource
Syntax
resource "aws_instance" "web" {
# ...
connection {
type = "ssh"
user = "ec2-user"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
provisioner "file" {
source = "config.json"
destination = "/tmp/config.json"
}
}
Arguments
| Argument | คำอธิบาย |
|---|---|
source | Path ใน local (ไฟล์หรือ folder) |
content | String content (แทน source) |
destination | Path ปลายทางใน remote |
ตัวอย่าง: Copy File
provisioner "file" {
source = "scripts/setup.sh"
destination = "/tmp/setup.sh"
}
ตัวอย่าง: Copy Folder
# Trailing slash → copy contents
provisioner "file" {
source = "configs/"
destination = "/etc/myapp/"
}
# No trailing slash → copy folder itself
provisioner "file" {
source = "configs"
destination = "/etc/myapp"
}
ตัวอย่าง: Copy Inline Content
provisioner "file" {
content = <<-EOF
server {
listen 80;
root /var/www/html;
}
EOF
destination = "/etc/nginx/sites-available/default"
}
ตัวอย่าง: Templated File
provisioner "file" {
content = templatefile("nginx.conf.tpl", {
server_name = var.domain
upstream = aws_alb.main.dns_name
})
destination = "/etc/nginx/nginx.conf"
}
nginx.conf.tpl
server {
listen 80;
server_name ${server_name};
location / {
proxy_pass http://${upstream};
}
}
Connection Block
file provisioner ต้องมี connection — Terraform ต้องคุยกับ remote ได้
SSH (Linux)
connection {
type = "ssh"
user = "ec2-user"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
SSH with Password
connection {
type = "ssh"
user = "admin"
password = var.ssh_password
host = self.public_ip
}
WinRM (Windows)
connection {
type = "winrm"
user = "Administrator"
password = var.winrm_password
host = self.public_ip
port = 5986
https = true
insecure = true # for self-signed cert
}
Bastion Host (Jump Box)
connection {
type = "ssh"
user = "ec2-user"
private_key = file("~/.ssh/id_rsa")
host = self.private_ip # private IP
bastion_host = aws_instance.bastion.public_ip
bastion_user = "ec2-user"
bastion_private_key = file("~/.ssh/id_rsa")
}
ตัวอย่าง: เต็มๆ
resource "aws_instance" "app" {
ami = "ami-12345"
instance_type = "t2.micro"
key_name = aws_key_pair.deployer.key_name
vpc_security_group_ids = [aws_security_group.ssh.id]
connection {
type = "ssh"
user = "ec2-user"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
timeout = "5m"
}
# 1. Copy config file
provisioner "file" {
source = "app/config.json"
destination = "/tmp/config.json"
}
# 2. Copy entire directory
provisioner "file" {
source = "app/"
destination = "/home/ec2-user/app/"
}
# 3. Move + restart service
provisioner "remote-exec" {
inline = [
"sudo mv /tmp/config.json /etc/myapp/config.json",
"sudo systemctl restart myapp"
]
}
}
Limitations
1. ต้องเชื่อมต่อได้
- Linux: SSH port 22 เปิด
- Windows: WinRM port 5985/5986 เปิด
- Security group/firewall อนุญาต source IP
2. ไฟล์ขนาดใหญ่
- ⚠️ Copy ไฟล์ใหญ่ผ่าน provisioner = ช้า
- ดีกว่า: upload ไป S3 → download ผ่าน user_data
3. ต้อง Public IP หรือ Bastion
- Private subnet → ต้อง bastion host
- VPC peering ผ่าน VPN → ตั้งค่า host ตาม
ทางเลือกที่ดีกว่า
Use Case: Copy Application Code
❌ Provisioner:
provisioner "file" {
source = "app/"
destination = "/var/www/app/"
}
✅ Bake into AMI ด้วย Packer:
# packer build → custom AMI ที่มี code อยู่แล้ว
data "aws_ami" "app" {
filter { ... }
}
resource "aws_instance" "web" {
ami = data.aws_ami.app.id
}
✅ S3 + user_data:
resource "aws_s3_object" "app" {
bucket = aws_s3_bucket.code.id
key = "app.tar.gz"
source = "app.tar.gz"
}
resource "aws_instance" "web" {
user_data = <<-EOF
#!/bin/bash
aws s3 cp s3://${aws_s3_bucket.code.id}/app.tar.gz /tmp/
tar -xzf /tmp/app.tar.gz -C /var/www/
EOF
}
Use Case: Copy Config File
❌ Provisioner:
provisioner "file" {
content = templatefile("config.tpl", {...})
destination = "/etc/app/config.json"
}
✅ user_data + heredoc:
resource "aws_instance" "web" {
user_data = <<-EOF
#!/bin/bash
cat > /etc/app/config.json <<CONFIG
{
"server": "${aws_alb.main.dns_name}",
"port": 8080
}
CONFIG
EOF
}
✅ AWS Secrets Manager:
resource "aws_secretsmanager_secret" "app_config" {
name = "prod/app-config"
}
resource "aws_secretsmanager_secret_version" "app_config" {
secret_id = aws_secretsmanager_secret.app_config.id
secret_string = jsonencode({
server = aws_alb.main.dns_name
port = 8080
})
}
# EC2 fetch via SDK
resource "aws_instance" "web" {
iam_instance_profile = aws_iam_instance_profile.app.name
user_data = <<-EOF
#!/bin/bash
aws secretsmanager get-secret-value \
--secret-id prod/app-config \
--query SecretString \
--output text > /etc/app/config.json
EOF
}
สรุป
fileprovisioner = copy file/folder ไป remote- ต้องมี
connectionblock (SSH/WinRM) - รองรับ
source(file path) หรือcontent(string) - ทางเลือกดีกว่า: Packer AMI, S3 + user_data, Secrets Manager
- ใช้เฉพาะตอน last resort
ต่อไป → local-exec provisioner