diff --git a/00_manifest.csv b/00_manifest.csv index f1e96f7..3d7a85e 100644 --- a/00_manifest.csv +++ b/00_manifest.csv @@ -144,4 +144,15 @@ VKC_CASE_03_migration_РемизовКЛ_20260619.md,CASE,M08,CASE_03,Анали VKC_CASE_03_migration_IvanovII_20260619.drawio.png,DIAGRAM,M08,CASE_03,Схема целевой архитектуры интернет-магазина в VK Cloud,04_diagrams/VKC_CASE_03_migration_IvanovII_20260619.drawio.png,,final, VKC_ARCH_M08_highload_store_REPORT_РемизовКЛ_20260619.md,CASE,M08,8.2,Проектирование высоконагруженной архитектуры интернет-магазина,01_reports/VKC_ARCH_M08_highload_store_REPORT_РемизовКЛ_20260619.md,,final, VKC_ARCH_M08_highload_store_diogram_РемизовКЛ_20260619.drawio.png,DIAGRAM,M08,8.2,Схема архитектуры высоконагруженного интернет-магазина,04_diagrams/VKC_ARCH_M08_highload_store_diogram_РемизовКЛ_20260619.drawio.png,VKC_ARCH_M08_highload_store_REPORT_РемизовКЛ_20260619.md,final, +VKC_PROJ_V01_README_РемизовКЛ_20260628.md,PROJ,PROJ,V01,README итогового проекта,01_reports/VKC_PROJ_V01_README_РемизовКЛ_20260628.md,,final, +VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4,EVIDENCE,PROJ,V01,Видеообзор демонстрации,05_exports/VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4,final +VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf,PRESENTATION,PROJ,V01,Презентация итогового проекта,05_exports/VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf,final +VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png,DIAGRAM,PROJ,V01,Архитектурная схема,04_diagrams/VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png,final +VKC_PROJ_V01_ab_log_РемизовКЛ_20260628.log,EVIDENCE,PROJ,V01,Лог нагрузочного тестирования ab,02_evidence/VKC_PROJ_V01_ab_log_RemizovKL_20260628.log,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, +VKC_PROJ_V01_curl_log_РемизовКЛ_20260628.log,EVIDENCE,PROJ,V01,Лог curl -v к /DevOps,02_evidence/VKC_PROJ_V01_curl_log_RemizovKL_20260628.log,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, +VKC_PROJ_V01_ssh_log_РемизовКЛ_20260628.log,EVIDENCE,PROJ,V01,Лог SSH-подключений,02_evidence/VKC_PROJ_V01_ssh_log_RemizovKL_20260628.log,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, +VKC_PROJ_V01_main_РемизовКЛ_20260628.tf,CODE,PROJ,V01,Основной код Terraform,03_code/VKC_PROJ_V01_main_РемизовКЛ_20260628.tf,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, +VKC_PROJ_V01_variables_РемизовКЛ_20260628.tf,CODE,PROJ,V01,Переменные Terraform,03_code/VKC_PROJ_V01_variables_РемизовКЛ_20260628.tf,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, +VKC_PROJ_V01_outputs_РемизовКЛ_20260628.tf,CODE,PROJ,V01,Выходные переменные Terraform,03_code/VKC_PROJ_V01_outputs_РемизовКЛ_20260628.tf,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, +VKC_PROJ_V01_backend_РемизовКЛ_20260628.tf,CODE,PROJ,V01,Настройка бэкенда S3,03_code/VKC_PROJ_V01_backend_РемизовКЛ_20260628.tf,VKC_PROJ_V01_README_РемизовКЛ_20260628.md,final, 00_manifest.csv,MANIFEST,all,all,Финальный манифест сдачи,00_manifest.csv,,final, diff --git a/01_reports/VKC_PROJ_V01_README_РемизовКЛ_20260628.md b/01_reports/VKC_PROJ_V01_README_РемизовКЛ_20260628.md new file mode 100644 index 0000000..970b6a1 --- /dev/null +++ b/01_reports/VKC_PROJ_V01_README_РемизовКЛ_20260628.md @@ -0,0 +1,191 @@ +--- +course_code: VKCLOUD-80 +artifact_type: PROJ +project_variant: 1 +project_title: Отказоустойчивый веб-хостинг на Docker + Terraform (VK Cloud) +student_fio: Ремизов Кирилл Львович +date: 2026-06-28 +source_docs: + - Д1 + - Д9 +attached_files: + - VKC_PROJ_V01_demo_video_RemizovKL_20260628.mp4 + - VKC_PROJ_V01_ab_log_RemizovKL_20260628.log + - VKC_PROJ_V01_curl_log_RemizovKL_20260628.log + - VKC_PROJ_V01_ssh_log_RemizovKL_20260628.log + - VKC_PROJ_V01_terraform_state_list_RemizovKL_20260628.txt + - VKC_PROJ_V01_architecture.drawio.png + - VKC_PROJ_V01_backend_РемизовКЛ_20260628.tf + - VKC_PROJ_V01_main_РемизовКЛ_20260628.tf + - VKC_PROJ_V01_outputs_РемизовКЛ_20260628.tf + - VKC_PROJ_V01_variables_РемизовКЛ_20260628.tf +repo_url: + - https://github.com/BlackCorbeau/final_assessment + - https://git.rustprogersteam.ru/Black_Raven/MyResume +demo_url: http://95.163.213.173/DevOps +status: final +--- + +# README итогового проекта + +## 1. Цель проекта + +Развернуть отказоустойчивую инфраструктуру для веб‑приложения (сайт‑резюме), упакованного в Docker‑образ, с использованием виртуальных машин, балансировщика нагрузки и управляемой базы данных (PostgreSQL) в облаке VK Cloud. Вся инфраструктура описывается кодом (Terraform), управляется через GitHub Actions и обеспечивает доступность сайта при отказе одного из веб‑серверов (SLA 99.9%). + +## 2. Выбранный вариант и почему он выбран + +**Выбран вариант №1 из Документа 9** – *«Отказоустойчивый веб‑хостинг на ВМ»*, но с заменой ручного Nginx на Docker‑контейнер с собственным приложением. + +**Почему выбран:** +- Этот вариант покрывает все ключевые темы курса: сеть, безопасность, балансировка, работа с базами данных, автоматизация. +- Он позволяет продемонстрировать навыки работы с Terraform, Docker, CI/CD и облачными сервисами VK Cloud. +- Стек соответствует реальным задачам промышленной эксплуатации. +- Проект имеет чёткие критерии успеха и позволяет наглядно показать отказоустойчивость. + +## 3. Архитектура + +### Схема + +![Архитектурная схема](VKC_PROJ_V01_architecture.drawio.png) + +*Схема создана в draw.io и отражает все компоненты инфраструктуры.* + +### Основные компоненты + +- **Виртуальные машины**: + - **2 веб‑сервера** (flavor `Basic-1-1-10`) в приватной подсети – на каждом запущен Docker‑контейнер с приложением (образ из приватного реестра). + - **Бастион** (flavor `Basic-1-1-10`) в публичной подсети – единственная точка входа по SSH для управления. +- **Балансировщик нагрузки** (Application L7) с публичным Floating IP – распределяет HTTP‑трафик между веб‑серверами, выполняет health‑check по пути `/DevOps`. +- **Управляемая PostgreSQL** (flavor `Standard-2-8-50`) – создана в приватной подсети, но приложение к ней не подключается (архитектурный задел для будущей интеграции). + +### Сетевой контур + +- **VPC** с двумя подсетями: + - **public** (192.168.1.0/24) – для балансировщика и бастиона. + - **private** (192.168.2.0/24) – для веб‑серверов и БД. +- Интернет‑шлюз подключён к роутеру, обеспечивает доступ к публичным IP. +- Бастион имеет Floating IP, доступ по SSH разрешён только с моего IP-адреса. + +### Безопасность + +- **Security Groups**: + - `main` – разрешает HTTP (80) для всех, SSH (22) только с моего IP, исходящий трафик разрешён. + - `db_sg` – разрешает доступ к PostgreSQL (5432) только из приватной подсети. +- SSH‑доступ к веб‑серверам возможен только через бастион (используется проброс агента или скопированный ключ). +- Пароль к БД задан в коде (захардкожен для упрощения, в продакшене следует использовать переменные окружения или Vault). + +### Мониторинг + +- Health‑check балансировщика по HTTP `/DevOps` – проверяет доступность приложения. +- Нагрузочное тестирование с `ab` подтверждает стабильность (99.9% успешных запросов). + +### Управление затратами + +- Использованы минимальные флейворы `Basic-1-1-10` для ВМ и `Standard-2-8-50` для БД. +- Все ресурсы управляются Terraform, после защиты будут удалены командой `terraform destroy`. +- State хранится в S3, что исключает потерю состояния и лишние расходы. + +## 4. Используемый стек + +| Компонент | Технология | +|--------------------|------------------------------------------| +| Инфраструктура | Terraform (provider vkcs) | +| Оркестрация | Docker (контейнеры на ВМ) | +| Балансировка | VK Cloud Load Balancer (Application L7) | +| База данных | VK Cloud DBaaS (PostgreSQL 14) | +| CI/CD | GitHub Actions | +| Хранение состояния | S3 (VK Cloud Object Storage) | +| Язык приложения | Python (Flask) + Gunicorn | +| Контейнеризация | Docker, образ из приватного реестра | + +## 5. Репозитории проекта + +Исходный код проекта размещён в двух репозиториях: + +- **GitHub (основной)** – [https://github.com/BlackCorbeau/final_assessment](https://github.com/BlackCorbeau/final_assessment) +- **Forgejo (зеркало)** – [https://git.rustprogersteam.ru/Black_Raven/MyResume](https://git.rustprogersteam.ru/Black_Raven/MyResume) + +## 6. Порядок развертывания + +1. **Подготовка окружения:** + - Убедиться, что установлены Terraform, OpenStack CLI, Docker (локально). + - Получить RC‑файл для доступа к VK Cloud, экспортировать переменные окружения или задать их в `terraform.tfvars`. + - Создать S3‑бакет для хранения state (имя `tf-state-final-assessment`). + +2. **Клонирование репозитория:** + ```bash + git clone https://github.com/BlackCorbeau/final_assessment.git + cd final_assessment/terraform + ``` + +3. **Настройка переменных:** + - Скопировать `terraform.tfvars.example` в `terraform.tfvars` и заполнить все обязательные переменные: + ```hcl + my_ip = "ваш_публичный_IP/32" + project_name = "final_assessment" + docker_image = "git.rustprogersteam.ru/black_raven/myresume/resume:latest" + vkcs_username = "..." + vkcs_password = "..." + vkcs_project_id = "..." + vkcs_region = "RegionOne" + vkcs_auth_url = "https://infra.mail.ru:35357/v3/" + ssh_public_key = "~/.ssh/id_rsa.pub" + ``` + +4. **Инициализация и применение:** + ```bash + terraform init + terraform plan + terraform apply -auto-approve + ``` + +5. **Автоматический деплой через GitHub Actions:** + - При пуше в ветку `main` workflow выполняет `terraform plan` и `apply` автоматически (требуются секреты: `VKCS_USERNAME`, `VKCS_PASSWORD`, `VKCS_PROJECT_ID`, `VKCS_AUTH_URL`, `MY_IP`, `SSH_PUBLIC_KEY` и др.). + +6. **Проверка outputs:** + - После успешного apply получаем: + - `load_balancer_ip` – публичный IP балансировщика. + - `bastion_floating_ip` – IP бастиона. + - `db_host`, `db_name`, `db_user`, `db_password` – параметры БД. + +## 7. Проверка работоспособности + +Все этапы проверки зафиксированы в видеообзоре `VKC_PROJ_V01_demo_video_RemizovKL_20260628.mp4`: + +| Этап | Действие | Метка времени в видео | +| ---- | ---------------------------------------------------------------------------------------------- | --------------------- | +| 1 | Просмотр созданных ресурсов в консоли VK Cloud (ВМ, балансировщик, БД) | 00:00 – 01:13 | +| 2 | Проверка доступности сайта через браузер (http://95.163.213.173/DevOps) | 01:14 – 01:26 | +| 3 | Подключение к бастиону и веб‑серверам через SSH, проверка запущенных контейнеров (`docker ps`) | 01:27 – 01:50 | +| 4 | Остановка контейнера на web-1 (`docker stop`), проверка, что сайт продолжает работать | 01:51 – 03:09 | +| 5 | Запуск контейнера обратно (`docker start`), возвращение в пул | 03:10 – 04:15 | +| 6 | Подключение к PostgreSQL через `psql` (подтверждение наличия БД) | 04:16 – 05:32 | +| 7 | Нагрузочное тестирование `ab -n 1000 -c 10` с выводом результатов | 05:33 – 05:53 | + +Также приложены отдельные логи: +- `VKC_PROJ_V01_ab_log_RemizovKL_20260628.log` – полный вывод нагрузочного теста. +- `VKC_PROJ_V01_curl_log_RemizovKL_20260628.log` – вывод `curl -v`. +- `VKC_PROJ_V01_ssh_log_RemizovKL_20260628.log` – лог SSH-сессий. + +## 8. Известные ограничения + +- Пароль БД захардкожен в коде – в продакшене использовать переменные. +- Health‑check использует `/DevOps` (не выделенный `/health`). +- Образ собран с тегом `latest` – обновление требует ручного изменения тега. +- Отсутствует мониторинг (Prometheus/Grafana) – проект сфокусирован на базовой отказоустойчивости. + +## 9. Приложенные файлы + +| Файл | Назначение | +|------|------------| +| `VKC_PROJ_V01_README_RemizovKL_20260628.md` | Данный файл – полный отчёт по проекту. | +| `VKC_PROJ_V01_demo_video_RemizovKL_20260628.mp4` | **Видеообзор** со всеми этапами проверки (сайт, SSH, отказоустойчивость, нагрузка, БД, консоль). | +| `VKC_PROJ_V01_ab_log_RemizovKL_20260628.log` | Лог нагрузочного тестирования `ab`. | +| `VKC_PROJ_V01_curl_log_RemizovKL_20260628.log` | Лог `curl -v` к `/DevOps`. | +| `VKC_PROJ_V01_ssh_log_RemizovKL_20260628.log` | Лог SSH-подключений и проверки контейнеров. | +| `VKC_PROJ_V01_terraform_state_list_RemizovKL_20260628.txt` | Вывод `terraform state list`. | +| `VKC_PROJ_V01_architecture.drawio.png` | Архитектурная схема. | + +--- + +**Итог:** Проект полностью соответствует требованиям варианта №1, все критерии успеха выполнены, инфраструктура работоспособна и готова к защите. Видеообзор содержит все необходимые доказательства. diff --git a/02_evidence/VKC_PROJ_V01_ab_log_РемизовКЛ_20260628.log b/02_evidence/VKC_PROJ_V01_ab_log_РемизовКЛ_20260628.log new file mode 100644 index 0000000..310abc6 --- /dev/null +++ b/02_evidence/VKC_PROJ_V01_ab_log_РемизовКЛ_20260628.log @@ -0,0 +1,56 @@ + ~/rosatom/final_asessment_terraform +nix-shell ❯ ab -n 1000 -c 10 http://95.163.213.173/DevOps via 💠 default on ☁️ (ru-msk) +This is ApacheBench, Version 2.3 <$Revision: 1923142 $> +Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ +Licensed to The Apache Software Foundation, http://www.apache.org/ + +Benchmarking 95.163.213.173 (be patient) +Completed 100 requests +Completed 200 requests +Completed 300 requests +Completed 400 requests +Completed 500 requests +Completed 600 requests +Completed 700 requests +Completed 800 requests +Completed 900 requests +Completed 1000 requests +Finished 1000 requests + + +Server Software: gunicorn +Server Hostname: 95.163.213.173 +Server Port: 80 + +Document Path: /DevOps +Document Length: 10796 bytes + +Concurrency Level: 10 +Time taken for tests: 13.065 seconds +Complete requests: 1000 +Failed requests: 1 + (Connect: 0, Receive: 0, Length: 1, Exceptions: 0) +Total transferred: 10922067 bytes +HTML transferred: 10785204 bytes +Requests per second: 76.54 [#/sec] (mean) +Time per request: 130.653 [ms] (mean) +Time per request: 13.065 [ms] (mean, across all concurrent requests) +Transfer rate: 816.36 [Kbytes/sec] received + +Connection Times (ms) + min mean[+/-sd] median max +Connect: 0 0 0.1 0 1 +Processing: 25 114 334.8 62 5001 +Waiting: 0 105 296.8 57 4156 +Total: 25 114 334.8 62 5001 + +Percentage of the requests served within a certain time (ms) + 50% 62 + 66% 73 + 75% 79 + 80% 83 + 90% 95 + 95% 113 + 98% 1114 + 99% 2100 + 100% 5001 (longest request) diff --git a/02_evidence/VKC_PROJ_V01_curl_log_РемизовКЛ_20260628.log b/02_evidence/VKC_PROJ_V01_curl_log_РемизовКЛ_20260628.log new file mode 100644 index 0000000..fe5d8da --- /dev/null +++ b/02_evidence/VKC_PROJ_V01_curl_log_РемизовКЛ_20260628.log @@ -0,0 +1,266 @@ + ~/r/final_assessment/terraform on main [?ok] +nix-shell ❯ curl -v http://95.163.213.173/DevOps via 💠 default on ☁️ (ru-msk) +* Trying 95.163.213.173:80... +* Established connection to 95.163.213.173 (95.163.213.173 port 80) from 198.18.0.1 port 57226 +* using HTTP/1.x +> GET /DevOps HTTP/1.1 +> Host: 95.163.213.173 +> User-Agent: curl/8.20.0 +> Accept: */* +> +* Request completely sent off +< HTTP/1.1 200 OK +< server: gunicorn +< date: Sun, 28 Jun 2026 10:29:17 GMT +< content-type: text/html; charset=utf-8 +< content-length: 10796 +< + + + + + + Кирилл Ремизов + + + + + + +
+
+
+ +
+
+ +
+
+ +
+

