diff --git a/README.md b/README.md index 64ef33813a..298f2ba001 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,11 @@ -# Домашнее задание к занятию "`Название занятия`" - `Фамилия и имя студента` +# Домашнее задание к занятию "Управляющие конструкции в коде Terraform" - `Вялов Владислав` -### Инструкция по выполнению домашнего задания +## Задание 1 - 1. Сделайте `fork` данного репозитория к себе в Github и переименуйте его по названию или номеру занятия, например, https://github.com/имя-вашего-репозитория/git-hw или https://github.com/имя-вашего-репозитория/7-1-ansible-hw). - 2. Выполните клонирование данного репозитория к себе на ПК с помощью команды `git clone`. - 3. Выполните домашнее задание и заполните у себя локально этот файл README.md: - - впишите вверху название занятия и вашу фамилию и имя - - в каждом задании добавьте решение в требуемом виде (текст/код/скриншоты/ссылка) - - для корректного добавления скриншотов воспользуйтесь [инструкцией "Как вставить скриншот в шаблон с решением](https://github.com/netology-code/sys-pattern-homework/blob/main/screen-instruction.md) - - при оформлении используйте возможности языка разметки md (коротко об этом можно посмотреть в [инструкции по MarkDown](https://github.com/netology-code/sys-pattern-homework/blob/main/md-instruction.md)) - 4. После завершения работы над домашним заданием сделайте коммит (`git commit -m "comment"`) и отправьте его на Github (`git push origin`); - 5. Для проверки домашнего задания преподавателем в личном кабинете прикрепите и отправьте ссылку на решение в виде md-файла в вашем Github. - 6. Любые вопросы по выполнению заданий спрашивайте в чате учебной группы и/или в разделе “Вопросы по заданию” в личном кабинете. - -Желаем успехов в выполнении домашнего задания! - -### Дополнительные материалы, которые могут быть полезны для выполнения задания +![alt text](img/1.jpg) -1. [Руководство по оформлению Markdown файлов](https://gist.github.com/Jekins/2bf2d0638163f1294637#Code) ---- +## Задание 4 -### Задание 1 - -`Приведите ответ в свободной форме........` - -1. `Заполните здесь этапы выполнения, если требуется ....` -2. `Заполните здесь этапы выполнения, если требуется ....` -3. `Заполните здесь этапы выполнения, если требуется ....` -4. `Заполните здесь этапы выполнения, если требуется ....` -5. `Заполните здесь этапы выполнения, если требуется ....` -6. - -``` -Поле для вставки кода... -.... -.... -.... -.... -``` - -`При необходимости прикрепитe сюда скриншоты -![Название скриншота 1](ссылка на скриншот 1)` - - ---- - -### Задание 2 - -`Приведите ответ в свободной форме........` - -1. `Заполните здесь этапы выполнения, если требуется ....` -2. `Заполните здесь этапы выполнения, если требуется ....` -3. `Заполните здесь этапы выполнения, если требуется ....` -4. `Заполните здесь этапы выполнения, если требуется ....` -5. `Заполните здесь этапы выполнения, если требуется ....` -6. - -``` -Поле для вставки кода... -.... -.... -.... -.... -``` - -`При необходимости прикрепитe сюда скриншоты -![Название скриншота 2](ссылка на скриншот 2)` - - ---- - -### Задание 3 - -`Приведите ответ в свободной форме........` - -1. `Заполните здесь этапы выполнения, если требуется ....` -2. `Заполните здесь этапы выполнения, если требуется ....` -3. `Заполните здесь этапы выполнения, если требуется ....` -4. `Заполните здесь этапы выполнения, если требуется ....` -5. `Заполните здесь этапы выполнения, если требуется ....` -6. - -``` -Поле для вставки кода... -.... -.... -.... -.... -``` - -`При необходимости прикрепитe сюда скриншоты -![Название скриншота](ссылка на скриншот)` - -### Задание 4 - -`Приведите ответ в свободной форме........` - -1. `Заполните здесь этапы выполнения, если требуется ....` -2. `Заполните здесь этапы выполнения, если требуется ....` -3. `Заполните здесь этапы выполнения, если требуется ....` -4. `Заполните здесь этапы выполнения, если требуется ....` -5. `Заполните здесь этапы выполнения, если требуется ....` -6. - -``` -Поле для вставки кода... -.... -.... -.... -.... -``` - -`При необходимости прикрепитe сюда скриншоты -![Название скриншота](ссылка на скриншот)` +![alt text](img/2.jpg) \ No newline at end of file diff --git a/img/1.jpg b/img/1.jpg new file mode 100644 index 0000000000..9b4f91b384 Binary files /dev/null and b/img/1.jpg differ diff --git a/img/2.jpg b/img/2.jpg new file mode 100644 index 0000000000..da1658c973 Binary files /dev/null and b/img/2.jpg differ diff --git a/img/img15.png b/img/img15.png deleted file mode 100644 index 97618b8b9f..0000000000 Binary files a/img/img15.png and /dev/null differ diff --git a/img/img16.png b/img/img16.png deleted file mode 100644 index 3fc3eef59d..0000000000 Binary files a/img/img16.png and /dev/null differ diff --git a/img/img17.png b/img/img17.png deleted file mode 100644 index 0ea655194a..0000000000 Binary files a/img/img17.png and /dev/null differ diff --git a/img/img18.png b/img/img18.png deleted file mode 100644 index 985bd45147..0000000000 Binary files a/img/img18.png and /dev/null differ diff --git a/img/img19.png b/img/img19.png deleted file mode 100644 index 2c1e7ba67c..0000000000 Binary files a/img/img19.png and /dev/null differ diff --git a/img/img20.png b/img/img20.png deleted file mode 100644 index b003cbd6e1..0000000000 Binary files a/img/img20.png and /dev/null differ diff --git a/md-instruction.md b/md-instruction.md deleted file mode 100644 index 32add5b663..0000000000 --- a/md-instruction.md +++ /dev/null @@ -1,52 +0,0 @@ -# Знакомство с MarkDown - - -**Markdown** - язык разметки, созданный с целью обозначения форматирования в простом тексте и сохранением максимальной читаемости текста. *Текстовые файлы, описанные в формате markdown имеют расширение файла .md* - -Благодаря использованию [специализированных символов](#symbols), файл формата markdown может быть интерпретирован онлайн-сервисами, такими как GitHub, в файл, обладающий специальным графическим представлением текста. - - - -# - -### Специальные символы .md - -Для обозначения заголовков в markdown используется символ **#**: - - - -*Для того чтобы обозначить заголовок между # и текстом обязательно должен быть пробельный символ* - -# - -Markdown поддерживает и **стандартные способы выделения текста**: - - - -*Для переноса текста на следующую строку, используется сочетание двух пробелов в конце строки* - -# - -Существует также возможность использования **списков**: - - - -*Вложенный список создается при помощи четырех символов пробела или табуляции* - -# - -Описание кода возможно и без использования нумерованного списка, с помощью набора символов **```название языка**: - - - -*Использование символа ``` без указания языка позволит выделить блок без выделения цветом* - -# - -Для отображения в файле формата .md изображений используется синтаксис, схожий с описанием внешней ссылки **![альтернативный текст](ссылка на изображение)**: - - - -# - -Важно, что путь до файла с кодом или изображением в вашем репозитории может быть указан через абсолютную или относительную ссылку. То есть для указания абсолютной ссылки на файл, опубликованный в сети, необходимо указывать ссылку в виде **"https://адрес_файла"**, а для указания относительного пути к файлу, находящемуся строго в текущем репозитории, в виде **"ДИРЕКТОРИЯ/ФАЙЛ.РАСШИРЕНИЕ"**. diff --git a/screen-instruction.md b/screen-instruction.md deleted file mode 100644 index ca64ce301f..0000000000 --- a/screen-instruction.md +++ /dev/null @@ -1,18 +0,0 @@ -# Как вставить скриншот в шаблон с решением - -1. Разместите скриншот в локальном репозитории -2. Вставьте ссылку с указанием файла скриншота в следующем формате: - - `![alt text](https://github.com/username/reponame/blob/branch/path/image.png)` - где - [username] — ваш ник на Github; - [reponame] — название репозитория, в котором хранятся скриншоты; - [branch] — ветка репозитория; - [path] — путь к месту нахождения скриншота. - -Пример вставки изображения: - -### Задание 1 - -Скриншот-1 к заданию 1: -![Скриншот-1](https://github.com/netology-code/sys-pattern-homework/blob/main/img/img15.png) diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000000..df429d2212 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,12 @@ +# Local .terraform directories and files +**/.terraform/* +.terraform* + +!.terraformrc + +# .tfstate files +*.tfstate +*.tfstate.* + +# own secret vars store. +personal.auto.tfvars \ No newline at end of file diff --git a/src/.terraformrc b/src/.terraformrc new file mode 100644 index 0000000000..9bc7728211 --- /dev/null +++ b/src/.terraformrc @@ -0,0 +1,9 @@ +provider_installation { + network_mirror { + url = "https://terraform-mirror.yandexcloud.net/" + include = ["registry.terraform.io/*/*"] + } + direct { + exclude = ["registry.terraform.io/*/*"] + } +} \ No newline at end of file diff --git a/src/ansible.tf b/src/ansible.tf new file mode 100644 index 0000000000..160d747d64 --- /dev/null +++ b/src/ansible.tf @@ -0,0 +1,40 @@ +locals { + webservers_for_ansible = [ + for i, vm in yandex_compute_instance.web : { + name = vm.name + external_ip = vm.network_interface[0].nat_ip_address + fqdn = vm.fqdn + } + ] + + databases_for_ansible = [ + for name, vm in yandex_compute_instance.db-vm : { + name = vm.name + external_ip = vm.network_interface[0].nat_ip_address + fqdn = vm.fqdn + } + ] + + storage_for_ansible = [ + { + name = yandex_compute_instance.storage.name + external_ip = yandex_compute_instance.storage.network_interface[0].nat_ip_address + fqdn = yandex_compute_instance.storage.fqdn + } + ] +} + +resource "local_file" "ansible_inventory" { + filename = "${path.module}/inventory.ini" + content = templatefile("${path.module}/inventory.tmpl", { + webservers = local.webservers_for_ansible + databases = local.databases_for_ansible + storage = local.storage_for_ansible + }) + + depends_on = [ + yandex_compute_instance.web, + yandex_compute_instance.db-vm, + yandex_compute_instance.storage + ] +} \ No newline at end of file diff --git a/src/count-vm.tf b/src/count-vm.tf new file mode 100644 index 0000000000..d678e32b77 --- /dev/null +++ b/src/count-vm.tf @@ -0,0 +1,35 @@ +resource "yandex_compute_instance" "web" { + count = var.web_vm_config.count + + name = "web-${count.index + 1}" + platform_id = var.web_vm_config.platform_id + zone = var.zone + + resources { + cores = var.web_vm_config.cpu + memory = var.web_vm_config.ram + core_fraction = var.web_vm_config.core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu.id + size = var.web_vm_config.disk_size + } + } + + network_interface { + subnet_id = yandex_vpc_subnet.default.id + nat = true + security_group_ids = [yandex_vpc_security_group.web-sg.id] + } + + metadata = { + ssh-keys = "ubuntu:${local.public_ssh_key}" + hostname = "web-${count.index + 1}" + } + + depends_on = [ + yandex_compute_instance.db-vm + ] +} \ No newline at end of file diff --git a/src/data.tf b/src/data.tf new file mode 100644 index 0000000000..5379da18bb --- /dev/null +++ b/src/data.tf @@ -0,0 +1,12 @@ +data "yandex_compute_image" "ubuntu" { + family = "ubuntu-2204-lts" +} + +data "yandex_vpc_network" "default" { + name = "default-network" +} + + +data "yandex_vpc_subnet" "default" { + name = "default-subnet" +} \ No newline at end of file diff --git a/src/disk_vm.tf b/src/disk_vm.tf new file mode 100644 index 0000000000..f990a278ce --- /dev/null +++ b/src/disk_vm.tf @@ -0,0 +1,53 @@ +resource "yandex_compute_disk" "storage_disk" { + count = var.storage_disks_config.count + + name = "storage-disk-${count.index + 1}" + type = var.storage_disks_config.type + zone = var.zone + size = var.storage_disks_config.size + + labels = { + environment = "storage" + disk-number = "${count.index + 1}" + } +} + +resource "yandex_compute_instance" "storage" { + name = "storage" + platform_id = var.storage_vm_config.platform_id + zone = var.zone + + resources { + cores = var.storage_vm_config.cpu + memory = var.storage_vm_config.ram + core_fraction = var.storage_vm_config.core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu.id + size = var.storage_vm_config.disk_size + } + } + + dynamic "secondary_disk" { + for_each = yandex_compute_disk.storage_disk[*].id + content { + disk_id = secondary_disk.value + } + } + + network_interface { + subnet_id = yandex_vpc_subnet.default.id + nat = true + } + + metadata = { + ssh-keys = "ubuntu:${local.public_ssh_key}" + hostname = "storage" + } + + depends_on = [ + yandex_compute_disk.storage_disk + ] +} \ No newline at end of file diff --git a/src/for_each-vm.tf b/src/for_each-vm.tf new file mode 100644 index 0000000000..29e2fa5ec7 --- /dev/null +++ b/src/for_each-vm.tf @@ -0,0 +1,39 @@ +locals { + db_vms_map = { + for vm in var.each_vm : + vm.vm_name => vm + } +} + + +# Создание ВМ для баз данных с использованием for_each +resource "yandex_compute_instance" "db-vm" { + for_each = local.db_vms_map + + name = each.value.vm_name + platform_id = "standard-v1" + zone = var.zone + + resources { + cores = each.value.cpu + memory = each.value.ram + core_fraction = 20 + } + + boot_disk { + initialize_params { + image_id = var.image_id + size = each.value.disk_volume + } + } + + network_interface { + subnet_id = yandex_vpc_subnet.default.id + nat = true + } + + metadata = { + ssh-keys = "ubuntu:${local.public_ssh_key}" + hostname = each.value.vm_name + } +} \ No newline at end of file diff --git a/src/inventory.tmpl b/src/inventory.tmpl new file mode 100644 index 0000000000..cbf5d9ce8c --- /dev/null +++ b/src/inventory.tmpl @@ -0,0 +1,17 @@ +# Ansible inventory for Yandex Cloud instances +# Generated by Terraform + +[webservers] +web-1 ansible_host=111.88.241.58 fqdn=fhmn3r5757okl9pvh844.auto.internal +web-2 ansible_host=130.193.38.215 fqdn=fhmimdnu2a3as7ontiha.auto.internal + +[databases] +main ansible_host=51.250.0.127 fqdn=fhmde9jbcfgoesjfrhmu.auto.internal +replica ansible_host=111.88.251.165 fqdn=fhmj5a5h90gbgnpv5tu8.auto.internal + +[storage] +storage ansible_host=51.250.78.218 fqdn=fhmfitmbm6s56jk4849v.auto.internal + +[all:vars] +ansible_user=ubuntu +ansible_ssh_private_key_file=~/.ssh/id_rsa diff --git a/src/main.tf b/src/main.tf new file mode 100644 index 0000000000..f5fe5fb77b --- /dev/null +++ b/src/main.tf @@ -0,0 +1,14 @@ +provider "yandex" { + token = var.yc_token + cloud_id = var.yc_cloud_id + folder_id = var.yc_folder_id + zone = var.zone +} + + +resource "yandex_vpc_subnet" "default" { + name = "default-subnet" + zone = var.zone + network_id = yandex_vpc_network.default.id + v4_cidr_blocks = var.v4_cidr_blocks +} \ No newline at end of file diff --git a/src/outputs.tf b/src/outputs.tf new file mode 100644 index 0000000000..3c101077b4 --- /dev/null +++ b/src/outputs.tf @@ -0,0 +1,42 @@ +output "web_vm_ips" { + description = "External IP addresses of web VMs" + value = { + for i, vm in yandex_compute_instance.web : + vm.name => vm.network_interface[0].nat_ip_address + } +} + +output "db_vm_ips" { + description = "External IP addresses of database VMs" + value = { + for name, vm in yandex_compute_instance.db-vm : + name => vm.network_interface[0].nat_ip_address + } +} + +output "storage_vm_ip" { + description = "External IP address of storage VM" + value = yandex_compute_instance.storage.network_interface[0].nat_ip_address +} + +output "vms_fqdn" { + description = "FQDN of all created VMs" + value = { + web = { + for vm in yandex_compute_instance.web : + vm.name => vm.fqdn + } + db = { + for name, vm in yandex_compute_instance.db-vm : + name => vm.fqdn + } + storage = { + storage = yandex_compute_instance.storage.fqdn + } + } +} + +output "inventory_file" { + description = "Path to generated Ansible inventory" + value = local_file.ansible_inventory.filename +} \ No newline at end of file diff --git a/src/personal.auto.tfvars_example b/src/personal.auto.tfvars_example new file mode 100644 index 0000000000..22c0272d1a --- /dev/null +++ b/src/personal.auto.tfvars_example @@ -0,0 +1,3 @@ +token = "" +cloud_id = "" +folder_id = "" diff --git a/src/providers.tf b/src/providers.tf new file mode 100644 index 0000000000..5eb525965b --- /dev/null +++ b/src/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + yandex = { + source = "yandex-cloud/yandex" + } + } + required_version = "~>1.12.0" +} + +provider "yandex" { + token = var.token + cloud_id = var.cloud_id + folder_id = var.folder_id + zone = var.default_zone +} \ No newline at end of file diff --git a/src/security.tf b/src/security.tf new file mode 100644 index 0000000000..6f052c0829 --- /dev/null +++ b/src/security.tf @@ -0,0 +1,21 @@ +resource "yandex_vpc_security_group" "web-sg" { + name = "web-security-group" + description = "Security group for web VMs" + network_id = yandex_vpc_network.default.id + + dynamic "ingress" { + for_each = local.security_group_ingress_rules + content { + description = ingress.value.description + protocol = ingress.value.protocol + port = ingress.value.port + v4_cidr_blocks = ingress.value.v4_cidr_blocks + } + } + + egress { + description = "All outcoming" + protocol = "ANY" + v4_cidr_blocks = var.public_access_cidrs + } +} \ No newline at end of file diff --git a/src/variables.tf b/src/variables.tf new file mode 100644 index 0000000000..ccf3be607d --- /dev/null +++ b/src/variables.tf @@ -0,0 +1,148 @@ +variable "yc_token" { + description = "Yandex Cloud OAuth token" + type = string + sensitive = true +} + +variable "yc_cloud_id" { + description = "Yandex Cloud cloud ID" + type = string +} + +variable "yc_folder_id" { + description = "Yandex Cloud folder ID" + type = string +} + + +variable "zone" { + description = "Yandex Cloud availability zone" + type = string + default = "ru-central1-a" +} + +variable "v4_cidr_blocks" { + description = "CIDR blocks for subnet" + type = list(string) + default = ["10.0.1.0/24"] +} + +variable "public_access_cidrs" { + description = "CIDR blocks for public access" + type = list(string) + default = ["0.0.0.0/0"] +} + + +variable "web_vm_config" { + description = "Configuration for web VMs" + type = object({ + count = number + cpu = number + ram = number + disk_size = number + core_fraction = number + platform_id = string + }) + default = { + count = 2 + cpu = 2 + ram = 2 + disk_size = 10 + core_fraction = 20 + platform_id = "standard-v1" + } +} + + +variable "database_vms" { + description = "Configuration for database VMs" + type = list(object({ + name = string + cpu = number + ram = number + disk_volume = number + })) + default = [ + { + name = "main" + cpu = 2 + ram = 4 + disk_volume = 20 + }, + { + name = "replica" + cpu = 4 + ram = 8 + disk_volume = 30 + } + ] +} + + +variable "storage_disks_config" { + description = "Configuration for storage disks" + type = object({ + count = number + size = number + type = string + }) + default = { + count = 3 + size = 1 + type = "network-hdd" + } +} + + +variable "storage_vm_config" { + description = "Configuration for storage VM" + type = object({ + cpu = number + ram = number + disk_size = number + core_fraction = number + platform_id = string + }) + default = { + cpu = 2 + ram = 2 + disk_size = 10 + core_fraction = 20 + platform_id = "standard-v1" + } +} + + +variable "security_group_rules" { + description = "Security group rules" + type = map(object({ + description = string + protocol = string + port = number + })) + default = { + http = { + description = "HTTP" + protocol = "TCP" + port = 80 + } + https = { + description = "HTTPS" + protocol = "TCP" + port = 443 + } + ssh = { + description = "SSH" + protocol = "TCP" + port = 22 + } + } +} + + +variable "ssh_public_key_path" { + description = "Path to SSH public key" + type = string + default = "~/.ssh/id_rsa.pub" +} \ No newline at end of file