Первоначальная настройка терраритового бэкэнда с использованием терраформы
Я только начинаю работать с terraform и хотел бы использовать AWS S3 в качестве бэкэнда для хранения состояния моих проектов.
terraform {
backend "s3" {
bucket = "tfstate"
key = "app-state"
region = "us-east-1"
}
}
Я чувствую, что имеет смысл настроить мою корзину S3, группы IAM и политики для инфраструктуры внутреннего хранения с помощью terraform.
Если я настраиваю свое состояние бэкэнда до того, как применяю свою начальную инфраструктуру terraform, он обоснованно жалуется, что бэкэнд-контейнер еще не создан. Итак, у меня возникает вопрос, как мне настроить мой внутренний сервер terraform с помощью terraform, сохраняя при этом свое состояние для внутреннего сервера, отслеживаемого terraform. Похоже, проблема с матрешками.
У меня есть некоторые мысли о том, как написать сценарий вокруг этого, например, проверить, существует ли корзина или какое-то состояние, затем загрузить terraform и, наконец, скопировать terraform tfstate до s3 из локальной файловой системы после первого запуска. Но прежде чем идти по этому трудоемкому пути, я подумал, что должен убедиться, что не упустил что-то очевидное
Ответы
Ответ 1
Чтобы настроить это с помощью удаленного состояния terraform, у меня обычно есть отдельная папка с именем remote-state
в моей папке dev и prod terraform.
Следующий файл main.tf
настроит ваше удаленное состояние для того, что вы опубликовали:
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "tfstate"
versioning {
enabled = true
}
lifecycle {
prevent_destroy = true
}
}
resource "aws_dynamodb_table" "terraform_state_lock" {
name = "app-state"
read_capacity = 1
write_capacity = 1
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Затем перейдите в эту папку, используя cd remote-state
, и запустите terraform init && terraform apply
- это нужно выполнить только один раз. Вы можете добавить что-то в имя таблицы bucket и DynamodBB, чтобы разделить вашу среду.
Ответ 2
Как вы обнаружили, вы не можете использовать terraform для того, чтобы в первую очередь создавать потребности терраформирования компонентов.
Хотя я понимаю склонность к тому, чтобы terraform "отслеживал все", это очень сложно, и больше головной боли, чем того стоит.
Обычно я обрабатываю эту ситуацию, создавая простую оболочку бутстрапа script. Он создает такие вещи, как:
- Ведро s3 для хранения состояния
- Добавляет управление версиями в указанное ведро
- пользователь и группа Ira terraform с определенными политиками, которые мне понадобятся для построений терраформ.
В то время как вам нужно всего лишь запустить этот один раз (технически), я нахожу, что, когда я разрабатываю новую систему, я разворачиваю и разрываю вещи несколько раз. Таким образом, выполнение этих шагов в одном script делает это намного проще.
Я обычно строю script как идемпотент. Таким образом, вы можете запускать его несколько раз, не опасаясь, что вы создаете дубликаты ведра, пользователей и т.д.
Ответ 3
Опираясь на большой вклад Остина Дэвиса, я использую вариант, включающий требование шифрования данных:
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "tfstate"
versioning {
enabled = true
}
lifecycle {
prevent_destroy = true
}
}
resource "aws_dynamodb_table" "terraform_state_lock" {
name = "app-state"
read_capacity = 1
write_capacity = 1
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
resource "aws_s3_bucket_policy" "terraform_state" {
bucket = "${aws_s3_bucket.terraform_state.id}"
policy =<<EOF
{
"Version": "2012-10-17",
"Id": "RequireEncryption",
"Statement": [
{
"Sid": "RequireEncryptedTransport",
"Effect": "Deny",
"Action": ["s3:*"],
"Resource": ["arn:aws:s3:::${aws_s3_bucket.terraform_state.bucket}/*"],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
},
"Principal": "*"
},
{
"Sid": "RequireEncryptedStorage",
"Effect": "Deny",
"Action": ["s3:PutObject"],
"Resource": ["arn:aws:s3:::${aws_s3_bucket.terraform_state.bucket}/*"],
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
},
"Principal": "*"
}
]
}
EOF
}
Ответ 4
Обычно я начинаю без удаленного бэкэнда для создания начальной инфраструктуры, как вы сказали, S3, роли IAM и другие важные вещи. После этого я просто добавляю конфигурацию сервера и запускаю terraform init для перехода на S3.
Это не лучший случай, но в большинстве случаев я не перестраиваю всю свою среду каждый день, поэтому этот полуавтоматический подход достаточно хорош. Я также разделяю следующие "слои" инфраструктуры (VPC, Subnets, IGW, NAT и т.д.) На различные состояния.
Ответ 5
Я создал модуль terraform с несколькими командами/инструкциями начальной загрузки, чтобы решить эту проблему:
https://github.com/samstav/terraform-aws-backend
В README есть подробные инструкции, но суть такова:
# conf.tf
module "backend" {
source = "github.com/samstav/terraform-aws-backend"
backend_bucket = "terraform-state-bucket"
}
Затем в вашей оболочке (убедитесь, что вы еще не написали свой блок terraform {}
):
terraform get -update
terraform init -backend=false
terraform plan -out=backend.plan -target=module.backend
terraform apply backend.plan
Теперь напишите свой блок terraform {}
:
# conf.tf
terraform {
backend "s3" {
bucket = "terraform-state-bucket"
key = "states/terraform.tfstate"
dynamodb_table = "terraform-lock"
}
}
И тогда вы можете повторно инициировать:
terraform init -reconfigure
Ответ 6
Я решил эту проблему путем создания удаленного состояния проекта в первом цикле применения плана инициализации и инициализации удаленного состояния во втором цикле применения плана инициализации.
# first init plan apply cycle
# Configure the AWS Provider
# https://www.terraform.io/docs/providers/aws/index.html
provider "aws" {
version = "~> 2.0"
region = "us-east-1"
}
resource "aws_s3_bucket" "terraform_remote_state" {
bucket = "terraform-remote-state"
acl = "private"
tags = {
Name = "terraform-remote-state"
Environment = "Dev"
}
}
# add this sniped and execute the
# the second init plan apply cycle
# https://www.terraform.io/docs/backends/types/s3.html
terraform {
backend "s3" {
bucket = "terraform-remote-state"
key = "path/to/my/key"
region = "us-east-1"
}
}
Ответ 7
Предполагая, что вы запускаете terraform локально, а не на каком-либо виртуальном сервере, и что вы хотите сохранить состояние terraform в сегменте S3, который не существует. Вот как я бы подошел к этому,
Создать скрипт Terraform, который обеспечивает S3 Bucket
Создайте скрипт terraform, который обеспечивает вашу инфраструктуру
В конце вашего скрипта terraform для предоставления корзины, которая будет использоваться вторым скриптом terraform для хранения файлов состояния, включите код для предоставления нулевого ресурса.
В блоке кода для нулевого ресурса с помощью команды запуска local-exec provisioner перейдите в каталог, в котором существует ваш второй скрипт terraform, за которым следует обычная инициализация terraform для инициализации бэкэнда, затем план terraform, затем применение terraform