03. Локальный стек¶
Как поднять локальное окружение для работы над конкретным сервисом и как прогонять кросс-сервисные сценарии.
Подход¶
Каждый сервис-репо имеет свой docker-compose.yml, который поднимает
его собственную инфру (postgres + redis + kafka + сам сервис). Когда ты
работаешь над сервисом — ты работаешь с одним компоузом.
Для тестов кросс-сервисных сценариев со всеми сервисами одновременно
будет отдельный full-stack compose в infra-репозитории (TBD). Пока его
нет — поднимай per-service compose'ы рядом, при необходимости объединяй
через host.docker.internal (подробности ниже).
Запуск¶
Первый раз:
make bootstrap:
1. Копирует .env.example в .env, если .env отсутствует.
2. Скачивает Go-модули (go mod download && go mod tidy).
3. docker compose up -d — поднимает инфру и сам сервис.
4. Ждёт healthcheck'и postgres/redis/kafka.
5. Применяет миграции (либо через встроенный runner в main.go, либо
через отдельный migrate-контейнер — зависит от сервиса).
6. Сервис стартует и начинает слушать порт.
Последующие запуски:
Rebuild после правок кода:
Порты¶
Текущие порты сервисов (см. docker-compose.yml и internal/config/
каждого репо):
| Сервис | HTTP | Метрики |
|---|---|---|
| user | 8001 | через /metrics на 8001 |
| review | 8007 | через /metrics на 8007 |
| media | 8008 | через /metrics на 8008 |
| notification | 8013 | через /metrics на 8013 |
Общие инфра-порты, когда сервис запущен единолично:
| Компонент | Порт |
|---|---|
| Postgres | 5432 (в user — 3431, чтобы не конфликтовать, см. docker-compose.yml) |
| Redis | 6379 |
| Kafka (external) | 9092 |
| Kafka UI | 8090 |
| MinIO (media) | 9000 (API), 9001 (console) |
| Prometheus | 9090 |
| Grafana | 3000 |
| Loki | 3100 |
| Tempo | 3200 |
Если два сервиса надо запускать одновременно — в одном из них переопредели
port через .env (для Postgres: DB_PORT=5433), либо меняй проброс в
docker-compose.yml.
Проверка здоровья¶
curl -sf http://localhost:<port>/healthz
# {"status":"ok"}
curl -sf http://localhost:<port>/readyz
# {"status":"ready"}
/healthz — liveness, отвечает 200, пока процесс жив.
/readyz — readiness, проверяет pool/redis/kafka. Если вернул 503 —
какая-то зависимость не отвечает, смотри логи.
Postgres¶
Открыть psql внутри контейнера:
(Реализовано как docker compose exec postgres psql -U <user> -d <db>.)
С машины:
Пароль — из .env (локальный dev).
Полезные команды внутри psql:
\dn — список схем
\dt <schema>. — таблицы в схеме
\d <table> — структура таблицы
SELECT * FROM <service>.outbox WHERE published_at IS NULL;
Kafka¶
Быстрый просмотр — redpanda/kafdrop UI в compose (если подключён):
Либо через CLI:
docker compose exec kafka /opt/kafka/bin/kafka-topics.sh \
--bootstrap-server localhost:9092 --list
docker compose exec kafka /opt/kafka/bin/kafka-console-consumer.sh \
--bootstrap-server localhost:9092 \
--topic kazmaps.review.review.created \
--from-beginning
Если в Makefile есть make kafka-console — используй его.
Redis¶
Полезные команды:
MinIO (media-сервис)¶
- API:
http://localhost:9000(S3-совместимый endpoint для SDK). - Console:
http://localhost:9001(веб-UI).
Логин/пароль — из .env (MINIO_ROOT_USER/MINIO_ROOT_PASSWORD).
Логи¶
Follow логи самого сервиса:
Другие контейнеры:
Все контейнеры одновременно:
Остановка¶
make down # stop, volumes сохраняются — данные на месте
make clean # down -v, volumes удаляются — чистый старт
Volumes¶
Postgres-данные живут в named volume <service>_postgres_data (точное
имя зависит от compose project). make down их не удаляет — в
следующий раз поднимется та же БД с теми же записями.
Чистый старт:
После make clean Postgres стартует пустым, миграции применяются заново.
Troubleshooting¶
Порт занят¶
Error: ports are not available: 0.0.0.0:5432 -> listen tcp 0.0.0.0:5432: bind: address already in use
Найти, кто держит порт:
- macOS / Linux:
lsof -i :5432 - Windows:
netstat -ano | findstr 5432
Обычно это уже запущенный Postgres другого сервиса. Либо останови его
(make down там), либо переопредели порт в .env для текущего
(DB_PORT=5433).
Миграции не применяются¶
См. ../troubleshooting/migration-fails.md.
Healthcheck висит¶
Смотри docker compose ps — кто unhealthy? Обычно Kafka дольше всех
поднимается (до 30 секунд в первый раз).
«Connection refused» от сервиса в pool/redis¶
Сервис стартанул раньше инфры. Должен быть depends_on: condition:
service_healthy в compose; если отсутствует — добавь и сделай make
rebuild.
Cross-service сценарии¶
Два варианта, когда нужно проверить «сервис A зовёт сервис B»:
Вариант 1: оба compose'а рядом¶
Чтобы review дозвонился до user внутри контейнера, используй
host.docker.internal:8001 (на macOS/Windows) или 172.17.0.1:8001 (на
Linux) в env-переменной USER_SERVICE_URL:
Портовые конфликты разруливай через .env per-compose.
Вариант 2: mock downstream в integration-тесте¶
Когда нужен не живой сервис, а просто детерминированный ответ — подними
httptest.NewServer в тесте и подставь его URL в конфиг тестируемого
сервиса. Подробнее — ../conventions/testing.md.
Переменные окружения¶
.env— не коммитится, живёт локально. Сюда ты кладёшь свои dev-значения..env.example— коммитится, содержит placeholder'ы. При смене переменных вinternal/config/обновляй оба: пример и документацию вREADME.mdсервиса.- docker-compose читает
.envавтоматически (с корня compose-файла).
Проверь, что всё ок¶
cd ~/projects/<service>
make bootstrap
curl -sf http://localhost:<port>/healthz
curl -sf http://localhost:<port>/readyz
make logs # смотри, что сервис пишет "starting ..." и без ERROR
Если до этого момента всё проходит — инфра поднята корректно. Переходи к
02-first-pr.md, если ещё не.