diff --git a/README.md b/README.md index 8b78056..e7b53b0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,229 @@ # errormess_infra errormess Infra repository --- +--- +## Работа с Terraform, принципы организации инфраструктурного кода и работа над инфраструктурой в команде. +#### Выполненные работы: + +1. Создаем ветку **terraform-2** и подичищаем результат заданий со звездочкой: +```bash +git checkout -b terraform-2; git mv terraform/lb.tf terraform/files/ +``` +2. Создадим IP для внешнего ресурса с поомщью **yandex_vpc_network** и **yandex_vpc_subnet**, для этого добавляем в **main.tf** следующие строки: +``` +resource "yandex_vpc_network" "app-network" { + name = "reddit-app-network" +} + +resource "yandex_vpc_subnet" "app-subnet" { + name = "reddit-app-subnet" + zone = "ru-central1-a" + network_id = "${yandex_vpc_network.app-network.id}" + v4_cidr_blocks = ["192.168.10.0/24"] +} +``` +3. Добавляем упоминание о созданных сетевых ресурсах в код создания инстанса: +``` + network_interface { + subnet_id = yandex_vpc_subnet.app-subnet.id + nat = true + } +``` +4. Пересоздаем и проверяем как работают неявные зависимости: +```bash +terraform destroy --auto-approve; terraform plan; terraform apply --auto-approve +``` +5. Создаем 2 новых шаблона для packer **app.json** и **db.json** на базе уже имеющегося **ubuntu16.json** +``` +cp packer/ubuntu16.json packer/app.json; cp packer/ubuntu16.json packer/db.json +``` +редактируем полученные файлы, оставляя каждом необходимый провижионер и поменян некоторые параметры +``` +... + "image_name": "reddit-app-base-{{timestamp}}", + "image_family": "reddit-app-base", +... + "disk_name": "reddit-app-base", +... +``` +6. Запекаем образы +```bash +packer validate -var-file=./variables.json ./app.json +packer build -var-file=./variables.json ./app.json +packer validate -var-file=./variables.json ./db.json +packer build -var-file=./variables.json ./db.json +``` +7. Разбиваем **main.tf** на части создав **app.tf** и **db.tf**, а так же выносим в отдельный файл описание сети **vpc.tf**. +Для начала определим новые переменные: +``` +variable app_disk_image { + description = "disk image for reddit app" + default = "reddit-app-base" +} +variable db_disk_image { + description = "disk image for mongodb" + default = "reddit-db-base" +``` +и обозначим их +``` +app_disk_image = "reddit-app-base" +db_disk_image = "reddit-db-base" +``` +вынесем описание ресурсов например **app.tf** +``` +resource "yandex_compute_instance" "app" { + name = "reddit-app" + + labels = { + tags = "reddit-app" + } + resources { + cores = 2 + memory = 2 + } + + boot_disk { + initialize_params { + image_id = var.app_disk_image + } + } + + network_interface { + subnet_id = yandex_vpc_subnet.app-subnet.id + nat = true + } + + metadata = { + ssh-keys = "ubuntu:${file(var.public_key_path)}" + } +} +``` +оставив в **main.tf** только +``` +provider "yandex" { + version = "~> 0.43" + service_account_key_file = var.service_account_key_file + cloud_id = var.cloud_id + folder_id = var.folder_id + zone = var.zone +} +``` +правим **outputs.tf** +``` +output "external_ip_address_app" { + value = yandex_compute_instance.app.network_interface.0.nat_ip_address +} +output "external_ip_address_db" { + value = yandex_compute_instance.db.network_interface.0.nat_ip_address +} +``` +8. Проверяем работу +```bash +terraform destroy --auto-approve; terraform plan; terraform apply --auto-approve +``` +9. Создаем модульную инфраструктуру. Создаем папку **modules** внутри папки **terraform** +``` +mkdir modules +``` +теперь на необходимо создать папки для наших модулей +``` +mkdir app; mkdir db +``` +и в кажддом из модулей создаем знакомую нам структуру из **main.tf**, **outputs.ft** и **variables.tf** +``` +variable public_key_path { + description = "Path to the public key used for ssh access" +} + variable db_disk_image { + description = "Disk image for reddit db" + default = "reddit-db-base" +} +variable subnet_id { +description = "Subnets for modules" +} +``` +outputs.tf +``` +output "external_ip_address_app" { + value = yandex_compute_instance.app.network_interface.0.nat_ip_address +} +``` +удаляем из дириктории **app.tf**, **db.tf** и **vpc.tf** +``` +rm app.tf; rm db.tf; rm vpc.tf +``` +укащываем в **main.tf** исользование модулей +``` +module "app" { + source = "./modules/app" + public_key_path = var.public_key_path + app_disk_image = var.app_disk_image + subnet_id = var.subnet_id +} + +module "db" { + source = "./modules/db" + public_key_path = var.public_key_path + db_disk_image = var.db_disk_image + subnet_id = var.subnet_id +} +``` +правим **outputs.tf** +``` +output "external_ip_address_app" { + value = module.app.external_ip_address_app +} +output "external_ip_address_db" { + value = module.db.external_ip_address_db +} +``` +загружаем модули +``` +terraform get +``` +и пробуем все собрать +``` +terraform plan; terraform apply --auto-approve +``` +10. Переиспользование модулей. Для этого необходимо создать среды **prod** и **stage** +``` +mkdir prod; mkdir stage +``` +копируем в эти каталоги наши основные рабочией файлы +``` +cp main.tf prod/; cp outputs.tf prod/; cp variables.tf prod/; cp terraform.tfvars prod/ +``` +анологично делаем и для **stage**, и корректируем **main.tf** +``` +provider "yandex" { + service_account_key_file = var.service_account_key_file + cloud_id = var.cloud_id + folder_id = var.folder_id + zone = var.zone +} +module "app" { + source = "../modules/app" + public_key_path = var.public_key_path + app_disk_image = var.app_disk_image + subnet_id = var.subnet_id +} + +module "db" { + source = "../modules/db" + public_key_path = var.public_key_path + db_disk_image = var.db_disk_image + subnet_id = var.subnet_id +} +``` +корректируем синтаксис +``` +terraform fmt +``` +и проверяем на каждом стенде +``` +terraform init; terraform apply --auto-approve +``` + ## Знакомство с Terraform #### Выполненные работы 1. Создаем ветку **terraform-1** и устанавливаем дистрибутив Terraform @@ -341,4 +564,4 @@ someinternalhost_IP = 10.128.0.17 ``` testapp_IP = 158.160.34.149 testapp_port = 9292 -``` \ No newline at end of file +``` diff --git a/packer/app.json b/packer/app.json new file mode 100644 index 0000000..d09ecb6 --- /dev/null +++ b/packer/app.json @@ -0,0 +1,23 @@ +{ + "builders": [ + { + "type": "yandex", + "service_account_key_file": "{{user `key`}}", + "folder_id": "{{user `fid`}}", + "source_image_family": "{{user `image`}}", + "image_name": "ruby-base-{{timestamp}}", + "image_family": "ruby-base", + "ssh_username": "ubuntu", + "use_ipv4_nat": true, + "platform_id": "standard-v1" + } + ], + "provisioners": [ + { + "type": "shell", + "script": "./scripts/install_ruby.sh", + "execute_command": "sudo {{.Path}}" + } + ] +} + diff --git a/packer/db.json b/packer/db.json new file mode 100644 index 0000000..557dba7 --- /dev/null +++ b/packer/db.json @@ -0,0 +1,22 @@ +{ + "builders": [ + { + "type": "yandex", + "service_account_key_file": "{{user `key`}}", + "folder_id": "{{user `fid`}}", + "source_image_family": "{{user `image`}}", + "image_name": "mongodb-base-{{timestamp}}", + "image_family": "mongodb-base", + "ssh_username": "ubuntu", + "use_ipv4_nat": true, + "platform_id": "standard-v1" + } + ], + "provisioners": [ + { + "type": "shell", + "script": "./scripts/install_mongodb.sh", + "execute_command": "sudo {{.Path}}" + } + ] +} diff --git a/packer/scripts/install_mongodb.sh b/packer/scripts/install_mongodb.sh index 6a2578a..0f4143c 100644 --- a/packer/scripts/install_mongodb.sh +++ b/packer/scripts/install_mongodb.sh @@ -1,12 +1,12 @@ -#!/bin/bash -sudo apt update -sudo apt-get install apt-transport-https ca-certificates git -y - -wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add - -echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list - -sudo apt-get update -sudo apt-get install -y mongodb-org - -sudo systemctl start mongod -sudo systemctl enable mongod +#!/bin/bash +sudo apt update +sudo apt-get install apt-transport-https ca-certificates git -y + +wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add - +echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list + +sudo apt-get update +sudo apt-get install -y mongodb-org + +sudo systemctl start mongod +sudo systemctl enable mongod diff --git a/packer/scripts/install_ruby.sh b/packer/scripts/install_ruby.sh index b601632..4c55ec5 100644 --- a/packer/scripts/install_ruby.sh +++ b/packer/scripts/install_ruby.sh @@ -1,5 +1,5 @@ -#!/bin/bash -sudo apt update -echo 'sleep 4m for install updates'; sleep 4m; echo "start install ruby" -sudo apt install -y ruby-full ruby-bundler build-essential -#test +#!/bin/bash +sudo apt update +echo 'sleep 4m for install updates'; sleep 4m; echo "start install ruby" +sudo apt install -y ruby-full ruby-bundler build-essential +#test diff --git a/terraform/lb.tf b/terraform/files/lb.tf similarity index 100% rename from terraform/lb.tf rename to terraform/files/lb.tf diff --git a/terraform/main.tf b/terraform/main.tf deleted file mode 100644 index fd0265b..0000000 --- a/terraform/main.tf +++ /dev/null @@ -1,49 +0,0 @@ -provider "yandex" { - token = var.token - cloud_id = var.cloud_id - folder_id = var.folder_id - zone = var.zone -} - -resource "yandex_compute_instance" "app" { - count = var.instances - name = "reddit-app-${count.index}" - - resources { - cores = 2 - memory = 2 - } - - metadata = { - ssh-keys = "ubuntu:${file(var.public_key_path)}" - } - - boot_disk { - initialize_params { - image_id = var.image_id - } - } - - network_interface { - subnet_id = var.subnet_id - nat = true - } - - connection { - type = "ssh" - host = self.network_interface.0.nat_ip_address - user = "ubuntu" - agent = false - # путь до приватного ключа - private_key = file(var.private_key_path) - } - - provisioner "file" { - source = "files/puma.service" - destination = "/tmp/puma.service" - } - - provisioner "remote-exec" { - script = "files/deploy.sh" - } -} diff --git a/terraform/modules/app/main.tf b/terraform/modules/app/main.tf new file mode 100644 index 0000000..470fb46 --- /dev/null +++ b/terraform/modules/app/main.tf @@ -0,0 +1,26 @@ +resource "yandex_compute_instance" "app" { + name = "reddit-app" + + labels = { + tags = "reddit-app" + } + resources { + cores = 2 + memory = 2 + } + + boot_disk { + initialize_params { + image_id = var.app_disk_image + } + } + + network_interface { + subnet_id = var.subnet_id + nat = true + } + + metadata = { + ssh-keys = "ubuntu:${file(var.public_key_path)}" + } +} diff --git a/terraform/modules/app/outputs.tf b/terraform/modules/app/outputs.tf new file mode 100644 index 0000000..4fb67fc --- /dev/null +++ b/terraform/modules/app/outputs.tf @@ -0,0 +1,3 @@ +output "external_ip_address_app" { + value = yandex_compute_instance.app.network_interface.0.nat_ip_address +} diff --git a/terraform/modules/app/variables.tf b/terraform/modules/app/variables.tf new file mode 100644 index 0000000..9eac32f --- /dev/null +++ b/terraform/modules/app/variables.tf @@ -0,0 +1,10 @@ +variable public_key_path { + description = "Path to the public key used for ssh access" +} +variable app_disk_image { + description = "Disk image for reddit app" + default = "reddit-app-base" +} +variable subnet_id { +description = "Subnets for modules" +} diff --git a/terraform/modules/db/main.tf b/terraform/modules/db/main.tf new file mode 100644 index 0000000..1b0de90 --- /dev/null +++ b/terraform/modules/db/main.tf @@ -0,0 +1,26 @@ +resource "yandex_compute_instance" "db" { + name = "reddit-db" + labels = { + tags = "reddit-db" + } + + resources { + cores = 2 + memory = 2 + } + + boot_disk { + initialize_params { + image_id = var.db_disk_image + } + } + + network_interface { + subnet_id = var.subnet_id + nat = true + } + + metadata = { + ssh-keys = "ubuntu:${file(var.public_key_path)}" + } +} diff --git a/terraform/modules/db/outputs.tf b/terraform/modules/db/outputs.tf new file mode 100644 index 0000000..319c935 --- /dev/null +++ b/terraform/modules/db/outputs.tf @@ -0,0 +1,3 @@ +output "external_ip_address_db" { + value = yandex_compute_instance.db.network_interface.0.nat_ip_address +} diff --git a/terraform/modules/db/variables.tf b/terraform/modules/db/variables.tf new file mode 100644 index 0000000..9955403 --- /dev/null +++ b/terraform/modules/db/variables.tf @@ -0,0 +1,10 @@ +variable public_key_path { + description = "Path to the public key used for ssh access" +} + variable db_disk_image { + description = "Disk image for reddit db" + default = "reddit-db-base" +} +variable subnet_id { +description = "Subnets for modules" +} diff --git a/terraform/modules/vpc/main.tf b/terraform/modules/vpc/main.tf new file mode 100644 index 0000000..c50b24a --- /dev/null +++ b/terraform/modules/vpc/main.tf @@ -0,0 +1,10 @@ +resource "yandex_vpc_network" "app-network" { + name = "reddit-app-network" +} + +resource "yandex_vpc_subnet" "app-subnet" { + name = "reddit-app-subnet" + zone = "ru-central1-a" + network_id = "${yandex_vpc_network.app-network.id}" + v4_cidr_blocks = ["192.168.10.0/24"] +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf deleted file mode 100644 index 1cff9d3..0000000 --- a/terraform/outputs.tf +++ /dev/null @@ -1,6 +0,0 @@ -output "external_ip_addresses_app" { - value = yandex_compute_instance.app[*].network_interface.0.nat_ip_address -} -output "loadbalancer_ip_address" { - value = yandex_lb_network_load_balancer.lb.listener.*.external_address_spec[0].*.address -} diff --git a/terraform/prod/backend.tf b/terraform/prod/backend.tf new file mode 100644 index 0000000..1217899 --- /dev/null +++ b/terraform/prod/backend.tf @@ -0,0 +1,23 @@ +resource "yandex_iam_service_account" "sa" { + name = "backet" +} + +resource "yandex_resourcemanager_folder_iam_member" "sa-editor" { + folder_id = "b1g5bhhmfr2843h67kop" + role = "storage.editor" + member = "serviceAccount:${yandex_iam_service_account.sa.id}" +} + +// Создание статического ключа доступа +resource "yandex_iam_service_account_static_access_key" "sa-static-key" { + service_account_id = yandex_iam_service_account.sa.id + description = "static access key for object storage" +} + +resource "yandex_storage_bucket" "test" { + access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key + secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key + bucket = var.bucket_name + // key = "terraform.tfstate" +} + diff --git a/terraform/prod/main.tf b/terraform/prod/main.tf new file mode 100644 index 0000000..7a4a062 --- /dev/null +++ b/terraform/prod/main.tf @@ -0,0 +1,19 @@ +provider "yandex" { + token = var.token + cloud_id = var.cloud_id + folder_id = var.folder_id + zone = var.zone +} +module "app" { + source = "../modules/app" + public_key_path = var.public_key_path + app_disk_image = var.app_disk_image + subnet_id = var.subnet_id +} + +module "db" { + source = "../modules/db" + public_key_path = var.public_key_path + db_disk_image = var.db_disk_image + subnet_id = var.subnet_id +} diff --git a/terraform/prod/terraform.tfvars.example b/terraform/prod/terraform.tfvars.example new file mode 100644 index 0000000..dc54ad2 --- /dev/null +++ b/terraform/prod/terraform.tfvars.example @@ -0,0 +1,15 @@ +cloud_id = "b1gugdsadasdvdk2t1741nm6dhp" +token = "y0_AgAAAABl2asasddsa-iaAATuwQAAAADUb2GaZs_LDS0UQvigAk-UF4dhavf_xDg" +folder_id = "b1g5bhhmkop" +zone = "ru-central1-a" +image_id = "fdmasdasdasdgfudautbbk62q5" +public_key_path = "~/.ssh/id_rsa.pub" +private_key_path = "~/.ssh/id_rsa" +subnet_id = "e9basdasdasdasr5m142hmv0lfip6rj" +#service_account_key_file = "key.json" +instances = 1 +app_disk_image = "fd8m01720s7bqv4qggfdgffgfgfgfgsm29" +db_disk_image = "fd8r6easd8fl5dfasdnc705mjn" +access_key = "ajetasde76lasdasd5asd1vkgpl7bolk" +secret_key = "YCM2KnsasdasdDcqwuwozOZK44asdasA40o42zTFzUQx84qODYZ" +bucket_name = "errormess" diff --git a/terraform/prod/variables.tf b/terraform/prod/variables.tf new file mode 100644 index 0000000..c83ddee --- /dev/null +++ b/terraform/prod/variables.tf @@ -0,0 +1,55 @@ +variable cloud_id { + description = "Cloud" +} +variable token { + description = "Token" +} +variable folder_id { + description = "Folder" +} +variable zone { + description = "Zone" + # Значение по умолчанию + default = "ru-central1-a" +} +variable region_id { + description = "region" + default = "ru-central1" +} +variable public_key_path { + # Описание переменной + description = "Path to the public key used for ssh access" +} +variable private_key_path { + description = "Path to the private key used for ssh access" +} +variable image_id { + description = "Disk image" +} +variable subnet_id { + description = "Subnet" +} +#variable service_account_key_file { +# description = "key .json" +#} +variable instances { + description = "Count instances" + default = 1 +} +variable app_disk_image { + description = "Disk image for reddit app" + default = "reddit-app-base" +} +variable db_disk_image { + description = "Disk image for reddit db" + default = "reddit-db-base" +} +variable access_key { + description = "key id" +} +variable secret_key { + description = "secret key" +} +variable bucket_name { + description = "bucket name" +} diff --git a/terraform/stage/backend.tf b/terraform/stage/backend.tf new file mode 100644 index 0000000..cb7f442 --- /dev/null +++ b/terraform/stage/backend.tf @@ -0,0 +1,11 @@ +terraform { + backend "s3" { + endpoint = "storage.yandexcloud.net" + bucket = "storage-errormess" + region = "ru-central1" + key = "./terraform.tfstate" + + skip_region_validation = true + skip_credentials_validation = true + } +} diff --git a/terraform/stage/main.tf b/terraform/stage/main.tf new file mode 100644 index 0000000..346837f --- /dev/null +++ b/terraform/stage/main.tf @@ -0,0 +1,20 @@ +provider "yandex" { + version = "~> 0.43" + token = var.token + cloud_id = var.cloud_id + folder_id = var.folder_id + zone = var.zone +} +module "app" { + source = "../modules/app" + public_key_path = var.public_key_path + app_disk_image = var.app_disk_image + subnet_id = var.subnet_id +} + +module "db" { + source = "../modules/db" + public_key_path = var.public_key_path + db_disk_image = var.db_disk_image + subnet_id = var.subnet_id +} diff --git a/terraform/stage/terraform.tfvars.example b/terraform/stage/terraform.tfvars.example new file mode 100644 index 0000000..2acc8ea --- /dev/null +++ b/terraform/stage/terraform.tfvars.example @@ -0,0 +1,12 @@ +cloud_id = "b1gu" +token = "y0_AgAAAUb2GaZs_LDS0UQvigAk-UF4dhavf_xDg" +folder_id = "b1gfr2843h67kop" +zone = "ru-central1-a" +image_id = "fdcsmudautbbk62q5" +public_key_path = "~/.ssh/id_rsa.pub" +private_key_path = "~/.ssh/id_rsa" +subnet_id = "e9br5mv0lfip6rj" +#service_account_key_file = "key.json" +instances = 1 +app_disk_image = "f20s7bqv4qsm29" +db_disk_image = "ffl5dfnc705mjn" diff --git a/terraform/stage/variables.tf b/terraform/stage/variables.tf new file mode 100644 index 0000000..d56d080 --- /dev/null +++ b/terraform/stage/variables.tf @@ -0,0 +1,46 @@ +variable cloud_id { + description = "Cloud" +} +variable token { + description = "Token" +} +variable folder_id { + description = "Folder" +} +variable zone { + description = "Zone" + # Значение по умолчанию + default = "ru-central1-a" +} +variable region_id { + description = "region" + default = "ru-central1" +} +variable public_key_path { + # Описание переменной + description = "Path to the public key used for ssh access" +} +variable private_key_path { + description = "Path to the private key used for ssh access" +} +variable image_id { + description = "Disk image" +} +variable subnet_id { + description = "Subnet" +} +#variable service_account_key_file { +# description = "key .json" +#} +variable instances { + description = "Count instances" + default = 1 +} +variable app_disk_image { + description = "Disk image for reddit app" + default = "reddit-app-base" +} +variable db_disk_image { + description = "Disk image for reddit db" + default = "reddit-db-base" +} diff --git a/terraform/storage-bucket.tf b/terraform/storage-bucket.tf new file mode 100644 index 0000000..e8a706f --- /dev/null +++ b/terraform/storage-bucket.tf @@ -0,0 +1,30 @@ +provider "yandex" { + version = "~> 0.43" + token = var.token + cloud_id = var.cloud_id + folder_id = var.folder_id + zone = var.zone +} +resource "yandex_iam_service_account" "sa" { + name = "backet" +} + +// Назначение роли сервисному аккаунту +resource "yandex_resourcemanager_folder_iam_member" "sa-editor" { + folder_id = var.folder_id + role = "storage.editor" + member = "serviceAccount:${yandex_iam_service_account.sa.id}" +} + +// Создание статического ключа доступа +resource "yandex_iam_service_account_static_access_key" "sa-static-key" { + service_account_id = yandex_iam_service_account.sa.id + description = "static access key for object storage" +} + +// Создание бакета с использованием ключа +resource "yandex_storage_bucket" "test" { + access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key + secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key + bucket = "errormess" +} diff --git a/terraform/terraform.tfvars.example b/terraform/terraform.tfvars.example index a90517f..32d85ae 100644 --- a/terraform/terraform.tfvars.example +++ b/terraform/terraform.tfvars.example @@ -6,4 +6,4 @@ image_id = "csmudautbbk62q5" public_key_path = "~/.ssh/ubuntu.pub" private_key_path = "~/.ssh/ubuntu" subnet_id = "e9br5m142p6rj" -instances = 2 +instances = 1 diff --git a/terraform/variables.tf b/terraform/variables.tf index 17204f0..8fd7df0 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -36,4 +36,20 @@ variable instances { description = "Count instances" default = 1 } - +variable app_disk_image { + description = "Disk image for reddit app" + default = "reddit-app-base" +} +variable db_disk_image { + description = "Disk image for reddit db" + default = "reddit-db-base" +} +variable access_key { + description = "key id" +} +variable secret_key { + description = "secret key" +} +variable bucket_name { + description = "bucket name" +}