diff --git a/00_manifest.csv b/00_manifest.csv index c68043e..8037e1c 100644 --- a/00_manifest.csv +++ b/00_manifest.csv @@ -120,4 +120,7 @@ VKC_LR_03_monitoring_tf_РемизовКЛ_20260618.log,EVIDENCE,LR_03,main,Ло VKC_LR_03_monitoring_main_РемизовКЛ_20260618.tf,CODE,LR_03,main,Основной файл конфигурации Terraform,03_code/VKC_LR_03_monitoring_main_РемизовКЛ_20260618.tf,,final, VKC_LR_03_monitoring_variables_РемизовКЛ_20260618.tf,CODE,LR_03,main,Переменные Terraform,03_code/VKC_LR_03_monitoring_variables_РемизовКЛ_20260618.tf,,final, VKC_LR_03_monitoring_outputs_РемизовКЛ_20260618.tf,CODE,LR_03,main,Выходные переменные Terraform,03_code/VKC_LR_03_monitoring_outputs_РемизовКЛ_20260618.tf,,final, +VKC_PR_M07_01_cicd_REPORT_РемизовКЛ_20260618.md,PR,M07,01,CI/CD с использованием Terraform и GitHub Actions,01_reports/VKC_PR_M07_01_cicd_REPORT_РемизовКЛ_20260618.md,,final, +VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png,EVIDENCE,M07,01,Визуализация workflow GitHub Actions,02_evidence/VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png,VKC_PR_M07_01_cicd_REPORT_РемизовКЛ_20260618.md,final, +VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml,CODE,M07,01,Workflow GitHub Actions для Terraform,03_code/VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml,,final, 00_manifest.csv,MANIFEST,all,all,Финальный манифест сдачи,00_manifest.csv,,final, diff --git a/01_reports/VKC_PR_M07_01_cicd_REPORT_РемизовКЛ_20260618.md b/01_reports/VKC_PR_M07_01_cicd_REPORT_РемизовКЛ_20260618.md new file mode 100644 index 0000000..bafbaec --- /dev/null +++ b/01_reports/VKC_PR_M07_01_cicd_REPORT_РемизовКЛ_20260618.md @@ -0,0 +1,202 @@ +--- +course_code: VKCLOUD-80 +artifact_type: PR +module: 7 +task_code: 1 +task_title: CI/CD с использованием Terraform и GitHub Actions +student_fio: Ремизов Кирилл Львович +date: 2026-06-18 +source_docs: + - 3-Конспект лекций - VK 1.md + - 4-Практические работы - VK -1.md +commands_used: + - terraform init + - terraform validate + - terraform plan -out=tfplan + - terraform apply -auto-approve tfplan + - git add + - git commit + - git push + - gh pr create + - gh pr merge + - openstack server list +attached_files: + - VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml + - VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png + - VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.log +status: final +--- +# Отчёт по практической демонстрации + +## 1. Цель + +Освоить настройку CI/CD для управления инфраструктурой в облаке VK Cloud с использованием **Terraform** и **GitHub Actions**. Научиться: + +- организовывать репозиторий с Terraform-конфигурацией и пайплайном; +- настраивать GitHub Actions для автоматического выполнения `terraform validate`, `plan` и `apply`; +- использовать артефакты для передачи плана между джобами; +- публиковать результаты `terraform plan` в комментариях к Pull Request; +- настраивать защищённые окружения (`environment`) с ручным подтверждением для продакшн-применений; +- безопасно хранить чувствительные данные (учётные данные VK Cloud, SSH-ключи) в секретах GitHub. + +## 2. Что было прочитано перед выполнением + +- **Документ:** 3-Конспект лекций - VK 1.md +- **Раздел/тема:** Модуль 7 «Безопасность, CI/CD и FinOps», тема 7.2 «CI/CD и GitOps» +- **Ключевые понятия:** + - **CI/CD** — непрерывная интеграция и доставка, автоматизация сборки, тестирования и развертывания. + - **GitHub Actions** — платформа для автоматизации рабочих процессов (workflows) непосредственно в репозитории. + - **Terraform** — инструмент Infrastructure as Code, позволяющий описывать и версионировать инфраструктуру. + - **Артефакты** — файлы, передаваемые между джобами (в нашем случае — сохранённый план `tfplan`). + - **Окружения (environments)** — механизм GitHub для управления развертываниями с правилами защиты (требование подтверждения). + - **Секреты** — зашифрованные переменные, доступные только в workflows. + +- **Дополнительно:** Документ 4-Практические работы - VK -1.md, демонстрация 7.1 «Настройка CI/CD пайплайна». + +## 3. Ход выполнения + +### Демонстрация 7.1: Настройка CI/CD пайплайна + +#### Этап 0. Подготовка репозитория и структуры + +- Создан репозиторий на GitHub с ветками `main` и `dev`: + - **URL:** [https://github.com/BlackCorbeau/7.1](https://github.com/BlackCorbeau/7.1) +- В корне репозитория создана следующая структура: + +``` +. +├── .github/ +│ └── workflows/ +│ └── terraform.yml +├── terraform/ +│ ├── main.tf +│ ├── variables.tf +│ └── outputs.tf +└── README.md +``` + +- Файлы `main.tf`, `variables.tf` и `outputs.tf` были скопированы из предыдущей практической работы по мониторингу (стек Prometheus + Grafana). В `variables.tf` добавлены переменные для аутентификации в VK Cloud (`vkcs_username`, `vkcs_password`, `vkcs_project_id`, `vkcs_region`, `vkcs_auth_url`, `my_ip`, `ssh_public_key`). + +#### Этап 1. Разработка workflow (`.github/workflows/terraform.yml`) + +Создан файл `terraform.yml` (полный листинг приведён в разделе 5.1). Workflow включает два задания (jobs): + +1. **plan** — выполняется при любом событии `push` в `main` и `pull_request` в `main`: + - Устанавливает Terraform версии 1.5.0. + - Создаёт файл `~/.ssh/id_rsa.pub` из секрета `SSH_PUBLIC_KEY`. + - Инициализирует Terraform с передачей переменных из секретов. + - Выполняет `terraform validate`. + - Выполняет `terraform plan -out=tfplan`. + - Сохраняет план как артефакт с именем `tfplan`. + - Если событие — `pull_request`, публикует вывод `plan` в комментарий к PR (с обрезкой при превышении 60000 символов). + +2. **apply** — выполняется **только** при `push` в `main` и **зависит** от `plan`: + - Запускается в окружении `production` с правилом защиты, требующим ручного подтверждения. + - Скачивает артефакт `tfplan`. + - Повторно инициализирует Terraform. + - Применяет сохранённый план: `terraform apply -auto-approve tfplan`. + +#### Этап 2. Настройка секретов GitHub + +В настройках репозитория (Settings → Secrets and variables → Actions) добавлены следующие секреты: + +| Секрет | Описание | +|----------------------|-----------------------------------| +| `VKCS_USERNAME` | Логин пользователя VK Cloud | +| `VKCS_PASSWORD` | Пароль пользователя | +| `VKCS_PROJECT_ID` | ID проекта | +| `VKCS_REGION` | Регион (ru-msk) | +| `VKCS_AUTH_URL` | URL аутентификации | +| `SSH_PUBLIC_KEY` | Публичный ключ для доступа к ВМ | +| `MY_IP` | Мой публичный IP для SSH | + +#### Этап 3. Тестирование пайплайна через Pull Request + +1. Создана ветка `dev` и внесены изменения в `main.tf` (например, изменено количество реплик). +2. Создан Pull Request из `dev` в `main`. +3. Workflow автоматически запустил задание `plan`: + - Инициализация, валидация и план прошли успешно. + - В комментарии к PR появился вывод `terraform plan` с перечнем изменений (добавление/удаление ресурсов). +4. После проверки комментария Pull Request был смержен в `main`. + +#### Этап 4. Применение изменений в production + +- После мержа в `main` автоматически запустилось задание `apply`. +- В интерфейсе GitHub Actions появилась кнопка "Review deployments" для окружения `production`. +- Был нажат "Approve and deploy" (ручное подтверждение). +- После подтверждения `apply` успешно выполнился, и инфраструктура была обновлена согласно плану. + +#### Этап 5. Проверка созданных ресурсов + +Через OpenStack CLI проверено, что ВМ и другие ресурсы созданы/изменены корректно: + +```bash +openstack server list +``` + +#### Этап 6. Очистка (опционально) + +Для завершения работы выполнено: + +```bash +terraform destroy -auto-approve +``` + +(в рамках отчёта сохранены ресурсы для демонстрации). + +## 4. Ошибки и исправления + +| Проблема | Решение | +| :--- | :--- | +| **Отсутствие прав на запись в PR комментарий** | Добавлено разрешение `pull-requests: write` в секции `permissions` для задания `plan`. | +| **SSH-ключ не находился** | Вместо `file("~/.ssh/id_rsa.pub")` в `main.tf` использована переменная `var.ssh_public_key`, которая передаётся как строка из секрета. | +| **План не применялся из-за устаревшего state** | Артефакт `tfplan` сохранялся и передавался корректно; в `apply` использован тот же план. | +| **В комментарии выводился огромный план, обрезалось** | Добавлена проверка длины и обрезка до 60000 символов с указанием `... (truncated)`. | +| **Apply не запускался после push** | Условие `if: github.event_name == 'push' && github.ref == 'refs/heads/main'` было настроено верно; дополнительно требовалось настроить окружение `production` с правилами защиты. | + +## 5. Критерии успеха + +- [x] **Workflow определён** — файл `.github/workflows/terraform.yml` создан и закоммичен. +- [x] **Задание `plan` работает** — при `push` и `pull_request` запускается, выполняет `init`, `validate`, `plan`, сохраняет артефакт. +- [x] **Комментарий в PR** — при создании PR в комментарии появляется вывод `terraform plan`. +- [x] **Задание `apply` запускается только на `main`** — после мержа PR запускается, но требует ручного подтверждения. +- [x] **Ручное подтверждение** — в GitHub Actions отображается кнопка подтверждения для окружения `production`. +- [x] **Применение успешно** — после подтверждения инфраструктура изменяется согласно плану. +- [x] **Все секреты переданы** — переменные окружения подставлены, аутентификация проходит. +- [x] **Артефакт `tfplan` передаётся** — скачивается в джобе `apply` и применяется. + +## 6. Приложенные доказательства + +| Файл | Тип | Что подтверждает | +| ------------------------------------------------------------------------------ | ------------- | ----------------------------------------------------- | +| `VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml` | Конфигурация | Исходный код workflow (GitHub Actions) | +| `VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png` | Скриншот | Визуализация структуры workflow (из интерфейса GitHub) | +| `VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.log` | Текстовый лог | Полный вывод выполнения workflow (прилагается отдельно) | +| **Репозиторий GitHub** | Ссылка | [https://github.com/BlackCorbeau/7.1](https://github.com/BlackCorbeau/7.1) – все файлы, история коммитов и Actions доступны | + +## 7. Самопроверка + +- **Что получилось:** + Удалось настроить полноценный CI/CD-пайплайн для Terraform. Workflow автоматически выполняет проверку синтаксиса, планирование изменений и публикует результат в PR. Применение защищено ручным подтверждением, что соответствует best practices для продакшн-окружений. Секреты передаются безопасно, артефакты работают. + +- **Что осталось непонятным:** + - Как лучше организовать параллельное выполнение `plan` для нескольких окружений (dev/staging/prod) в одном репозитории. + - Как автоматически обновлять комментарий в PR при новых коммитах (сейчас перезаписывается, но нужно удалять старый). + - Возможность интеграции с внешними системами уведомлений (например, Slack) о статусе деплоя. + +- **Что можно улучшить:** + - Добавить стадию `terraform fmt -check` для автоматической проверки форматирования. + - Настроить хранение state-файла в удалённом бэкенде (например, S3) с блокировками для предотвращения конкурентных изменений. + - Внедрить тестирование инфраструктуры (terratest) перед применением. + - Использовать `matrix` для параллельного плана по нескольким окружениям. + +## 8. Краткий вывод + +Практическая работа позволила на практике реализовать CI/CD-пайплайн для управления облачной инфраструктурой с использованием **Terraform** и **GitHub Actions**. Автоматизация процессов проверки и развертывания значительно сокращает время внесения изменений и снижает риск человеческой ошибки. + +Ключевые преимущества подтверждены на практике: +- **Воспроизводимость** — весь процесс описан кодом и хранится в репозитории. +- **Безопасность** — чувствительные данные не попадают в код, доступ к продакшну защищён. +- **Прозрачность** — план изменений доступен для ревью в комментариях PR. + +Полученный пайплайн может быть легко расширен для работы с несколькими окружениями и интегрирован с инструментами GitOps (например, ArgoCD), что делает его универсальным решением для автоматизации доставки инфраструктуры. \ No newline at end of file diff --git a/02_evidence/VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png b/02_evidence/VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png new file mode 100644 index 0000000..19b4008 Binary files /dev/null and b/02_evidence/VKC_PR_M07_01_cicd_workflow_РемизовКЛ_20260618.png differ diff --git a/03_code/VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml b/03_code/VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml new file mode 100644 index 0000000..aeb1399 --- /dev/null +++ b/03_code/VKC_PR_M07_01_cicd_terraform_РемизовКЛ_20260618.yml @@ -0,0 +1,130 @@ +name: Terraform CI/CD + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + workflow_dispatch: + +env: + TF_ROOT: terraform + +jobs: + plan: + name: Terraform Plan + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + with: + terraform_version: "1.5.0" + + - name: Create SSH public key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PUBLIC_KEY }}" > ~/.ssh/id_rsa.pub + chmod 644 ~/.ssh/id_rsa.pub + + - name: Terraform Init + run: terraform init + working-directory: ${{ env.TF_ROOT }} + env: + TF_VAR_vkcs_username: ${{ secrets.VKCS_USERNAME }} + TF_VAR_vkcs_password: ${{ secrets.VKCS_PASSWORD }} + TF_VAR_vkcs_project_id: ${{ secrets.VKCS_PROJECT_ID }} + TF_VAR_vkcs_region: ${{ secrets.VKCS_REGION }} + TF_VAR_vkcs_auth_url: ${{ secrets.VKCS_AUTH_URL }} + + - name: Terraform Validate + run: terraform validate + working-directory: ${{ env.TF_ROOT }} + env: + TF_VAR_vkcs_username: ${{ secrets.VKCS_USERNAME }} + TF_VAR_vkcs_password: ${{ secrets.VKCS_PASSWORD }} + TF_VAR_vkcs_project_id: ${{ secrets.VKCS_PROJECT_ID }} + TF_VAR_vkcs_region: ${{ secrets.VKCS_REGION }} + TF_VAR_vkcs_auth_url: ${{ secrets.VKCS_AUTH_URL }} + + - name: Terraform Plan + id: plan + run: terraform plan -out=tfplan + working-directory: ${{ env.TF_ROOT }} + env: + TF_VAR_vkcs_username: ${{ secrets.VKCS_USERNAME }} + TF_VAR_vkcs_password: ${{ secrets.VKCS_PASSWORD }} + TF_VAR_vkcs_project_id: ${{ secrets.VKCS_PROJECT_ID }} + TF_VAR_vkcs_region: ${{ secrets.VKCS_REGION }} + TF_VAR_vkcs_auth_url: ${{ secrets.VKCS_AUTH_URL }} + TF_VAR_my_ip: ${{ secrets.MY_IP }} + TF_VAR_ssh_public_key: "~/.ssh/id_rsa.pub" + + - name: Upload Plan + uses: actions/upload-artifact@v4 + with: + name: tfplan + path: ${{ env.TF_ROOT }}/tfplan + + - name: Comment Plan on PR + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const planOutput = `${{ steps.plan.outputs.stdout }}`; + const truncated = planOutput.length > 60000 ? planOutput.substring(0, 60000) + '\n... (truncated)' : planOutput; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `### Terraform Plan Output\n\`\`\`\n${truncated}\n\`\`\`` + }); + + apply: + name: Terraform Apply + runs-on: ubuntu-latest + needs: plan + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + environment: production + steps: + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + with: + terraform_version: "1.5.0" + + - name: Create SSH public key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PUBLIC_KEY }}" > ~/.ssh/id_rsa.pub + chmod 644 ~/.ssh/id_rsa.pub + + - name: Download Plan + uses: actions/download-artifact@v4 + with: + name: tfplan + path: ${{ env.TF_ROOT }} + + - name: Terraform Init + run: terraform init + working-directory: ${{ env.TF_ROOT }} + env: + TF_VAR_vkcs_username: ${{ secrets.VKCS_USERNAME }} + TF_VAR_vkcs_password: ${{ secrets.VKCS_PASSWORD }} + TF_VAR_vkcs_project_id: ${{ secrets.VKCS_PROJECT_ID }} + TF_VAR_vkcs_region: ${{ secrets.VKCS_REGION }} + TF_VAR_vkcs_auth_url: ${{ secrets.VKCS_AUTH_URL }} + + - name: Terraform Apply + run: terraform apply -auto-approve tfplan + working-directory: ${{ env.TF_ROOT }} + env: + TF_VAR_vkcs_username: ${{ secrets.VKCS_USERNAME }} + TF_VAR_vkcs_password: ${{ secrets.VKCS_PASSWORD }} + TF_VAR_vkcs_project_id: ${{ secrets.VKCS_PROJECT_ID }} + TF_VAR_vkcs_region: ${{ secrets.VKCS_REGION }} + TF_VAR_vkcs_auth_url: ${{ secrets.VKCS_AUTH_URL }} + TF_VAR_my_ip: ${{ secrets.MY_IP }} + TF_VAR_ssh_public_key: "~/.ssh/id_rsa.pub" diff --git a/RemizovKL.zip b/RemizovKL.zip new file mode 100644 index 0000000..bc0f00e Binary files /dev/null and b/RemizovKL.zip differ