Terraform 将文件复制/上传到 AWS EC2 实例



我们有 cronjob 和 shell 脚本,我们希望在使用 terraform 创建实例时将其复制或上传到 aws ec2 实例。

我们试过了

  1. 文件配置器: 但它不是摇摆不定的,并且阅读此选项不适用于所有地形版本
provisioner "file" {
source      = "abc.sh"
destination = "/home/ec2-user/basic2.sh"
}
  1. >尝试的数据模板文件选项
data "template_file" "userdata_line" {
template = <<EOF
#!/bin/bash
mkdir /home/ec2-user/files2
cd /home/ec2-user/files2
sudo touch basic2.sh
sudo chmod 777 basic2.sh
base64 basic.sh |base64 -d >basic2.sh
EOF
}

尝试了所有选项,但没有一个有效。
你能帮忙或建议吗?
我是地球的新手,所以长期以来一直在努力。

当从安装了 cloud-init 的 AMI 开始时(这在许多官方 Linux 发行版中很常见(,我们可以使用 cloud-init 的write_files模块将任意文件放入文件系统中,只要它们足够小以适应user_data参数的约束以及所有其他cloud-init数据。

与所有 cloud-init 模块一样,我们使用 cloud-init 基于 YAML 的配置格式来配置write_files,该格式以特殊标记字符串#cloud-config开头,在自己的一行上,然后是 YAML 数据结构。因为JSON是YAML的一个子集,所以我们可以使用Terraform的jsonencode来生成一个有效的值[1]。

locals {
cloud_config_config = <<-END
#cloud-config
${jsonencode({
write_files = [
{
path        = "/etc/example.txt"
permissions = "0644"
owner       = "root:root"
encoding    = "b64"
content     = filebase64("${path.module}/example.txt")
},
]
})}
END
}

当我们设置时,write_files模块可以接受 base64 格式的数据encoding = "b64",因此我们将其与 Terraform 的filebase64函数结合使用以包含外部文件的内容。此处还可以使用其他方法,例如使用 Terraform 模板动态生成字符串,并使用base64encode将其编码为文件内容。

如果你可以在一个配置文件中表达你想要 cloud-init 做的所有事情,就像上面一样,那么你可以直接local.cloud_config_config分配作为你的实例user_data,云配置应该在系统启动时识别并处理它:

user_data = local.cloud_config_config

如果您需要将创建文件与其他一些操作(例如运行 shell 脚本(结合起来,则可以使用 cloud-init 的多部分存档格式对多个"文件"进行编码,以便 cloud-init 进行处理。Terraform 有一个cloudinit提供程序,其中包含一个数据源,用于轻松构建 cloud-init 的多部分存档:

data "cloudinit_config" "example" {
gzip          = false
base64_encode = false
part {
content_type = "text/cloud-config"
filename     = "cloud-config.yaml"
content      = local.cloud_config_config
}
part {
content_type = "text/x-shellscript"
filename     = "example.sh"
content  = <<-EOF
#!/bin/bash
echo "Hello World"
EOT
}
}

此数据源将在cloudinit_config.example.rendered处生成单个字符串,这是一个多部分存档,适合用作云初始化的user_data

user_data = data.cloudinit_config.example.rendered

EC2 规定的最大用户数据大小为 64 KB,因此所有编码数据加在一起必须符合该限制。如果您需要放置接近或超过该限制的大文件,最好使用中间其他系统来传输该文件,例如让 Terraform 将文件写入 Amazon S3 存储桶,并让实例中的软件使用实例配置文件凭证检索该数据。但是,对于用于系统配置的小型数据文件,这应该是不必要的。

需要注意的是,从 Terraform 和 EC2 的角度来看,user_data的内容只是一个任意字符串。处理字符串时的任何问题都必须在目标操作系统本身中进行调试,方法是读取 cloud-init 日志以查看它如何解释配置以及尝试执行这些操作时发生的情况。


[1]:我们也可能会使用yamlencode,但在我写这篇文章的时候,该函数有一个警告,它的确切格式可能会在未来的 Terraform 版本中发生变化,这对user_data来说是不可取的,因为它会导致实例被替换。如果您将来阅读本文,并且该警告不再出现在yamldecode文档中,请考虑改用yamlencode

我用provisioner "file"只是为了这个,没有问题...
但你必须提供一个连接:

resource "aws_instance" "foo" {
...
provisioner "file" {
source      = "~/foobar"
destination = "~/foobar"
connection {
type        = "ssh"
user        = "ubuntu"
private_key = "${file("~/Downloads/AWS_keys/test.pem")}"
host        = "${self.public_dns}"
}
}
...
}

下面是一些代码示例:
https://github.com/heldersepu/hs-scripts/blob/master/TerraForm/ec2_ubuntu.tf#L21

不知何故,在公司领域,没有任何选项有效。 但最终我们能够使用 S3 存储桶复制/下载文件。

创建 s3.tf 以 basic2.sh 上传此文件

resource "aws_s3_bucket" "demo-s3" {
bucket = "acom-demo-s3i-<bucketID>-us-east-1"
acl    = "private"

tags {
Name = "acom-demo-s3i-<bucketID>-us-east-1"
StackId = "demo-s3"
}
}
resource "aws_s3_bucket_policy" "s3_policy" {
bucket = "${aws_s3_bucket.demo-s3.id}"
policy = <<EOF
{
"Version": "2009-10-17",
"Statement": [
{
"Sid": "Only allow specific role",
"Effect": "allow",
"Principal":{ "AWS": ["arn:aws:iam::<bucketID>:role/demo-s3i"]},
"Action":  "s3:*",
"Resource": [
"arn:aws:s3:::acom-demo-s3i-<bucketID>-us-east-1",
"arn:aws:s3:::acom-demo-s3i-<bucketID>-us-east-1/*"
]
}
]
}
EOF
}

resource "aws_s3_bucket_object" "object" {
bucket = "acom-demo-s3i-<bucketID>-us-east-1"
key    = "scripts/basic2.sh"
source = "scripts/basic2.sh"
etag = "${filemd5("scripts/basic2.sh")}"
}

然后在其他TPL文件中声明文件下载部分。

aws s3 cp s3://acom-demo-s3i-<bucketID>-us-east-1/scripts/basic2.sh /home/ec2-user/basic2.sh

这里有一个更简单的示例,如何将write_filescloud-init一起使用,如 @martin-atkins 所述

templates/cloud-init.yml.tpl的内容

#cloud-config
package_update: true
package_upgrade: true
packages:
- ansible
write_files:
- content: |
${base64encode("${ansible_playbook}")}
encoding: b64
owner: root:root
path: /opt/ansible-playbook.yml
permissions: '0750'
runcmd:
- ansible-playbook /opt/ansible-playbook.yml

main.tf文件的内容:

data "template_file" "instance_startup_script" {
template = file(format("%s/templates/templates/cloud-init.yml.tpl", path.module))
vars = {
ansible_playbook = templatefile("${path.module}/templates/ansible-playbook.yml.tpl", {
playbookvar = var.play_book_var
})

cloudinitvar = var.cloud_init_var
}
}

可以对云初始化模板和 ansible-playbook 模板使用变量插值

您必须使用具有 ec2 实例连接详细信息的文件预置器。示例配置如下所示:

provisioner "file" {
source      = "${path.module}/files/script.sh"
destination = "/tmp/script.sh"
connection {
type     = "ssh"
user     = "root"
password = "${var.root_password}"
host     = "${var.host}"
}
}

您可以使用用户名/密码,私钥甚至堡垒主机进行连接。欲了解更多详情 https://www.terraform.io/docs/provisioners/connection.html

这对我有用:

resource "aws_instance" "myapp-server" {
ami = data.aws_ami.ubuntu.id
instance_type = xx
subnet_id =  xx
vpc_security_group_ids = xx
availability_zone=xx
associate_public_ip_address = true  
key_name = xx  
user_data = file(xx)
connection {
type     = "ssh"
host     =  self.public_ip
user     = "ubuntu"
private_key     = file(xx) 
}

provisioner "file" {
source      = "source-file"
destination = "dest-file"
}
} 

相关内容

  • 没有找到相关文章

最新更新