Учебный Go / DevOps / SRE-проект вокруг простого сервиса заметок.
Проект начинался как учебный сервис заметок, потом перерос в локальный стенд на Docker Compose, а затем был перенесён в Kubernetes. В репозитории собраны backend на Go, PostgreSQL, nginx как reverse proxy, Python reporter, Kubernetes-манифесты, CI в GitHub Actions и публикация Docker-образов в GHCR.
Я сделал этот репозиторий как лабораторный стенд для практики:
- написания простого Go API;
- работы с PostgreSQL;
- сборки Docker-образов;
- запуска нескольких сервисов через Docker Compose;
- настройки nginx как reverse proxy;
- переноса приложения в Kubernetes;
- работы с ConfigMap, Secret, Deployment, Service, StatefulSet и PVC;
- настройки CI в GitHub Actions;
- публикации образов в GHCR;
- ручного деплоя конкретной версии по commit SHA;
- troubleshooting в Docker Compose и Kubernetes.
Проект специально не усложнялся бизнес-логикой. Мне было важнее пройти весь путь вокруг сервиса: как он собирается, как запускается, как общается с другими компонентами, как обновляется и как чинится, когда что-то ломается.
В проекте есть несколько компонентов:
api— Go-сервис с REST API для заметок;postgres— база данных для хранения заметок;nginx— reverse proxy перед API;reporter— Python-скрипт, который проверяет доступность сервиса и сохраняет отчёты;compose.yaml— локальный запуск всего стенда;k8s/— Kubernetes-манифесты;.github/workflows/— CI pipeline;docs/— заметки по архитектуре, troubleshooting и CI/CD.
В Docker Compose схема примерно такая:
client -> localhost:8081 -> nginx -> api -> postgres
^
|
reporter
Запуск:
docker compose up --buildПроверка:
docker compose ps
curl http://localhost:8081/healthz
curl http://localhost:8081/notesОстановка:
docker compose downПосле локального запуска я перенёс стенд в Kubernetes.
Сейчас в k8s/ описаны:
- namespace для проекта;
- ConfigMap с общими настройками;
- Secret с паролем базы;
- PostgreSQL как
StatefulSetсPVC; - API как
DeploymentиService; - nginx как
DeploymentиService; - reporter как
Deploymentс отдельным volume для отчётов.
Локально можно запускать через Minikube.
minikube start --driver=dockerСборка образов внутри Docker-окружения Minikube:
eval $(minikube -p minikube docker-env)
docker build -t go-notes-api:local -f Dockerfile.api .
docker build -t go-notes-reporter:local -f Dockerfile.reporter .Применение манифестов:
kubectl apply -f k8s/00-namespace.yaml
kubectl apply -f k8s/01-config.yaml
kubectl apply -f k8s/02-postgres.yaml
kubectl apply -f k8s/03-api.yaml
kubectl apply -f k8s/04-nginx.yaml
kubectl apply -f k8s/05-reporter.yamlПроверка объектов:
kubectl -n go-notes-platform get pods,svc,endpoints,pvcОткрыть приложение локально:
kubectl -n go-notes-platform port-forward svc/nginx 8081:80В другом терминале:
curl http://localhost:8081/healthz
curl http://localhost:8081/notesВ проекте настроен GitHub Actions workflow.
Он запускается на:
push;pull_request;- ручной запуск через
workflow_dispatch.
Pipeline проверяет:
- Go API;
- Python reporter;
- сборку Docker-образа API;
- сборку Docker-образа reporter.
После успешной сборки образы публикуются в GHCR:
ghcr.io/ru6ich/go-notes-api:latest
ghcr.io/ru6ich/go-notes-api:<commit-sha>
ghcr.io/ru6ich/go-notes-reporter:latest
ghcr.io/ru6ich/go-notes-reporter:<commit-sha>
Деплой в Kubernetes пока сделан вручную по конкретному SHA. Это осознанно: мне было важно руками пройти процесс обновления образов и проверки rollout.
Пример:
kubectl -n go-notes-platform set image deployment/api \
api=ghcr.io/ru6ich/go-notes-api:<SHA>
kubectl -n go-notes-platform rollout status deployment/apiПосле проверки SHA можно зафиксировать в Kubernetes-манифестах, чтобы состояние кластера снова соответствовало файлам в репозитории.
Reporter проверяет доступность сервиса и сохраняет результаты в /app/reports.
Ожидаемые файлы:
summary.csv;latency.png;success_rate.png;stats.json.
Проверка в Kubernetes:
kubectl -n go-notes-platform exec deploy/reporter -- ls -la /app/reports
kubectl -n go-notes-platform exec deploy/reporter -- cat /app/reports/stats.jsonНесколько команд, которые я часто использовал при отладке:
kubectl -n go-notes-platform get pods,svc,endpoints,pvc
kubectl -n go-notes-platform describe pod <pod-name>
kubectl -n go-notes-platform logs deploy/<deployment-name>
kubectl -n go-notes-platform exec -it <pod-name> -- sh
kubectl -n go-notes-platform port-forward svc/nginx 8081:80.
├── .github/
│ └── workflows/
│ └── ci.yml
├── api/
├── db/
│ └── init.sql
├── docs/
│ ├── architecture.md
│ ├── lab-notes.md
│ ├── troubleshooting.md
│ ├── cicd-notes.md
│ └── cheatsheets/
├── k8s/
│ ├── 00-namespace.yaml
│ ├── 01-config.yaml
│ ├── 02-postgres.yaml
│ ├── 03-api.yaml
│ ├── 04-nginx.yaml
│ └── 05-reporter.yaml
├── nginx/
│ └── nginx.conf
├── reporter/
├── Dockerfile.api
├── Dockerfile.reporter
├── compose.yaml
└── README.md
На практике я разобрал:
- как Go API подключается к PostgreSQL;
- как сервисы общаются внутри Docker Compose;
- как nginx проксирует запросы к API;
- чем отличается stateless-сервис от stateful-сервиса;
- зачем PostgreSQL в Kubernetes нужен
StatefulSetиPVC; - как Kubernetes связывает компоненты через
Service; - как искать проблемы через logs, describe, exec, endpoints и port-forward;
- как собрать и опубликовать Docker-образы через GitHub Actions;
- как обновлять сервис в Kubernetes конкретной версией образа.
Проект учебный и продолжает развиваться.
Что можно добавить дальше:
- больше troubleshooting-сценариев;
- readiness/liveness probes;
- проверку Kubernetes-манифестов в CI;
- linting для Go, Python и YAML;
- Helm chart;
- более полноценный monitoring через Prometheus/Grafana;
- автоматизированный deploy после успешного CI.