Ремизов Кирилл Львович

+
Интересующее направление: SRE/DevOps инженер
+ +

Студент 3 курса ННГУ им. Лобачевского по направлению "Программная инженерия" (Средний бал: 3,85). Стремлюсь к профессиональному росту: изучаю новые технологии, алгоритмы и подходы к разработке. Как молодой специалист, подхожу к работе с энтузиазмом и готов вкладываться в сложные проекты.

+ +
+
+
+ +
+
+ +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+
+ + Образование +
+

2023–2027 ННГУ им. Лобачевского, Нижний Новгород

+

Программная инженерия

+
+ + +
+
+ + Достижения +
+

2025 Участие в хакатоне от IT-холдинга Т1, 3-е место.

+
+ + +
+
+ + Языки +
+
    +
  • Английский (B2)
  • +
  • Французский (разговорный)
  • +
+
+ + +
+
+ + Soft Skills +
+
    +
  • Ответственный и пунктуальный
  • +
  • Любовь к своему делу
  • +
  • Умение работать в команде
  • +
  • Открыт к обмену опытом
  • +
+
+
+ + +
+ +
+
+ + Технические навыки +
+ +
+
+ C++ + 5/5 +
+
+
+
+
+ +
+
+ Rust + 4/5 +
+
+
+
+
+ +
+
+ SQL + 3/5 +
+
+
+
+
+ +
+
+ Python + 2/5 +
+
+
+
+
+ +
+
+ CI/CD + 5/5 +
+
+
+
+
+ +
+
+ Linux + 5/5 +
+
+
+
+
+ +
+
+ Docker + 5/5 +
+
+
+
+
+
+ + +
+
+ + Профессиональные навыки +
+
+
    +
  • Работа с терминалом
  • +
  • Vim
  • +
  • Docker
  • +
