feat: Added final project

This commit is contained in:
Black_Raven committed 2026-06-28 16:20:00 +03:00
1 parent 0302da1fd7
commit b76898970b
12 files changed
+1118

No files matched your search

+11
View File
@@ -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_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_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_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, 00_manifest.csv,MANIFEST,all,all,Финальный манифест сдачи,00_manifest.csv,,final,
1 file_name artifact_type module_or_lab task_code task_title relative_path evidence_for status comment
144 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
145 VKC_ARCH_M08_highload_store_REPORT_РемизовКЛ_20260619.md CASE M08 8.2 Проектирование высоконагруженной архитектуры интернет-магазина 01_reports/VKC_ARCH_M08_highload_store_REPORT_РемизовКЛ_20260619.md final
146 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
147 VKC_PROJ_V01_README_РемизовКЛ_20260628.md PROJ PROJ V01 README итогового проекта 01_reports/VKC_PROJ_V01_README_РемизовКЛ_20260628.md final
148 VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4 EVIDENCE PROJ V01 Видеообзор демонстрации 05_exports/VKC_PROJ_V01_demo_video_РемизовКЛ_20260628.mp4 final
149 VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf PRESENTATION PROJ V01 Презентация итогового проекта 05_exports/VKC_PROJ_V01_presentation_РемизовКЛ_20260628.pdf final
150 VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png DIAGRAM PROJ V01 Архитектурная схема 04_diagrams/VKC_PROJ_V01_architecture_РемизовКЛ_20260628.drawio.png final
151 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
152 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
153 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
154 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
155 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
156 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
157 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
158 00_manifest.csv MANIFEST all all Финальный манифест сдачи 00_manifest.csv final
@@ -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, все критерии успеха выполнены, инфраструктура работоспособна и готова к защите. Видеообзор содержит все необходимые доказательства.
@@ -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)
@@ -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
<
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Кирилл Ремизов</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap">
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<!-- Шапка с фото и контактами -->
<div class="header">
<div class="photo-section">
<div class="photo-slider" id="photoSlider">
<!-- Фотографии будут добавлены через JavaScript -->
</div>
<div class="slider-controls" id="sliderControls">
<!-- Точки управления слайдером будут добавлены через JavaScript -->
</div>
</div>
<div class="info-section">
<h1>Ремизов Кирилл Львович</h1>
<div class="subtitle">Интересующее направление: SRE/DevOps инженер</div>
<p>Студент 3 курса ННГУ им. Лобачевского по направлению "Программная инженерия" (Средний бал: 3,85). Стремлюсь к профессиональному росту: изучаю новые технологии, алгоритмы и подходы к разработке. Как молодой специалист, подхожу к работе с энтузиазмом и готов вкладываться в сложные проекты.</p>
<div class="contacts">
<div class="contact-item">
<div class="contact-icon">
<i class="fas fa-phone"></i>
</div>
<div>
<div><a href="tel:+79051932953">+7 (905) 193-29-53</a></div>
</div>
</div>
<div class="contact-item">
<div class="contact-icon">
<i class="fas fa-envelope"></i>
</div>
<div>
<div><a href="mailto:remizov.kirill2005@yandex.ru">remizov.kirill2005@yandex.ru</a></div>
</div>
</div>
<div class="contact-item">
<div class="contact-icon">
<i class="fab fa-telegram"></i>
</div>
<div>
<div><a href="https://t.me/simpleRussianProger" target="_blank">@simpleRussianProger</a></div>
</div>
</div>
<div class="contact-item">
<div class="contact-icon">
<i class="fab fa-github"></i>
</div>
<div>
<div><a href="https://github.com/BlackCorbeau" target="_blank">BlackCorbeau (GitHub)</a></div>
</div>
</div>
<div class="contact-item">
<div class="contact-icon">
<i class="fab fa-git-alt"></i>
</div>
<div>
<div><a href="https://git.rustprogersteam.ru/Black_Raven" target="_blank">RemizovKL (Forgejo)</a></div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<!-- Левая колонка -->
<div class="left-column">
<!-- Образование -->
<div class="card">
<div class="card-title">
<i class="fas fa-graduation-cap"></i>
<span>Образование</span>
</div>
<p><strong>2023–2027 ННГУ им. Лобачевского</strong>, Нижний Новгород</p>
<p style="color: var(--text-muted); margin-top: 5px;">Программная инженерия</p>
</div>
<!-- Достижения -->
<div class="card">
<div class="card-title">
<i class="fas fa-trophy"></i>
<span>Достижения</span>
</div>
<p><strong>2025</strong> Участие в хакатоне от IT-холдинга Т1, 3-е место.</p>
</div>
<!-- Языки -->
<div class="card">
<div class="card-title">
<i class="fas fa-globe"></i>
<span>Языки</span>
</div>
<ul class="list">
<li>Английский (B2)</li>
<li>Французский (разговорный)</li>
</ul>
</div>
<!-- Soft Skills -->
<div class="card">
<div class="card-title">
<i class="fas fa-users"></i>
<span>Soft Skills</span>
</div>
<ul class="list">
<li>Ответственный и пунктуальный</li>
<li>Любовь к своему делу</li>
<li>Умение работать в команде</li>
<li>Открыт к обмену опытом</li>
</ul>
</div>
</div>
<!-- Правая колонка -->
<div class="right-column">
<!-- Технические навыки -->
<div class="card">
<div class="card-title">
<i class="fas fa-cogs"></i>
<span>Технические навыки</span>
</div>
<div class="skill-item">
<div class="skill-header">
<span>C++</span>
<span>5/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 100%;"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-header">
<span>Rust</span>
<span>4/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 80%;"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-header">
<span>SQL</span>
<span>3/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 60%;"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-header">
<span>Python</span>
<span>2/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 40%;"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-header">
<span>CI/CD</span>
<span>5/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 100%;"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-header">
<span>Linux</span>
<span>5/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 100%;"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-header">
<span>Docker</span>
<span>5/5</span>
</div>
<div class="skill-bar">
<div class="skill-level" style="width: 100%;"></div>
</div>
</div>
</div>
<!-- Профессиональные навыки -->
<div class="card">
<div class="card-title">
<i class="fas fa-tools"></i>
<span>Профессиональные навыки</span>
</div>
<div class="two-column-list">
<ul class="list">
<li>Работа с терминалом</li>
<li>Vim</li>
<li>Docker</li>
</ul>
<ul class="list">
<li>Kubernetes</li>
<li>*nix системы</li>
</ul>
</div>
</div>
<!-- Ссылка на репозиторий -->
<div class="card">
<div class="card-title">
<i class="fas fa-code-branch"></i>
<span>Репозиторий проекта</span>
</div>
<p>Исходный код этого резюме доступны в репозитории:</p>
<a href="https://git.rustprogersteam.ru/Black_Raven/MyResume" target="_blank" class="repo-link">
<i class="fab fa-git-alt"></i>
<span>https://git.rustprogersteam.ru/Black_Raven/MyResume</span>
</a>
</div>
</div>
</div>
<div class="footer">
<p><i class="fas fa-heart" style="color: var(--primary);"></i> Обновлено: <span id="currentDate"></span></p>
<p style="margin-top: 10px; font-size: 0.8rem;">Стиль вдохновлен Forgejo | Черно-оранжевая цветовая схема</p>
</div>
<script src="/static/js/script.js"></script>
</body>
* Connection #0 to host 95.163.213.173:80 left intact
</html>%
@@ -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.
@@ -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
}
}
@@ -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#*"
}
@@ -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 = "Имя пользователя БД"
}
@@ -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
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB