terraform копировать / загружать файлы в экземпляр aws ec2

У нас есть cronjob и сценарий оболочки, который мы хотим скопировать или загрузить в экземпляр aws ec2 при создании экземпляра с использованием terraform.

мы устали

  1. инициатор файлов: но он не работает, и эта опция чтения не работает со всеми версиями terraform
      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
    }

попробовал все варианты, но ни один из них не работал.
не могли бы вы помочь или посоветовать.
Я новичок в terraform, так что долго борюсь с этим.


person pratik    schedule 30.05.2020    source источник


Ответы (5)


При запуске из AMI, в котором установлен cloud-init (что часто встречается во многих официальных дистрибутивах Linux), мы можем используйте write_files модуль cloud-init для размещения произвольных файлов в файловой системы, если они достаточно малы, чтобы соответствовать ограничениям аргумента user_data вместе со всеми другими данными cloud-init.

Как и все модули cloud-init, мы настраиваем write_files с помощью облака Формат конфигурации на основе YAML -init, который начинается со специальной строки маркера #cloud-config в отдельной строке, за которой следует структура данных YAML. Поскольку JSON является подмножеством YAML, мы можем использовать jsonencode Terraform для создания допустимое значение [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's _ 10_ для включения содержимого внешнего файла. Здесь возможны другие подходы, такие как динамическое создание строки с использованием шаблонов Terraform и использование base64encode < / a>, чтобы закодировать его как содержимое файла.

Если вы можете выразить все, что вы хотите, чтобы cloud-init делал в одном файле конфигурации, как указано выше, вы можете напрямую назначить local.cloud_config_config в качестве своего экземпляра user_data, и cloud-config распознает и обработает его при загрузке системы:

  user_data = local.cloud_config_config

Если вместо этого вам нужно объединить создание файла с некоторыми другими действиями, такими как запуск сценария оболочки, вы можете использовать multipart archive для кодирования нескольких" файлов "для обработки 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 для cloud-init:

  user_data = cloudinit_config.example.rendered

EC2 устанавливает максимальное количество пользовательских данных размер 64 килобайта, поэтому все закодированные данные вместе должны соответствовать этому пределу. Если вам нужно разместить большой файл, который приближается к этому пределу или превышает его, вероятно, было бы лучше использовать другую промежуточную систему для передачи этого файла, например, чтобы Terraform записал файл в корзину Amazon S3 и поместил программное обеспечение в ваш экземпляр получает эти данные с помощью профиля экземпляра учетные данные. Однако в этом не должно быть необходимости для небольших файлов данных, используемых для конфигурации системы.

Важно отметить, что с точки зрения Terraform и EC2 содержимое user_data - это просто произвольная строка. Любые проблемы при обработке строки необходимо отлаживать в самой целевой операционной системе, читая журналы cloud-init, чтобы увидеть, как она интерпретировала конфигурацию и что произошло, когда она попыталась выполнить эти действия.


[1]: мы также потенциально можем использовать _21 _, но в то время, когда я пишу это, у этой функции есть предупреждение о том, что ее точное форматирование может измениться в будущих версиях Terraform, и это нежелательно для user_data, потому что это приведет к замене экземпляра. Если вы читаете это в будущем и этого предупреждения больше нет в yamldecode документах, рассмотрите возможность использования вместо этого yamlencode.

person Martin Atkins    schedule 30.05.2020
comment
Возможно ли это сделать, но с экземпляром Elastic Beanstalk? например, создайте там .env файл, чтобы избежать ограничения среды 4K - person Vitim.us; 02.03.2021
comment
Боюсь, я не очень хорошо знаком с Elastic Beanstalk. Это кажется совершенно отличным от других вариантов развертывания, связанных с EC2, поэтому я предлагаю задать новый вопрос на Stack Exchange, чтобы он, надеюсь, будет более заметным для людей, знакомых с Elastic Beanstalk. - person Martin Atkins; 02.03.2021

Я использовал 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

person Helder Sepulveda    schedule 30.05.2020
comment
Проблема, с которой я столкнулся с этим методом, заключается в том, что вы не можете использовать этот файл в пользовательских данных, поскольку это происходит после загрузки. - person openCivilisation; 05.04.2021
comment
@openCivilisation Да, все, что вам нужно в ОС, вы должны встроить в свой AMI, для этого поищите в Packer - person Helder Sepulveda; 05.04.2021

как-то в корпоративном домене ни один из вариантов не работал. но, наконец, мы смогли копировать / скачивать файлы с помощью ведра 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
person pratik    schedule 26.06.2020

Вы должны использовать средство подготовки файлов с данными о подключении к экземпляру 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

person Jeevagan    schedule 30.05.2020

Вот немного более простой пример использования write_files с cloud-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
  }
}

Можно использовать интерполяцию переменных как для шаблонов cloud-init, так и для ansible-playbook.

person Roman Shishkin    schedule 27.04.2021