diff --git a/.gitignore b/.gitignore index c83cb6d..7f86c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,36 @@ terraform.rc # End of https://www.toptal.com/developers/gitignore/api/ansible +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# End of https://www.toptal.com/developers/gitignore/api/go + # Other .vscode .DS_Store ansible/secrets +main diff --git a/README.md b/README.md index 41f54f6..8566f51 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,10 @@ ## Структура проекта -0. [kubeadm](./kubeadm/) - это инструмент для простого и быстрого развёртывания кластера Kubernetes. +1. [Docker](./docker/) - **Docker** – это программная платформа для быстрой сборки, отладки и развертывания приложений с помощью **контейнеров**. -1. [OpenTofu](./opnetofu) — программное обеспечение с **открытым исходным кодом**, используемое для **управления внешними ресурсами** (например, в рамках модели **инфраструктура как код**). Проект Linux Foundation. Пользователи определяют и предоставляют инфраструктуру центра обработки данных с помощью **декларативного языка конфигурации**, известного как HashiCorp Configuration Language (HCL) или JSON. +2. [kubeadm](./kubeadm/) - это инструмент для простого и быстрого развёртывания кластера Kubernetes. -2. [Ansible](./ansible) — система управления конфигурациями, написанная на языке программирования **Python**, с использованием **декларативного языка разметки** для **описания конфигураций**. Применяется для **автоматизации настройки и развёртывания программного обеспечения**. +3. [OpenTofu](./opnetofu) — программное обеспечение с **открытым исходным кодом**, используемое для **управления внешними ресурсами** (например, в рамках модели **инфраструктура как код**). Проект Linux Foundation. Пользователи определяют и предоставляют инфраструктуру центра обработки данных с помощью **декларативного языка конфигурации**, известного как HashiCorp Configuration Language (HCL) или JSON. + +4. [Ansible](./ansible) — система управления конфигурациями, написанная на языке программирования **Python**, с использованием **декларативного языка разметки** для **описания конфигураций**. Применяется для **автоматизации настройки и развёртывания программного обеспечения**. diff --git a/docker/.dockerignore b/docker/.dockerignore new file mode 100644 index 0000000..d880757 --- /dev/null +++ b/docker/.dockerignore @@ -0,0 +1,32 @@ +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# End of https://www.toptal.com/developers/gitignore/api/go + +# Other +docker-compose.yaml +Dockefile +nginx.tmpl diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..41579e1 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,19 @@ +# Используем официальный образ Golang +FROM docker.io/library/golang:1.22.2-alpine AS builder +# Устанавливаем рабочую директорию +WORKDIR /build +# Копируем исходный код приложения в контейнер +COPY ./ ./ +RUN CGO_ENABLED=0 go build main.go + +# Отдельный этап сборки для уменьшения размера образа +FROM docker.io/library/alpine:3.19.1 AS runner +# Устанавливаем рабочую директорию +WORKDIR /app +# Копируем скомпилированное приложение из предыдущего этапа +COPY --from=builder /build/main ./ +# Запускаем healthcheck, проверяющий доступность веб-сервера на порту 8080 +HEALTHCHECK --interval=5s --timeout=5s --start-period=3s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost:8080/ || exit 1 +# Запускаем приложение при старте контейнера +CMD ["./main"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..ff2b25a --- /dev/null +++ b/docker/README.md @@ -0,0 +1,82 @@ +# Docker + +## Описание приложения + +Простой веб сервис написанный на **Go**, возвращающий имя узла. + +Сервис можно запустить несколькими способами. + +### Локальный запуск + +Сборка приложения: + +```sh +go build main.go +``` + +Запуск + +```sh +./main +``` + +Вывод + +```output +Сервер запущен на порту 8080... +``` + +### Запуск в контейнере + +```sh +docker build -t test . && docker run test +``` + +Вывод + +```output +Сервер запущен на порту 8080... +``` + +### Запуск при помощи docker compose + +Запуск + +```sh +docker compose --profile blue up --wait --remove-orphans --scale web-blue=5 +``` + +Вывод + +```output + ✔ Network docker_default Created 0.0s + ✔ Container docker-nginx-proxy-1 Healthy 0.1s + ✔ Container docker-web-blue-2 Healthy 0.1s + ✔ Container docker-web-blue-4 Healthy 0.1s + ✔ Container docker-web-blue-3 Healthy 0.0s + ✔ Container docker-web-blue-5 Healthy 0.1s + ✔ Container docker-web-blue-1 Healthy 0.1s + ``` + +### Сине-зеленое развертывание + +Запуск + +```sh +bash ./deploy.sh +``` + +Вывод + +```output +Список контейнеров +NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS +docker-nginx-proxy-1 nginxproxy/nginx-proxy:1.5.1-alpine "/app/docker-entrypo…" nginx-proxy 12 seconds ago Up 5 seconds (healthy) 0.0.0.0:80->80/tcp +docker-web-blue-1 docker-web-blue "./main" web-blue 12 seconds ago Up 11 seconds (healthy) 8080/tcp +docker-web-blue-2 docker-web-blue "./main" web-blue 12 seconds ago Up 11 seconds (healthy) 8080/tcp +docker-web-blue-3 docker-web-blue "./main" web-blue 12 seconds ago Up 11 seconds (healthy) 8080/tcp +Журналы запуска web-blue +web-blue-2 | Сервер запущен на порту 8080... +web-blue-1 | Сервер запущен на порту 8080... +web-blue-3 | Сервер запущен на порту 8080... +``` diff --git a/docker/deploy.sh b/docker/deploy.sh new file mode 100644 index 0000000..8b213d0 --- /dev/null +++ b/docker/deploy.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Эта строка настраивает оболочку так, чтобы она выходила из скрипта при возникновении ошибки в любой команде. +# Это помогает обнаружить и обрабатывать ошибки в скрипте. +set -e + +# Проверяем состояние контейнера с именем "web-blue", чтобы определить, является ли он "здоровым" (healthy). +# Если это так, переменным NEW и OLD присваиваются значения "green" и "blue" соответственно, иначе наоборот. +if [ "$(docker compose ps web-blue | grep healthy)" ] +then + export NEW="green" + export OLD="blue" +else + export NEW="blue" + export OLD="green" +fi + +# Выводим сообщение о том, какой профиль поднимается в данный момент (значение переменной NEW). +echo Поднимаю проект с профилем ${NEW} +# Эта команда использует docker-compose для запуска проекта с указанным профилем (значение переменной NEW), +# разворачивая контейнеры в фоновом режиме, пересоздавая их, удаляя сиротские контейнеры, +# масштабируя сервис "web" на три экземпляра и дожидаясь их запуска. +docker compose \ + --profile ${NEW} \ + up \ + --detach \ + --build \ + --remove-orphans \ + --scale web-${NEW}=3 \ + --wait + +# Эта строка выводит сообщение о том, какие сервисы останавливаются в данный момент (значение переменной OLD). +echo Останавливаю сервисы ${OLD} +# Эта команда использует docker-compose для остановки сервиса "web" с именем, соответствующим значению переменной OLD. +docker compose stop \ + web-${OLD} + +# Эта строка выводит сообщение о том, какие сервисы удаляются в данный момент (значение переменной OLD). +echo Удаляю сервисы ${OLD} +# Эта команда использует docker-compose для принудительного удаления сервиса "web" с именем, соответствующим значению переменной OLD. +docker compose rm -f \ + web-${OLD} + +# Эта строка выводит сообщение о выводе списка всех контейнеров. +echo Список контейнеров +docker compose ps -a + +# Эта команда выводит сообщение о том, что будут выведены журналы запуска для сервиса "web" с именем, +# соответствующим значению переменной NEW, и затем выводит эти журналы. +echo Журналы запуска web-${NEW} +docker compose logs web-${NEW} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 0000000..1b2256c --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,57 @@ +services: + # Сервис для развертывания приложения с профилем "blue" + web-blue: &web + build: + context: . + environment: + - VIRTUAL_HOST=web # Виртуальный хост для NGINX + - VIRTUAL_PORT=8080 # Виртуальный порт для NGINX + expose: + - 8080 + deploy: + resources: + limits: + cpus: "0.5" # Лимитированный доступ к ресурсам CPU + memory: 32M # Лимит памяти + restart: always # Перезапускать сервис при падении + profiles: + - blue + + # Сервис для развертывания приложения с профилем "green" + web-green: + <<: *web # Используем настройки из сервиса web-blue + profiles: + - green + + # NGINX-прокси + nginx-proxy: + image: nginxproxy/nginx-proxy:1.5.1-alpine + expose: + - 80 + ports: + - 80:80 # Проксируем порт 80 на хосте + healthcheck: + # Периодичность проверки состояния (5 секунд) + interval: 5s + # Максимальное время ожидания ответа (5 секунд) + timeout: 5s + # Количество попыток в случае неудачной проверки (5 попыток) + retries: 5 + # Время ожидания перед началом проверок (3 секунды) + start_period: 3s + # Команда для выполнения теста + test: curl -f http://localhost/ || exit 1 + volumes: + # Монтируем сокет Docker + - /var/run/docker.sock:/tmp/docker.sock:ro + # Монтируем шаблон NGINX + - ./nginx.tmpl:/app/nginx.tmpl:ro + deploy: + resources: + limits: + cpus: '0.1' # Лимитированный доступ к ресурсам CPU + memory: 128M # Лимит памяти + restart: always + profiles: + - blue + - green diff --git a/docker/main.go b/docker/main.go new file mode 100644 index 0000000..29d188b --- /dev/null +++ b/docker/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "net/http" + "os" +) + +func main() { + // Обработчик запросов + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Получаем имя хоста + hostname, err := os.Hostname() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Отправляем имя хоста в ответ + fmt.Fprintf(w, "Hostname Hostname: %s\n", hostname) + }) + + // Запуск веб-сервера на порту 8080 + fmt.Println("Сервер запущен на порту 8080...") + if err := http.ListenAndServe(":8080", nil); err != nil { + fmt.Printf("Ошибка запуска сервера: %s\n", err) + } +} diff --git a/docker/nginx.tmpl b/docker/nginx.tmpl new file mode 100644 index 0000000..dff02bc --- /dev/null +++ b/docker/nginx.tmpl @@ -0,0 +1,20 @@ +{{ range $host, $containers := groupBy $ "Env.VIRTUAL_HOST" }} +upstream {{ $host }} { + +{{ range $index, $value := $containers }} + {{ with $address := index $value.Addresses 0 }} + server {{ $value.Hostname }}:{{ $address.Port }}; + {{ end }} +{{ end }} + +} + +# конфигурация веб-сервера +server { + listen 80; + + location / { + proxy_pass http://{{ $host }}; + } +} +{{ end }} diff --git a/opentofu/kubeadm/terraform.tfvars.example b/opentofu/kubeadm/terraform.tfvars.example index b1c8e8e..c5306f0 100644 --- a/opentofu/kubeadm/terraform.tfvars.example +++ b/opentofu/kubeadm/terraform.tfvars.example @@ -1,2 +1,2 @@ virtual_environment_api_token = "root@pam!for-terraform-provider=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -virtual_environment_endpoint = "https://10.0.70.116:8006/" +virtual_environment_endpoint = "https://x.x.x.x:8006/"