diff --git a/.gitignore b/.gitignore index 551c1a05..46f9f650 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,13 @@ # own secret vars store. personal.auto.tfvars +# в этом файле ничег осекретного, поэтому добавляю в гит без опасений +#terraform.tfvars -terraform.tfvars +# а вот тут секретики, поэтому не показываю +personal.auto.tfvars + +tfplan -tfplan \ No newline at end of file +# тут ключ от квартиры, где деньги лежат +yc-terraform-training-acc-key.json diff --git a/01/hw-01.md b/01/hw-01.md index 9cc9b37c..822736f8 100644 --- a/01/hw-01.md +++ b/01/hw-01.md @@ -9,79 +9,163 @@ ### Чек-лист готовности к домашнему заданию -1. Скачайте и установите **Terraform** версии >=1.8.4 . Приложите скриншот вывода команды ```terraform --version```. -2. Скачайте на свой ПК этот git-репозиторий. Исходный код для выполнения задания расположен в директории **01/src**. -3. Убедитесь, что в вашей ОС установлен docker. +image ------ -### Инструменты и дополнительные материалы, которые пригодятся для выполнения задания - -1. Репозиторий с ссылкой на зеркало для установки и настройки Terraform: [ссылка](https://github.com/netology-code/devops-materials). -2. Установка docker: [ссылка](https://docs.docker.com/engine/install/ubuntu/). ------- -### Внимание!! Обязательно предоставляем на проверку получившийся код в виде ссылки на ваш github-репозиторий! ------- ### Задание 1 -1. Перейдите в каталог [**src**](https://github.com/netology-code/ter-homeworks/tree/main/01/src). Скачайте все необходимые зависимости, использованные в проекте. -2. Изучите файл **.gitignore**. В каком terraform-файле, согласно этому .gitignore, допустимо сохранить личную, секретную информацию?(логины,пароли,ключи,токены итд) -3. Выполните код проекта. Найдите в state-файле секретное содержимое созданного ресурса **random_password**, пришлите в качестве ответа конкретный ключ и его значение. -4. Раскомментируйте блок кода, примерно расположенный на строчках 29–42 файла **main.tf**. -Выполните команду ```terraform validate```. Объясните, в чём заключаются намеренно допущенные ошибки. Исправьте их. -5. Выполните код. В качестве ответа приложите: исправленный фрагмент кода и вывод команды ```docker ps```. -6. Замените имя docker-контейнера в блоке кода на ```hello_world```. Не перепутайте имя контейнера и имя образа. Мы всё ещё продолжаем использовать name = "nginx:latest". Выполните команду ```terraform apply -auto-approve```. -Объясните своими словами, в чём может быть опасность применения ключа ```-auto-approve```. Догадайтесь или нагуглите зачем может пригодиться данный ключ? В качестве ответа дополнительно приложите вывод команды ```docker ps```. -8. Уничтожьте созданные ресурсы с помощью **terraform**. Убедитесь, что все ресурсы удалены. Приложите содержимое файла **terraform.tfstate**. -9. Объясните, почему при этом не был удалён docker-образ **nginx:latest**. Ответ **ОБЯЗАТЕЛЬНО НАЙДИТЕ В ПРЕДОСТАВЛЕННОМ КОДЕ**, а затем **ОБЯЗАТЕЛЬНО ПОДКРЕПИТЕ** строчкой из документации [**terraform провайдера docker**](https://docs.comcloud.xyz/providers/kreuzwerker/docker/latest/docs). (ищите в классификаторе resource docker_image ) +1. Терраформ инициализирован, зависимости скачаны + +image + +2. Личную секретную информациюдопустимо хранить в `personal.auto.tfvars`, т.к. он игнорируется и не попадает в репозиторий. И более того, он даже подписан комментарием `# own secret vars store.` + +3. Безуспешные попытки получить пароль средствами Терраформа: +image + +При этом пароь в явном виде есть в файле `terraform.tfstate` + +image + + +**Пароль: AgA2Q1IDjYamAdzh** + + +4. Ошибка 1: Missing name for resource + +image + +Суть ошибки - в Terraform каждый ресурс должен иметь два лейбла (type, name), а в файле только "docker_image". + +Ошибка 2: Invalid resource name + +image + +Суть ошибки: Имя ресурса не может начинаться с цифры (1nginx). Имя должно начинаться с буквы или подчёркивания. Разрешены только буквы, цифры, подчёркивание и дефис. + +Ошибка 3: Reference to undeclared resource + +image + +Суть ошибки: задано имя ресурса `random_password.random_string_FAKE`, которого нет в конфигурации (нужно убрать `_FAKE`), нужно исправить последнюю букву в слове `resulT` на строчную. +Исправление: +``` +terraform { + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "~> 3.0.1" + } + } + required_version = ">=1.8.4" /*Многострочный комментарий. + Требуемая версия terraform */ +} +provider "docker" {} + +#однострочный комментарий + +resource "random_password" "random_string" { + length = 16 + special = false + min_upper = 1 + min_lower = 1 + min_numeric = 1 +} + + +resource "docker_image" "nginx" { + name = "nginx:latest" + keep_locally = true +} + + +resource "docker_container" "nginx1" { + image = docker_image.nginx.image_id + name = "example_${random_password.random_string.result}" + + ports { + internal = 80 + external = 9090 + } +} +``` + +5. Исправленный main.tf выше. +Вывод команды `docker ps`: + +image + + +6. Опасность применения ключа `-auto-approve` в том, что он позволяет применить все изменения без подтверждения. Т.е. есть явный риск случайно удалить или изменить важные ресурсы без предварительной проверки. +Польза - для автоматизации, когда код заведомо работает и подтверждения не требуется, либо для тестовой среды, где нет риска удалить что-то важное. + +Новый вывод команды ```docker ps```. + +image + + +7. Ресурсы уничтожены: + +image + +Содержимое файла **terraform.tfstate**: + +image + +8. При уничтожении ресурсов с помощью команды `terraform destroy` Docker-образ `nginx:latest` не был удалён и остался на сервере, потому что в коде нет указания его удалить. В Terraform-провайдере Docker для ресурса docker_image это управляется параметром `keep_locally`. Если `keep_locally = false`, образ будет удалён; если keep_locally = true или параметр не задан, образ останется на сервере. ------ ## Дополнительное задание (со звёздочкой*) -**Настоятельно рекомендуем выполнять все задания со звёздочкой.** Они помогут глубже разобраться в материале. -Задания со звёздочкой дополнительные, не обязательные к выполнению и никак не повлияют на получение вами зачёта по этому домашнему заданию. - ### Задание 2* -1. Создайте в облаке ВМ. Сделайте это через web-консоль, чтобы не слить по незнанию токен от облака в github(это тема следующей лекции). Если хотите - попробуйте сделать это через terraform, прочитав документацию yandex cloud. Используйте файл ```personal.auto.tfvars``` и гитигнор или иной, безопасный способ передачи токена! -2. Подключитесь к ВМ по ssh и установите стек docker. -3. Найдите в документации docker provider способ настроить подключение terraform на вашей рабочей станции к remote docker context вашей ВМ через ssh. -4. Используя terraform и remote docker context, скачайте и запустите на вашей ВМ контейнер ```mysql:8``` на порту ```127.0.0.1:3306```, передайте ENV-переменные. Сгенерируйте разные пароли через random_password и передайте их в контейнер, используя интерполяцию из примера с nginx.(```name = "example_${random_password.random_string.result}"``` , двойные кавычки и фигурные скобки обязательны!) +(Не нашёл в доке kreuzwerker/docker способа поднять контейнер именно на 127.0.0.1) + +`main.tf` получился такой: +https://github.com/wiqt8r/terraform-homeworks/blob/main/01/src/main.tf + +Наличие секретных env-переменных в контейнере: + +image + + +### Задание 3* +1. Tofu установлен: + +image + +2. Получить провайдеры из registry.opentofu.org не вышло - видимо, санкции. ``` - environment: - - "MYSQL_ROOT_PASSWORD=${...}" - - MYSQL_DATABASE=wordpress - - MYSQL_USER=wordpress - - "MYSQL_PASSWORD=${...}" - - MYSQL_ROOT_HOST="%" +Could not resolve provider kreuzwerker/docker: could not connect to registry.opentofu.org: failed to request discovery document: 403 Forbidden ``` +Скачал их с гитхаба. -6. Зайдите на вашу ВМ , подключитесь к контейнеру и проверьте наличие секретных env-переменных с помощью команды ```env```. Запишите ваш финальный код в репозиторий. +image -### Задание 3* -1. Установите [opentofu](https://opentofu.org/)(fork terraform с лицензией Mozilla Public License, version 2.0) любой версии -2. Попробуйте выполнить тот же код с помощью ```tofu apply```, а не terraform apply. ------- +Пришлось повозиться с `~/.tofurc` и прописать явный путь к провайдерам. +``` +provider_installation { + filesystem_mirror { + path = "/home/wiqtor/.opentofu/plugins" + include = ["registry.opentofu.org/hashicorp/random", "registry.opentofu.org/kreuzwerker/docker"] + } +} +``` -### Правила приёма работы +Установил локально -Домашняя работа оформляется в отдельном GitHub-репозитории в файле README.md. -Выполненное домашнее задание пришлите ссылкой на .md-файл в вашем репозитории. +image -### Критерии оценки +Развернул: -Зачёт ставится, если: +image -* выполнены все задания, -* ответы даны в развёрнутой форме, -* приложены соответствующие скриншоты и файлы проекта, -* в выполненных заданиях нет противоречий и нарушения логики. +Работает: -На доработку работу отправят, если: +image -* задание выполнено частично или не выполнено вообще, -* в логике выполнения заданий есть противоречия и существенные недостатки. diff --git a/01/src/.terraformrc b/01/src/.terraformrc index 9bc77282..1fc85eb5 100644 --- a/01/src/.terraformrc +++ b/01/src/.terraformrc @@ -1,9 +1,9 @@ provider_installation { network_mirror { - url = "https://terraform-mirror.yandexcloud.net/" - include = ["registry.terraform.io/*/*"] + url = "https://registry.comcloud.xyz/" } direct { exclude = ["registry.terraform.io/*/*"] } -} \ No newline at end of file +} + diff --git a/01/src/main.tf b/01/src/main.tf index 18f88532..8cc8df19 100644 --- a/01/src/main.tf +++ b/01/src/main.tf @@ -2,37 +2,47 @@ terraform { required_providers { docker = { source = "kreuzwerker/docker" - version = "~> 3.0.1" + version = "~> 3.8.0" } } - required_version = ">=1.8.4" /*Многострочный комментарий. - Требуемая версия terraform */ + required_version = ">=1.8.4" } -provider "docker" {} -#однострочный комментарий +provider "docker" { + host = "ssh://wqtr@89.169.167.232:22" +} -resource "random_password" "random_string" { - length = 16 - special = false - min_upper = 1 - min_lower = 1 - min_numeric = 1 +resource "random_password" "mysql_root" { + length = 16 + upper = true + lower = true + numeric = true + special = false } -/* -resource "docker_image" { - name = "nginx:latest" - keep_locally = true +resource "random_password" "mysql_user" { + length = 16 + upper = true + lower = true + numeric = true + special = false } -resource "docker_container" "1nginx" { - image = docker_image.nginx.image_id - name = "example_${random_password.random_string_FAKE.resulT}" +resource "docker_container" "mysql" { + image = "mysql:8" + name = "example_${random_password.mysql_root.result}" ports { - internal = 80 - external = 9090 + internal = 3306 + external = 3306 } + + env = [ + "MYSQL_ROOT_PASSWORD=${random_password.mysql_root.result}", + "MYSQL_DATABASE=wordpress", + "MYSQL_USER=wordpress", + "MYSQL_PASSWORD=${random_password.mysql_user.result}", + "MYSQL_ROOT_HOST=%" + ] } -*/ + diff --git a/02/hw-02.md b/02/hw-02.md index aafadb13..4f79f387 100644 --- a/02/hw-02.md +++ b/02/hw-02.md @@ -1,167 +1,579 @@ # Домашнее задание к занятию «Основы Terraform. Yandex Cloud» -### Цели задания +### Задание 1 -1. Создать свои ресурсы в облаке Yandex Cloud с помощью Terraform. -2. Освоить работу с переменными Terraform. +Сервисный аккаунт и ключ созданы +image -### Чек-лист готовности к домашнему заданию +SSH-ключ есть, переменная `vms_ssh_public_root_key` записана в `personal.auto.tfvars` -1. Зарегистрирован аккаунт в Yandex Cloud. Использован промокод на грант. -2. Установлен инструмент Yandex CLI. -3. Исходный код для выполнения задания расположен в директории [**02/src**](https://github.com/netology-code/ter-homeworks/tree/main/02/src). +image +Проект инициализируется, `terraform plan` завершается предупреждениями: +``` +Value for undeclared variable +The root module does not declare a variable named "service_account_key_file" +The root module does not declare a variable named "vms_ssh_public_root_key" +``` +То есть в personal.auto.tfvars указаны эти переменные, но в коде `variables.tf`` нет блоков variable с этими именами. Нужно добавить их: -### Задание 0 +Возникает ошибка: -1. Ознакомьтесь с [документацией к security-groups в Yandex Cloud](https://cloud.yandex.ru/docs/vpc/concepts/security-groups?from=int-console-help-center-or-nav). -Этот функционал понадобится к следующей лекции. +image ------- -### Внимание!! Обязательно предоставляем на проверку получившийся код в виде ссылки на ваш github-репозиторий! ------- +Потому что service_account_key_file задан явно, а не переменной: `service_account_key_file = file("~/.authorized_key.json")`. Надо сделать: `var.service_account_key_file`. -### Задание 1 -В качестве ответа всегда полностью прикладывайте ваш terraform-код в git. -Убедитесь что ваша версия **Terraform** ~>1.8.4 +image + +Возникают ошибки +"Platform "standart-v4" not found" - потому чти типа ВМ "standart-v4" в яндексе нет, нужно исправить main.tf и указать в ресурсе **platform_id = "standard-v3"** (т.е. Intel Ice Lake) +"the specified core fraction is not available" - потому что минимальная доля ЦПУ для ВМ 20%. Нужно указать `core_fraction = 20`. +"the specified number of cores is not available" - потому что минимальное количество ядер для standard-v3 - 2 + +Ошибки в resource исправлены: +image + +Также в main.tf указано `ssh-keys = "ubuntu:${var.vms_ssh_root_key}"`, исправлено на `${var.vms_ssh_public_root_key}"`, чтобы ключ корректно подкидывался в создаваемую ВМ. -1. Изучите проект. В файле variables.tf объявлены переменные для Yandex provider. -2. Создайте сервисный аккаунт и ключ. [service_account_key_file](https://terraform-provider.yandexcloud.net). -4. Сгенерируйте новый или используйте свой текущий ssh-ключ. Запишите его открытую(public) часть в переменную **vms_ssh_public_root_key**. -5. Инициализируйте проект, выполните код. Исправьте намеренно допущенные синтаксические ошибки. Ищите внимательно, посимвольно. Ответьте, в чём заключается их суть. -6. Подключитесь к консоли ВМ через ssh и выполните команду ``` curl ifconfig.me```. -Примечание: К OS ubuntu "out of a box, те из коробки" необходимо подключаться под пользователем ubuntu: ```"ssh ubuntu@vm_ip_address"```. Предварительно убедитесь, что ваш ключ добавлен в ssh-агент: ```eval $(ssh-agent) && ssh-add``` Вы познакомитесь с тем как при создании ВМ создать своего пользователя в блоке metadata в следующей лекции.; -8. Ответьте, как в процессе обучения могут пригодиться параметры ```preemptible = true``` и ```core_fraction=5``` в параметрах ВМ. -В качестве решения приложите: +После исправления -код исполняется, ресурс создан: -- скриншот ЛК Yandex Cloud с созданной ВМ, где видно внешний ip-адрес; -- скриншот консоли, curl должен отобразить тот же внешний ip-адрес; -- ответы на вопросы. +image + + +Посл подключения по SSH: + +image + +По поводу `preemptible = true` и `core_fraction=5` объяснялось на вебинаре. +- preemptible это прерываемая ВМ с ограниченным временем работы (до 24 часов), может быть автоматически остановлена в любой момент для высвобожения ресурсов. +- core fraction ограничивает гарантированную долю процессорного времени, которое доступно ВМ. Полезно для легких задач, не требующих значительной вычислительной мощности. +Оба параметра позволяют существенно экономить средства и запускать легковесные ВМ для экспериментов при учёбе. ### Задание 2 1. Замените все хардкод-**значения** для ресурсов **yandex_compute_image** и **yandex_compute_instance** на **отдельные** переменные. К названиям переменных ВМ добавьте в начало префикс **vm_web_** . Пример: **vm_web_name**. 2. Объявите нужные переменные в файле variables.tf, обязательно указывайте тип переменной. Заполните их **default** прежними значениями из main.tf. -3. Проверьте terraform plan. Изменений быть не должно. +3. Проверьте terraform plan. Изменений быть не должно. + +Хардкод-значения в main.tf такие: +- name = "netology-develop-platform-web" - будет переменная vm_web_name +- platform_id = "standard-v3" - будет переменная vm_web_platform_id +- cores = 2 - будет переменная vm_web_cores +- memory = 1 - будет переменная vm_web_memory +- core_fraction = 20 - будет переменная vm_web_core_fraction +- preemptible = true - будет переменная vm_web_preemptible +- image_id в boot_disk.initialize_params - здесь использую data.yandex_compute_image.ubuntu.family через переменную vm_web_image_family + +Добавляю в `variables.tf`: +``` +variable "vm_web_name" { + type = string + default = "netology-develop-platform-web" +} + +variable "vm_web_platform_id" { + type = string + default = "standard-v3" +} + +variable "vm_web_cores" { + type = number + default = 2 +} + +variable "vm_web_memory" { + type = number + default = 1 +} + +variable "vm_web_core_fraction" { + type = number + default = 20 +} + +variable "vm_web_preemptible" { + type = bool + default = true +} + +variable "vm_web_image_family" { + type = string + default = "ubuntu-2004-lts" +} +``` + +Меняю `yandex_compute_image` и `yandex_compute_instance` в main.tf: +``` +data "yandex_compute_image" "ubuntu" { + family = var.vm_web_image_family +} + +resource "yandex_compute_instance" "platform" { + name = var.vm_web_name + platform_id = var.vm_web_platform_id + + resources { + cores = var.vm_web_cores + memory = var.vm_web_memory + core_fraction = var.vm_web_core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu.id + } + } + + scheduling_policy { + preemptible = var.vm_web_preemptible + } + + network_interface { + subnet_id = yandex_vpc_subnet.develop.id + nat = true + } + + metadata = { + serial-port-enable = 1 + ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" + } +} +``` + +В результате `terraform plan` отрабатывает корректно, `terraform apply` создаёт такую же ВМ: + +image + ### Задание 3 -1. Создайте в корне проекта файл 'vms_platform.tf' . Перенесите в него все переменные первой ВМ. -2. Скопируйте блок ресурса и создайте с его помощью вторую ВМ в файле main.tf: **"netology-develop-platform-db"** , ```cores = 2, memory = 2, core_fraction = 20```. Объявите её переменные с префиксом **vm_db_** в том же файле ('vms_platform.tf'). ВМ должна работать в зоне "ru-central1-b" -3. Примените изменения. +Изменения применены, разворачивается две ВМ в двух зонах доступности: + +image + +Текущий main.tf: +``` +resource "yandex_vpc_network" "develop" { + name = var.vpc_name +} + +# Первая подсеть для первой ВМ +resource "yandex_vpc_subnet" "develop" { + name = var.vpc_name + zone = var.default_zone + network_id = yandex_vpc_network.develop.id + v4_cidr_blocks = var.default_cidr +} + +# Вторая подсеть для второй ВМ +resource "yandex_vpc_subnet" "develop_b" { + name = "${var.vpc_name}-b" + zone = var.vm_db_zone + network_id = yandex_vpc_network.develop.id + v4_cidr_blocks = var.vm_db_cidr +} + +# Первая ВМ +data "yandex_compute_image" "ubuntu" { + family = var.vm_web_image_family +} + +resource "yandex_compute_instance" "platform" { + name = var.vm_web_name + platform_id = var.vm_web_platform_id + + resources { + cores = var.vm_web_cores + memory = var.vm_web_memory + core_fraction = var.vm_web_core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu.id + } + } + + scheduling_policy { + preemptible = var.vm_web_preemptible + } + + network_interface { + subnet_id = yandex_vpc_subnet.develop.id + nat = true + } + + metadata = { + serial-port-enable = 1 + ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" + } +} + +# Вторая ВМ +data "yandex_compute_image" "ubuntu_db" { + family = var.vm_db_image_family +} + +resource "yandex_compute_instance" "platform_db" { + name = var.vm_db_name + platform_id = var.vm_db_platform_id + + resources { + cores = var.vm_db_cores + memory = var.vm_db_memory + core_fraction = var.vm_db_core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu_db.id + } + } + + scheduling_policy { + preemptible = var.vm_db_preemptible + } + + network_interface { + subnet_id = yandex_vpc_subnet.develop_b.id + nat = true + } + + zone = var.vm_db_zone + + metadata = { + serial-port-enable = 1 + ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" + } +} +``` + +Текущий vms_platform.tf: +``` +# Переменные первой ВМ + +variable "vm_web_name" { + type = string + default = "netology-develop-platform-web" +} + +variable "vm_web_platform_id" { + type = string + default = "standard-v3" +} + +variable "vm_web_cores" { + type = number + default = 2 +} + +variable "vm_web_memory" { + type = number + default = 1 +} + +variable "vm_web_core_fraction" { + type = number + default = 20 +} + +variable "vm_web_preemptible" { + type = bool + default = true +} + +variable "vm_web_image_family" { + type = string + default = "ubuntu-2004-lts" +} + +# Переменные второй ВМ + +variable "vm_db_name" { + type = string + default = "netology-develop-platform-db" +} + +variable "vm_db_platform_id" { + type = string + default = "standard-v3" +} + +variable "vm_db_cores" { + type = number + default = 2 +} + +variable "vm_db_memory" { + type = number + default = 2 +} + +variable "vm_db_core_fraction" { + type = number + default = 20 +} + +variable "vm_db_preemptible" { + type = bool + default = true +} + +variable "vm_db_image_family" { + type = string + default = "ubuntu-2004-lts" +} + +variable "vm_db_zone" { + type = string + default = "ru-central1-b" +} + +variable "vm_db_cidr" { + type = list(string) + default = ["10.0.2.0/24"] +} +``` ### Задание 4 -1. Объявите в файле outputs.tf **один** output , содержащий: instance_name, external_ip, fqdn для каждой из ВМ в удобном лично для вас формате.(без хардкода!!!) -2. Примените изменения. +Содержимое outputs.tf: +``` +output "vms_info" { + description = "Созданные ВМ - результат:" + value = [ + { + instance_name = yandex_compute_instance.platform.name + external_ip = yandex_compute_instance.platform.network_interface[0].nat_ip_address + fqdn = yandex_compute_instance.platform.fqdn + }, + { + instance_name = yandex_compute_instance.platform_db.name + external_ip = yandex_compute_instance.platform_db.network_interface[0].nat_ip_address + fqdn = yandex_compute_instance.platform_db.fqdn + } + ] +} +``` + +Вывод `terraform output`: + +image -В качестве решения приложите вывод значений ip-адресов команды ```terraform output```. ### Задание 5 -1. В файле locals.tf опишите в **одном** local-блоке имя каждой ВМ, используйте интерполяцию ${..} с НЕСКОЛЬКИМИ переменными по примеру из лекции. -2. Замените переменные внутри ресурса ВМ на созданные вами local-переменные. -3. Примените изменения. +Поскольку задача использовать имменно несколько переменных - можно задвть в variables.tf переменные, из которых будем собирать имя: +``` +variable "environment" { + type = string + default = "env" +} + +variable "role_web" { + type = string + default = "web" +} + +variable "role_db" { + type = string + default = "db" +} +``` +После этого в locals.tf задать блок с именами: +``` +locals { + vm_web_full_name = "${var.vpc_name}-${var.environment}-platform-${var.role_web}" + vm_db_full_name = "${var.vpc_name}-${var.environment}-platform-${var.role_db}" +} +``` +А затем в main.tf прописать в name виртуальных машин поля из locals: +- В блоке `resource "yandex_compute_instance" "platform"`: +``` +name = local.vm_web_full_name +``` +- В блоке `resource "yandex_compute_instance" "platform_db"`: +``` +name = local.vm_db_full_name +``` + +В итоге получаем имена ВМ в аутпуте: + +image + + ### Задание 6 -1. Вместо использования трёх переменных ".._cores",".._memory",".._core_fraction" в блоке resources {...}, объедините их в единую map-переменную **vms_resources** и внутри неё конфиги обеих ВМ в виде вложенного map(object). - ``` - пример из terraform.tfvars: - vms_resources = { - web={ - cores=2 - memory=2 - core_fraction=5 - hdd_size=10 - hdd_type="network-hdd" - ... - }, - db= { - cores=2 - memory=4 - core_fraction=20 - hdd_size=10 - hdd_type="network-ssd" - ... - } - } - ``` -3. Создайте и используйте отдельную map(object) переменную для блока metadata, она должна быть общая для всех ваших ВМ. - ``` - пример из terraform.tfvars: - metadata = { - serial-port-enable = 1 - ssh-keys = "ubuntu:ssh-ed25519 AAAAC..." - } - ``` - -5. Найдите и закоментируйте все, более не используемые переменные проекта. -6. Проверьте terraform plan. Изменений быть не должно. +Создаем `terraform.tfvars`: +``` +# конфигурации ресурсов ВМ +vms_resources = { + web = { + cores = 2 + memory = 1 + core_fraction = 20 + hdd_size = 5 + hdd_type = "network-hdd" + preemptible = true + } + + db = { + cores = 2 + memory = 2 + core_fraction = 20 + hdd_size = 5 + hdd_type = "network-hdd" + preemptible = true + } +} +``` +Добавляем метадату в personal.auto.tfvars, чтобы не светить лишнего в коде +``` +# метадата для ВМ +vms_metadata = { + serial-port-enable = 1 + ssh-keys = "ubuntu:ssh-ed25519 AAAAневажно wiqtor@home-server" +} +``` ------- +Добавляем в `vms_platform.tf` блок переменных для ресурсов и метадаты: +``` +# переменная для ресурсов ВМ +variable "vms_resources" { + description = "Ресурсы для ВМ" + type = map(object({ + cores = number + memory = number + core_fraction = number + hdd_size = number + hdd_type = string + preemptible = bool + })) +} + +# переменная для metadata +variable "vms_metadata" { + description = "метадата для ВМ" + type = map(string) +} +``` +После этого там же в vms_platform нужно закоммеентировать эти переменные - они больше не нужны: +``` +variable "vm_web_cores" +variable "vm_web_memory" +variable "vm_web_core_fraction" +variable "vm_web_preemptible" +variable "vm_db_cores" +variable "vm_db_memory" +variable "vm_db_core_fraction" +variable "vm_db_preemptible" +``` -## Дополнительное задание (со звёздочкой*) +Затем нужно поменять блоки ресурсов в main.tf, чтобы он брал новые переменные: +Для первой ВМ platform: +``` +resources { + cores = var.vms_resources["web"].cores + memory = var.vms_resources["web"].memory + core_fraction = var.vms_resources["web"].core_fraction +} + +boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu.id + size = var.vms_resources["web"].hdd_size + type = var.vms_resources["web"].hdd_type + } +} + +scheduling_policy { + preemptible = var.vms_resources["web"].preemptible +} + +metadata = var.vms_metadata +``` +Для второй ВМ platform_db: +``` +resources { + cores = var.vms_resources["db"].cores + memory = var.vms_resources["db"].memory + core_fraction = var.vms_resources["db"].core_fraction +} + +boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu_db.id + size = var.vms_resources["db"].hdd_size + type = var.vms_resources["db"].hdd_type + } +} + +scheduling_policy { + preemptible = var.vms_resources["db"].preemptible +} + +metadata = var.vms_metadata +``` +Проверяем, что всё правильно через `terraform plan` - всё сходится, изменений нет: + +image -**Настоятельно рекомендуем выполнять все задания со звёздочкой.** -Они помогут глубже разобраться в материале. Задания со звёздочкой дополнительные, не обязательные к выполнению и никак не повлияют на получение вами зачёта по этому домашнему заданию. ------ -### Задание 7* -Изучите содержимое файла console.tf. Откройте terraform console, выполните следующие задания: +## Дополнительное задание (со звёздочкой*) +------ +### Задание 7* -1. Напишите, какой командой можно отобразить **второй** элемент списка test_list. -2. Найдите длину списка test_list с помощью функции length(<имя переменной>). -3. Напишите, какой командой можно отобразить значение ключа admin из map test_map. +1. Напишите, какой командой можно отобразить **второй** элемент списка test_list. `local.test_list[1]` +2. Найдите длину списка test_list с помощью функции length(<имя переменной>). `length(local.test_list)` +3. Напишите, какой командой можно отобразить значение ключа admin из map test_map. `local.test_map["admin"]` 4. Напишите interpolation-выражение, результатом которого будет: "John is admin for production server based on OS ubuntu-20-04 with X vcpu, Y ram and Z virtual disks", используйте данные из переменных test_list, test_map, servers и функцию length() для подстановки значений. +`"${local.test_map["admin"]} is admin for ${local.test_list[2]} server based on OS ${local.servers.production.image} with ${local.servers.production.cpu} vcpu, ${local.servers.production.ram} ram and ${length(local.servers.production.disks)} virtual disks"` -**Примечание**: если не догадаетесь как вычленить слово "admin", погуглите: "terraform get keys of map" +Результат с сервера: + +image -В качестве решения предоставьте необходимые команды и их вывод. ------ ### Задание 8* -1. Напишите и проверьте переменную test и полное описание ее type в соответствии со значением из terraform.tfvars: -``` -test = [ - { - "dev1" = [ - "ssh -o 'StrictHostKeyChecking=no' ubuntu@62.84.124.117", - "10.0.1.7", - ] - }, - { - "dev2" = [ - "ssh -o 'StrictHostKeyChecking=no' ubuntu@84.252.140.88", - "10.0.2.29", - ] - }, - { - "prod1" = [ - "ssh -o 'StrictHostKeyChecking=no' ubuntu@51.250.2.101", - "10.0.1.30", - ] - }, -] -``` -2. Напишите выражение в terraform console, которое позволит вычленить строку "ssh -o 'StrictHostKeyChecking=no' ubuntu@62.84.124.117" из этой переменной. ------- +Добавляем указанное значение в terraform.tfvars. +После этого ззадаем переменную в variables.tf +``` +variable "test" { + description = "тестовая переменная для получения строки SSH подключения" + type = list( + map( + list(string) + ) + ) +} +``` +Теперь можно использовать выражение в terraform console для получения нужного результата: + +image + ------ ### Задание 9* -Используя инструкцию https://cloud.yandex.ru/ru/docs/vpc/operations/create-nat-gateway#tf_1, настройте для ваших ВМ nat_gateway. Для проверки уберите внешний IP адрес (nat=false) у ваших ВМ и проверьте доступ в интернет с ВМ, подключившись к ней через serial console. Для подключения предварительно через ssh измените пароль пользователя: ```sudo passwd ubuntu``` +NAT gateway настроен, внешний IP адрес у ВМ отключен (nat=false), из серийной консоли восьмёрки пингуются: + +image + + ### Правила приёма работыДля подключения предварительно через ssh измените пароль пользователя: sudo passwd ubuntu В качестве результата прикрепите ссылку на MD файл с описанием выполненой работы в вашем репозитории. Так же в репозитории должен присутсвовать ваш финальный код проекта. diff --git a/02/src/locals.tf b/02/src/locals.tf index e69de29b..2b6f28b9 100644 --- a/02/src/locals.tf +++ b/02/src/locals.tf @@ -0,0 +1,4 @@ +locals { + vm_web_full_name = "${var.vpc_name}-${var.environment}-platform-${var.role_web}" + vm_db_full_name = "${var.vpc_name}-${var.environment}-platform-${var.role_db}" +} diff --git a/02/src/main.tf b/02/src/main.tf index 49baf600..dfb57f52 100644 --- a/02/src/main.tf +++ b/02/src/main.tf @@ -1,41 +1,124 @@ resource "yandex_vpc_network" "develop" { name = var.vpc_name } + +# NAT-шлюз +resource "yandex_vpc_gateway" "nat_gateway" { + name = "${var.vpc_name}-nat-gateway" + folder_id = var.folder_id + shared_egress_gateway {} +} + +# Таблица маршрутизации для NAT +resource "yandex_vpc_route_table" "nat_route" { + name = "${var.vpc_name}-route-table" + folder_id = var.folder_id + network_id = yandex_vpc_network.develop.id + + static_route { + destination_prefix = "0.0.0.0/0" + gateway_id = yandex_vpc_gateway.nat_gateway.id + } +} + +# Первая подсеть для первой ВМ resource "yandex_vpc_subnet" "develop" { name = var.vpc_name zone = var.default_zone network_id = yandex_vpc_network.develop.id v4_cidr_blocks = var.default_cidr + route_table_id = yandex_vpc_route_table.nat_route.id } +# Вторая подсеть для второй ВМ +resource "yandex_vpc_subnet" "develop_b" { + name = "${var.vpc_name}-b" + zone = var.vm_db_zone + network_id = yandex_vpc_network.develop.id + v4_cidr_blocks = var.vm_db_cidr + route_table_id = yandex_vpc_route_table.nat_route.id +} +# Первая ВМ data "yandex_compute_image" "ubuntu" { - family = "ubuntu-2004-lts" + family = var.vm_web_image_family } + resource "yandex_compute_instance" "platform" { - name = "netology-develop-platform-web" - platform_id = "standart-v4" + name = local.vm_web_full_name + platform_id = var.vm_web_platform_id + resources { - cores = 1 - memory = 1 - core_fraction = 5 + cores = var.vms_resources["web"].cores + memory = var.vms_resources["web"].memory + core_fraction = var.vms_resources["web"].core_fraction } + boot_disk { initialize_params { - image_id = data.yandex_compute_image.ubuntu.image_id + image_id = data.yandex_compute_image.ubuntu.id + size = var.vms_resources["web"].hdd_size + type = var.vms_resources["web"].hdd_type } } + scheduling_policy { - preemptible = true + preemptible = var.vms_resources["web"].preemptible } + network_interface { subnet_id = yandex_vpc_subnet.develop.id nat = true } - metadata = { - serial-port-enable = 1 - ssh-keys = "ubuntu:${var.vms_ssh_root_key}" +# metadata = { +# serial-port-enable = 1 +# ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" +# } + metadata = var.vms_metadata + +} + +# Вторая ВМ +data "yandex_compute_image" "ubuntu_db" { + family = var.vm_db_image_family +} + +resource "yandex_compute_instance" "platform_db" { + name = local.vm_db_full_name + platform_id = var.vm_db_platform_id + + resources { + cores = var.vms_resources["db"].cores + memory = var.vms_resources["db"].memory + core_fraction = var.vms_resources["db"].core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu_db.id + size = var.vms_resources["db"].hdd_size + type = var.vms_resources["db"].hdd_type + } + } + + scheduling_policy { + preemptible = var.vms_resources["db"].preemptible + } + + network_interface { + subnet_id = yandex_vpc_subnet.develop_b.id + nat = true } + zone = var.vm_db_zone + +# metadata = { +# serial-port-enable = 1 +# ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" +# } + + metadata = var.vms_metadata } + + diff --git a/02/src/main.tf.old b/02/src/main.tf.old new file mode 100644 index 00000000..9a40676c --- /dev/null +++ b/02/src/main.tf.old @@ -0,0 +1,102 @@ +resource "yandex_vpc_network" "develop" { + name = var.vpc_name +} + +# Первая подсеть для первой ВМ +resource "yandex_vpc_subnet" "develop" { + name = var.vpc_name + zone = var.default_zone + network_id = yandex_vpc_network.develop.id + v4_cidr_blocks = var.default_cidr +} + +# Вторая подсеть для второй ВМ +resource "yandex_vpc_subnet" "develop_b" { + name = "${var.vpc_name}-b" + zone = var.vm_db_zone + network_id = yandex_vpc_network.develop.id + v4_cidr_blocks = var.vm_db_cidr +} + +# Первая ВМ +data "yandex_compute_image" "ubuntu" { + family = var.vm_web_image_family +} + +resource "yandex_compute_instance" "platform" { + name = local.vm_web_full_name + platform_id = var.vm_web_platform_id + + resources { + cores = var.vms_resources["web"].cores + memory = var.vms_resources["web"].memory + core_fraction = var.vms_resources["web"].core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu.id + size = var.vms_resources["web"].hdd_size + type = var.vms_resources["web"].hdd_type + } + } + + scheduling_policy { + preemptible = var.vms_resources["web"].preemptible + } + + network_interface { + subnet_id = yandex_vpc_subnet.develop.id + nat = true + } + +# metadata = { +# serial-port-enable = 1 +# ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" +# } + metadata = var.vms_metadata + +} + +# Вторая ВМ +data "yandex_compute_image" "ubuntu_db" { + family = var.vm_db_image_family +} + +resource "yandex_compute_instance" "platform_db" { + name = local.vm_db_full_name + platform_id = var.vm_db_platform_id + + resources { + cores = var.vms_resources["db"].cores + memory = var.vms_resources["db"].memory + core_fraction = var.vms_resources["db"].core_fraction + } + + boot_disk { + initialize_params { + image_id = data.yandex_compute_image.ubuntu_db.id + size = var.vms_resources["db"].hdd_size + type = var.vms_resources["db"].hdd_type + } + } + + scheduling_policy { + preemptible = var.vms_resources["db"].preemptible + } + + network_interface { + subnet_id = yandex_vpc_subnet.develop_b.id + nat = true + } + + zone = var.vm_db_zone + +# metadata = { +# serial-port-enable = 1 +# ssh-keys = "ubuntu:${var.vms_ssh_public_root_key}" +# } + + metadata = var.vms_metadata +} + diff --git a/02/src/outputs.tf b/02/src/outputs.tf index e69de29b..abe291b2 100644 --- a/02/src/outputs.tf +++ b/02/src/outputs.tf @@ -0,0 +1,15 @@ +output "vms_info" { + description = "Созданные ВМ - результат:" + value = [ + { + instance_name = yandex_compute_instance.platform.name + external_ip = yandex_compute_instance.platform.network_interface[0].nat_ip_address + fqdn = yandex_compute_instance.platform.fqdn + }, + { + instance_name = yandex_compute_instance.platform_db.name + external_ip = yandex_compute_instance.platform_db.network_interface[0].nat_ip_address + fqdn = yandex_compute_instance.platform_db.fqdn + } + ] +} diff --git a/02/src/providers.tf b/02/src/providers.tf index fae4dc37..45e1272e 100644 --- a/02/src/providers.tf +++ b/02/src/providers.tf @@ -12,5 +12,5 @@ provider "yandex" { cloud_id = var.cloud_id folder_id = var.folder_id zone = var.default_zone - service_account_key_file = file("~/.authorized_key.json") + service_account_key_file = var.service_account_key_file } diff --git a/02/src/terraform.tfvars b/02/src/terraform.tfvars new file mode 100644 index 00000000..f0caa7c2 --- /dev/null +++ b/02/src/terraform.tfvars @@ -0,0 +1,44 @@ +# конфигурации ресурсов ВМ +vms_resources = { + web = { + cores = 2 + memory = 1 + core_fraction = 20 + hdd_size = 5 + hdd_type = "network-hdd" + preemptible = true + } + + db = { + cores = 2 + memory = 2 + core_fraction = 20 + hdd_size = 5 + hdd_type = "network-hdd" + preemptible = true + } +} + +# переменная для теста + +test = [ + { + "dev1" = [ + "ssh -o 'StrictHostKeyChecking=no' ubuntu@62.84.124.117", + "10.0.1.7", + ] + }, + { + "dev2" = [ + "ssh -o 'StrictHostKeyChecking=no' ubuntu@84.252.140.88", + "10.0.2.29", + ] + }, + { + "prod1" = [ + "ssh -o 'StrictHostKeyChecking=no' ubuntu@51.250.2.101", + "10.0.1.30", + ] + }, +] + diff --git a/02/src/variables.tf b/02/src/variables.tf index 8e1bb4f1..ad1f0afb 100644 --- a/02/src/variables.tf +++ b/02/src/variables.tf @@ -1,5 +1,4 @@ -###cloud vars - +# cloud vars variable "cloud_id" { type = string @@ -29,10 +28,43 @@ variable "vpc_name" { } -###ssh vars +# ssh vars + +variable "service_account_key_file" { + type = string + description = "Путь к ключу яндекса" +} -variable "vms_ssh_root_key" { +variable "vms_ssh_public_root_key" { type = string - default = "" - description = "ssh-keygen -t ed25519" + description = "Публичный ключ SSH для root-пользователя" +} + +# name vars + +variable "environment" { + type = string + default = "env" +} + +variable "role_web" { + type = string + default = "web" +} + +variable "role_db" { + type = string + default = "db" +} + +# new "test" var + +variable "test" { + description = "тестовая переменная для получения строки SSH подключения" + type = list( + map( + list(string) + ) + ) } + diff --git a/02/src/vms_platform.tf b/02/src/vms_platform.tf new file mode 100644 index 00000000..b00d873e --- /dev/null +++ b/02/src/vms_platform.tf @@ -0,0 +1,103 @@ +# Переменные первой ВМ + +variable "vm_web_name" { + type = string + default = "netology-develop-platform-web" +} + +variable "vm_web_platform_id" { + type = string + default = "standard-v3" +} + +#variable "vm_web_cores" { +# type = number +# default = 2 +#} + +#variable "vm_web_memory" { +# type = number +# default = 1 +#} + +#variable "vm_web_core_fraction" { +# type = number +# default = 20 +#} + +#variable "vm_web_preemptible" { +# type = bool +# default = true +#} + +variable "vm_web_image_family" { + type = string + default = "ubuntu-2004-lts" +} + +# Переменные второй ВМ + +variable "vm_db_name" { + type = string + default = "netology-develop-platform-db" +} + +variable "vm_db_platform_id" { + type = string + default = "standard-v3" +} + +#variable "vm_db_cores" { +# type = number +# default = 2 +#} + +#variable "vm_db_memory" { +# type = number +# default = 2 +#} + +#variable "vm_db_core_fraction" { +# type = number +# default = 20 +#} + +#variable "vm_db_preemptible" { +# type = bool +# default = true +#} + +variable "vm_db_image_family" { + type = string + default = "ubuntu-2004-lts" +} + +variable "vm_db_zone" { + type = string + default = "ru-central1-b" +} + +variable "vm_db_cidr" { + type = list(string) + default = ["10.0.2.0/24"] +} + +# переменная для ресурсов ВМ +variable "vms_resources" { + description = "Ресурсы для ВМ" + type = map(object({ + cores = number + memory = number + core_fraction = number + hdd_size = number + hdd_type = string + preemptible = bool + })) +} + +# переменная для metadata +variable "vms_metadata" { + description = "метадата для ВМ" + type = map(string) +} + diff --git a/03/demo/providers.tf b/03/demo/providers.tf index c9e7d5a6..bcce36df 100644 --- a/03/demo/providers.tf +++ b/03/demo/providers.tf @@ -4,7 +4,7 @@ terraform { source = "yandex-cloud/yandex" } } - required_version = ">=1.8.4" + required_version = "~>1.12.0" } provider "yandex" { diff --git a/03/hw-03.md b/03/hw-03.md index 25863404..5ad17b40 100644 --- a/03/hw-03.md +++ b/03/hw-03.md @@ -17,7 +17,7 @@ ------ ### Внимание!! Обязательно предоставляем на проверку получившийся код в виде ссылки на ваш github-репозиторий! -Убедитесь что ваша версия **Terraform** ~>1.8.4 +Убедитесь что ваша версия **Terraform** ~>1.12.0 Теперь пишем красивый код, хардкод значения не допустимы! ------ diff --git a/03/src/providers.tf b/03/src/providers.tf index 1f337849..5eb52596 100644 --- a/03/src/providers.tf +++ b/03/src/providers.tf @@ -4,7 +4,7 @@ terraform { source = "yandex-cloud/yandex" } } - required_version = "~>1.8.4" + required_version = "~>1.12.0" } provider "yandex" {