Skip to main content

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คำอธิบาย
sourcePath ใน local (ไฟล์หรือ folder)
contentString content (แทน source)
destinationPath ปลายทางใน 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
}

สรุป

  • file provisioner = copy file/folder ไป remote
  • ต้องมี connection block (SSH/WinRM)
  • รองรับ source (file path) หรือ content (string)
  • ทางเลือกดีกว่า: Packer AMI, S3 + user_data, Secrets Manager
  • ใช้เฉพาะตอน last resort

ต่อไป → local-exec provisioner