+
    +
  • Kubernetes
  • +
  • *nix системы
  • +
+
+
+ + +
+
+ + Репозиторий проекта +
+

Исходный код этого резюме доступны в репозитории:

+ + + https://git.rustprogersteam.ru/Black_Raven/MyResume + +
+
+
+ + + + + +* Connection #0 to host 95.163.213.173:80 left intact +% diff --git a/02_evidence/VKC_PROJ_V01_ssh_log_РемизовКЛ_20260628.log b/02_evidence/VKC_PROJ_V01_ssh_log_РемизовКЛ_20260628.log new file mode 100644 index 0000000..f35231c --- /dev/null +++ b/02_evidence/VKC_PROJ_V01_ssh_log_РемизовКЛ_20260628.log @@ -0,0 +1,138 @@ + ~/r/final_assessment/terraform on main [ok] +nix-shell ❯ scp -i ~/.ssh/id_rsa ~/.ssh/id_rsa ubuntu@95.163.215.1:/home/ubuntu/.ssh/id_rsa via 💠 default on ☁️ (ru-msk) +The authenticity of host '95.163.215.1 (95.163.215.1)' can't be established. +ED25519 key fingerprint is: SHA256:IhiPDFfSS5rEQ83Sws/pkRp91/BsVD+kiZJwhG6G/H8 +This key is not known by any other names. +Are you sure you want to continue connecting (yes/no/[fingerprint])? yes +Warning: Permanently added '95.163.215.1' (ED25519) to the list of known hosts. +** WARNING: connection is not using a post-quantum key exchange algorithm. +** This session may be vulnerable to "store now, decrypt later" attacks. +** The server may need to be upgraded. See https://openssh.com/pq.html +id_rsa 100% 2602 192.9KB/s 00:00 + + ~/r/final_assessment/terraform on main [ok] +nix-shell ❯ ssh -A -i ~/.ssh/id_rsa ubuntu@95.163.215.1 via 💠 default on ☁️ (ru-msk) +** WARNING: connection is not using a post-quantum key exchange algorithm. +** This session may be vulnerable to "store now, decrypt later" attacks. +** The server may need to be upgraded. See https://openssh.com/pq.html +Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-216-generic x86_64) + + * Documentation: https://help.ubuntu.com + * Management: https://landscape.canonical.com + * Support: https://ubuntu.com/pro + + System information as of Sun Jun 28 10:23:32 UTC 2026 + + System load: 0.0 Processes: 101 + Usage of /: 9.0% of 19.20GB Users logged in: 0 + Memory usage: 20% IPv4 address for ens3: 192.168.1.10 + Swap usage: 0% + + +Expanded Security Maintenance for Infrastructure is not enabled. + +0 updates can be applied immediately. + +128 additional security updates can be applied with ESM Infra. +Learn more about enabling ESM Infra service for Ubuntu 20.04 at +https://ubuntu.com/20-04 + +New release '22.04.5 LTS' available. +Run 'do-release-upgrade' to upgrade to it. + + +Last login: Sun Jun 28 10:11:57 2026 from 95.26.148.233 +ubuntu@final-assessment-bastion:~$ ssh ubuntu@192.168.2.10 # теперь должно работать +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! +Someone could be eavesdropping on you right now (man-in-the-middle attack)! +It is also possible that a host key has just been changed. +The fingerprint for the ECDSA key sent by the remote host is +SHA256:zXGSX2Tz1E2gWu5hYFEpl0465z0zTQAR4+3hjRQOQnc. +Please contact your system administrator. +Add correct host key in /home/ubuntu/.ssh/known_hosts to get rid of this message. +Offending ECDSA key in /home/ubuntu/.ssh/known_hosts:1 + remove with: + ssh-keygen -f "/home/ubuntu/.ssh/known_hosts" -R "192.168.2.10" +ECDSA host key for 192.168.2.10 has changed and you have requested strict checking. +Host key verification failed. +ubuntu@final-assessment-bastion:~$ rm ~/.ssh/ +authorized_keys id_rsa known_hosts +ubuntu@final-assessment-bastion:~$ rm ~/.ssh/ +authorized_keys id_rsa known_hosts +ubuntu@final-assessment-bastion:~$ rm ~/.ssh/known_hosts +ubuntu@final-assessment-bastion:~$ ssh ubuntu@192.168.2.10 # теперь должно работать +The authenticity of host '192.168.2.10 (192.168.2.10)' can't be established. +ECDSA key fingerprint is SHA256:zXGSX2Tz1E2gWu5hYFEpl0465z0zTQAR4+3hjRQOQnc. +Are you sure you want to continue connecting (yes/no/[fingerprint])? ye +Please type 'yes', 'no' or the fingerprint: yes +Warning: Permanently added '192.168.2.10' (ECDSA) to the list of known hosts. +Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-216-generic x86_64) + + * Documentation: https://help.ubuntu.com + * Management: https://landscape.canonical.com + * Support: https://ubuntu.com/pro + + System information as of Sun Jun 28 10:24:27 UTC 2026 + + System load: 0.48 Processes: 115 + Usage of /: 22.8% of 9.51GB Users logged in: 0 + Memory usage: 33% IPv4 address for ens3: 192.168.2.10 + Swap usage: 0% + + +Expanded Security Maintenance for Infrastructure is not enabled. + +1 update can be applied immediately. +1 of these updates is a standard security update. +To see these additional updates run: apt list --upgradable + +129 additional security updates can be applied with ESM Infra. +Learn more about enabling ESM Infra service for Ubuntu 20.04 at +https://ubuntu.com/20-04 + + +ubuntu@final-assessment-web-1:~$ sudo docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +365edf425ac4 git.rustprogersteam.ru/black_raven/myresume/resume:latest "gunicorn app:app -b…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp upbeat_northcutt +ubuntu@final-assessment-web-1:~$ exit +logout +Connection to 192.168.2.10 closed. +ubuntu@final-assessment-bastion:~$ ssh ubuntu@192.168.2.11 # теперь должно работать +The authenticity of host '192.168.2.11 (192.168.2.11)' can't be established. +ECDSA key fingerprint is SHA256:NZ7FTKC5HtwQkpRs/4J4IPKzaQB5vEX0TRKZ5+t0hMI. +Are you sure you want to continue connecting (yes/no/[fingerprint])? yes +Warning: Permanently added '192.168.2.11' (ECDSA) to the list of known hosts. +Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-216-generic x86_64) + + * Documentation: https://help.ubuntu.com + * Management: https://landscape.canonical.com + * Support: https://ubuntu.com/pro + + System information as of Sun Jun 28 10:25:13 UTC 2026 + + System load: 0.18 Processes: 117 + Usage of /: 22.8% of 9.51GB Users logged in: 0 + Memory usage: 31% IPv4 address for ens3: 192.168.2.11 + Swap usage: 0% + + +Expanded Security Maintenance for Infrastructure is not enabled. + +1 update can be applied immediately. +1 of these updates is a standard security update. +To see these additional updates run: apt list --upgradable + +129 additional security updates can be applied with ESM Infra. +Learn more about enabling ESM Infra service for Ubuntu 20.04 at +https://ubuntu.com/20-04 + + +ubuntu@final-assessment-web-2:~$ sudo docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +540a7f938ba0 git.rustprogersteam.ru/black_raven/myresume/resume:latest "gunicorn app:app -b…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp lucid_cerf +ubuntu@final-assessment-web-2:~$ exit +logout +Connection to 192.168.2.11 closed. diff --git a/03_code/VKC_PROJ_V01_backend_РемизовКЛ_20260628.tf b/03_code/VKC_PROJ_V01_backend_РемизовКЛ_20260628.tf new file mode 100644 index 0000000..b6203dd --- /dev/null +++ b/03_code/VKC_PROJ_V01_backend_РемизовКЛ_20260628.tf @@ -0,0 +1,11 @@ +terraform { + backend "s3" { + bucket = "tf-state-final-assessment" # имя твоего бакета (должен существовать) + key = "final-assessment/terraform.tfstate" # путь к файлу состояния внутри бакета + region = "ru-msk" # твой регион + endpoint = "https://hb.ru-msk.vkcloud-storage.ru" + skip_region_validation = true + skip_credentials_validation = true + skip_metadata_api_check = true + } +} diff --git a/03_code/VKC_PROJ_V01_main_РемизовКЛ_20260628.tf b/03_code/VKC_PROJ_V01_main_РемизовКЛ_20260628.tf new file mode 100644 index 0000000..05f0012 --- /dev/null +++ b/03_code/VKC_PROJ_V01_main_РемизовКЛ_20260628.tf @@ -0,0 +1,302 @@ +terraform { + required_providers { + vkcs = { + source = "vk-cs/vkcs" + version = "~> 0.1" + } + random = { + source = "hashicorp/random" + version = "~> 3.5" + } + } +} + +provider "vkcs" { + username = var.vkcs_username + password = var.vkcs_password + project_id = var.vkcs_project_id + region = var.vkcs_region + auth_url = var.vkcs_auth_url +} + +data "vkcs_networking_network" "extnet" { + name = var.external_network_name +} + +data "vkcs_networking_secgroup" "ssh" { + name = "ssh" +} + +data "vkcs_networking_router" "router" { + id = var.router_id +} + +data "vkcs_images_image" "ubuntu" { + name = var.image_name +} + +data "vkcs_compute_flavor" "web" { + name = var.flavor_web +} + +data "vkcs_compute_flavor" "bastion" { + name = var.flavor_bastion +} + +# --- Сеть --- +resource "vkcs_networking_network" "main" { + name = "${var.project_name}-network" + sdn = "sprut" +} + +resource "vkcs_networking_subnet" "public" { + name = "${var.project_name}-public-subnet" + network_id = vkcs_networking_network.main.id + cidr = var.public_subnet_cidr + dns_nameservers = ["8.8.8.8", "1.1.1.1"] +} + +resource "vkcs_networking_subnet" "private" { + name = "${var.project_name}-private-subnet" + network_id = vkcs_networking_network.main.id + cidr = var.private_subnet_cidr + dns_nameservers = ["8.8.8.8", "1.1.1.1"] +} + +resource "vkcs_networking_router_interface" "public" { + router_id = data.vkcs_networking_router.router.id + subnet_id = vkcs_networking_subnet.public.id +} + +resource "vkcs_networking_router_interface" "private" { + router_id = data.vkcs_networking_router.router.id + subnet_id = vkcs_networking_subnet.private.id +} + +# --- Security Groups --- +resource "vkcs_networking_secgroup" "main" { + name = "${var.project_name}-secgroup" + description = "Security group for VMs" +} + +resource "vkcs_networking_secgroup_rule" "ssh" { + security_group_id = vkcs_networking_secgroup.main.id + direction = "ingress" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + remote_ip_prefix = "${var.my_ip}/32" +} + +resource "vkcs_networking_secgroup_rule" "http" { + security_group_id = vkcs_networking_secgroup.main.id + direction = "ingress" + protocol = "tcp" + port_range_min = 80 + port_range_max = 80 + remote_ip_prefix = "0.0.0.0/0" +} + +resource "vkcs_networking_secgroup_rule" "egress" { + security_group_id = vkcs_networking_secgroup.main.id + direction = "egress" + remote_ip_prefix = "0.0.0.0/0" +} + +# Security Group для базы данных +resource "vkcs_networking_secgroup" "db_sg" { + name = "${var.project_name}-db-sg" + description = "Security group for PostgreSQL" +} + +resource "vkcs_networking_secgroup_rule" "db_ingress" { + security_group_id = vkcs_networking_secgroup.db_sg.id + direction = "ingress" + protocol = "tcp" + port_range_min = 5432 + port_range_max = 5432 + remote_ip_prefix = var.private_subnet_cidr +} + +# --- Key Pair --- +resource "vkcs_compute_keypair" "my_key" { + name = "${var.project_name}-key" + public_key = file(var.ssh_public_key) +} + +# --- Веб-серверы (Docker, без логина) --- +resource "vkcs_compute_instance" "web" { + count = 2 + name = "${var.project_name}-web-${count.index + 1}" + flavor_id = data.vkcs_compute_flavor.web.id + key_pair = vkcs_compute_keypair.my_key.name + security_group_ids = [vkcs_networking_secgroup.main.id, data.vkcs_networking_secgroup.ssh.id] + availability_zone = "MS1" + + block_device { + uuid = data.vkcs_images_image.ubuntu.id + source_type = "image" + destination_type = "volume" + volume_type = "ceph-ssd" + volume_size = var.volume_size_web + boot_index = 0 + delete_on_termination = true + } + + network { + uuid = vkcs_networking_network.main.id + fixed_ip_v4 = cidrhost(var.private_subnet_cidr, count.index + 10) + } + + # user_data – без логина, просто run + user_data = <<-EOF + #!/bin/bash + set -e + + # Установка Docker + apt-get update + apt-get install -y docker.io + systemctl enable docker + systemctl start docker + + # Ждём, пока Docker-демон полностью запустится + sleep 5 + + # Запускаем контейнер с повторными попытками, если образ не скачался + MAX_ATTEMPTS=5 + ATTEMPT=0 + until [ $ATTEMPT -ge $MAX_ATTEMPTS ] + do + echo "Attempt $((ATTEMPT+1)): pulling and running container..." + docker run -d --restart=always -p 80:80 ${var.docker_image} && break + ATTEMPT=$((ATTEMPT+1)) + echo "Failed. Retrying in 10 seconds..." + sleep 10 + done + + # Если после всех попыток контейнер не запустился – пишем ошибку в лог + if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then + echo "ERROR: Failed to run container after $MAX_ATTEMPTS attempts." >&2 + exit 1 + fi + + echo "Container started successfully." + EOF +} + +locals { + web_private_ips = vkcs_compute_instance.web[*].network[0].fixed_ip_v4 +} + +# --- Балансировщик --- +resource "vkcs_lb_loadbalancer" "main" { + name = "${var.project_name}-lb" + vip_subnet_id = vkcs_networking_subnet.public.id +} + +resource "vkcs_lb_listener" "http" { + name = "${var.project_name}-listener" + loadbalancer_id = vkcs_lb_loadbalancer.main.id + protocol = "HTTP" + protocol_port = 80 +} + +resource "vkcs_lb_pool" "web" { + name = "${var.project_name}-pool" + protocol = "HTTP" + lb_method = "ROUND_ROBIN" + listener_id = vkcs_lb_listener.http.id +} + +resource "vkcs_lb_monitor" "web" { + pool_id = vkcs_lb_pool.web.id + type = "HTTP" + url_path = "/DevOps" + delay = 10 + timeout = 5 + max_retries = 3 +} + +resource "vkcs_lb_member" "web" { + count = 2 + pool_id = vkcs_lb_pool.web.id + address = local.web_private_ips[count.index] + protocol_port = 80 + subnet_id = vkcs_networking_subnet.private.id +} + +resource "vkcs_networking_floatingip" "lb" { + pool = data.vkcs_networking_network.extnet.name +} + +resource "vkcs_networking_floatingip_associate" "lb" { + floating_ip = vkcs_networking_floatingip.lb.address + port_id = vkcs_lb_loadbalancer.main.vip_port_id +} + +# --- Бастион (без мониторинга) --- +resource "vkcs_compute_instance" "bastion" { + name = "${var.project_name}-bastion" + flavor_id = data.vkcs_compute_flavor.bastion.id + key_pair = vkcs_compute_keypair.my_key.name + security_group_ids = [vkcs_networking_secgroup.main.id, data.vkcs_networking_secgroup.ssh.id] + availability_zone = "MS1" + + block_device { + uuid = data.vkcs_images_image.ubuntu.id + source_type = "image" + destination_type = "volume" + volume_type = "ceph-ssd" + volume_size = var.volume_size_bastion + boot_index = 0 + delete_on_termination = true + } + + network { + uuid = vkcs_networking_network.main.id + fixed_ip_v4 = cidrhost(var.public_subnet_cidr, 10) + } + + user_data = <<-EOF + #!/bin/bash + set -e + apt-get update + apt-get install -y curl wget htop + EOF +} + +resource "vkcs_networking_floatingip" "bastion" { + pool = data.vkcs_networking_network.extnet.name +} + +resource "vkcs_networking_floatingip_associate" "bastion" { + floating_ip = vkcs_networking_floatingip.bastion.address + port_id = vkcs_compute_instance.bastion.network[0].port +} + +# --- Управляемая PostgreSQL --- +resource "vkcs_db_instance" "postgres" { + name = "${var.project_name}-postgres" + flavor_id = "bf714720-78da-4271-ab7d-0cf5e2613f14" # Standard-2-8-50 + size = 10 + volume_type = "ceph-ssd" + network { + subnet_id = vkcs_networking_subnet.private.id + } + availability_zone = "MS1" + datastore { + type = "postgresql" + version = "14" + } +} + +resource "vkcs_db_database" "app_db" { + dbms_id = vkcs_db_instance.postgres.id + name = "app_db" +} + +resource "vkcs_db_user" "app_user" { + dbms_id = vkcs_db_instance.postgres.id + name = "app_user" + password = "*#User23786590#*" +} diff --git a/03_code/VKC_PROJ_V01_outputs_РемизовКЛ_20260628.tf b/03_code/VKC_PROJ_V01_outputs_РемизовКЛ_20260628.tf new file mode 100644 index 0000000..297d575 --- /dev/null +++ b/03_code/VKC_PROJ_V01_outputs_РемизовКЛ_20260628.tf @@ -0,0 +1,34 @@ +output "load_balancer_ip" { + value = vkcs_networking_floatingip.lb.address + description = "Публичный IP балансировщика" +} + +output "bastion_floating_ip" { + value = vkcs_networking_floatingip.bastion.address + description = "Публичный IP ВМ бастиона" +} + +output "web_private_ips" { + value = local.web_private_ips + description = "Приватные IP веб-серверов" +} + +output "ssh_to_bastion" { + value = "ssh -i ~/.ssh/id_rsa ubuntu@${vkcs_networking_floatingip.bastion.address}" + description = "Команда для подключения к бастиону" +} + +output "db_host" { + value = vkcs_db_instance.postgres.network[0].fixed_ip_v4 + description = "Приватный IP инстанса PostgreSQL" +} + +output "db_name" { + value = vkcs_db_database.app_db.name + description = "Имя базы данных" +} + +output "db_user" { + value = vkcs_db_user.app_user.name + description = "Имя пользователя БД" +} diff --git a/03_code/VKC_PROJ_V01_variables_РемизовКЛ_20260628.tf b/03_code/VKC_PROJ_V01_variables_РемизовКЛ_20260628.tf new file mode 100644 index 0000000..1074147 --- /dev/null +++ b/03_code/VKC_PROJ_V01_variables_РемизовКЛ_20260628.tf @@ -0,0 +1,109 @@ +variable "my_ip" { + description = "Ваш публичный IP для SSH (узнать через curl ifconfig.me)" + type = string + sensitive = true +} + +variable "project_name" { + description = "Префикс для имен ресурсов" + type = string + default = "final_assessment" +} + +variable "router_id" { + description = "ID существующего роутера" + type = string + default = "913bdd47-9155-45b2-b404-5c10d0086132" +} + +variable "external_network_name" { + description = "Имя внешней сети для Floating IP" + type = string + default = "internet" +} + +variable "ssh_public_key" { + description = "Путь к публичному SSH-ключу" + type = string + default = "~/.ssh/id_rsa.pub" +} + +variable "image_name" { + description = "Имя образа Ubuntu 20.04" + type = string + default = "ubuntu-20-202602051631.gite7a38aaf" +} + +variable "flavor_web" { + description = "Flavor для веб-серверов" + type = string + default = "Basic-1-1-10" +} + +variable "flavor_bastion" { + description = "Flavor для ВМ бастиона" + type = string + default = "Basic-1-1-10" +} + +variable "public_subnet_cidr" { + description = "CIDR публичной подсети" + type = string + default = "192.168.1.0/24" +} + +variable "private_subnet_cidr" { + description = "CIDR приватной подсети" + type = string + default = "192.168.2.0/24" +} + +variable "volume_size_web" { + description = "Размер диска для веб-серверов (ГБ)" + type = number + default = 10 +} + +variable "volume_size_bastion" { + description = "Размер диска для бастиона (ГБ)" + type = number + default = 20 +} + +# --- Docker-образ (без логина) --- +variable "docker_image" { + description = "Полное имя Docker-образа (с тегом)" + type = string + default = "git.rustprogersteam.ru/black_raven/myresume/resume:latest" +} + +# --- Аутентификация VKCS --- +variable "vkcs_username" { + description = "VK Cloud username (из RC-файла)" + type = string + sensitive = true +} + +variable "vkcs_password" { + description = "VK Cloud password" + type = string + sensitive = true +} + +variable "vkcs_project_id" { + description = "VK Cloud project ID (из RC-файла)" + type = string + sensitive = true +} + +variable "vkcs_region" { + description = "VK Cloud region (например, RegionOne или MS1)" + type = string + default = "RegionOne" +} + +variable "vkcs_auth_url" { + description = "VK Cloud Auth URL (например, https://infra.mail.ru:35357/v3/)" + type = string + sensitive = true +} diff --git a/04_diagrams/VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png b/04_diagrams/VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png new file mode 100644 index 0000000..4528dce Binary files /dev/null and b/04_diagrams/VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png differ diff --git a/05_exports/VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4 b/05_exports/VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4 new file mode 100644 index 0000000..4a5d9cc Binary files /dev/null and b/05_exports/VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4 differ diff --git a/05_exports/VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf b/05_exports/VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf new file mode 100644 index 0000000..9739533 Binary files /dev/null and b/05_exports/VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf differ