Graceful shutdown
Тема дорожной карты · Golang
Graceful shutdown в Go — практика корректной остановки работающего сервиса при получении сигнала завершения, обеспечивающая завершение всех обрабатываемых запросов, закрытие открытых соединений с базой данных и выход фоновых goroutines до завершения процесса. Стандартный паттерн использует signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) (Go 1.16+) для получения context.Context, отменяемого при получении сигнала, затем передаёт этот контекст в server.Shutdown(ctx) у *http.Server для дренирования активных соединений без принятия новых. Для gRPC-серверов grpcServer.GracefulStop() выполняет аналогичный дренаж, ожидая завершения всех активных RPC-вызовов перед остановкой. Kubernetes полагается на graceful shutdown для достижения zero-downtime rolling deployments: kubelet отправляет SIGTERM, ждёт terminationGracePeriodSeconds (по умолчанию 30 с), а затем отправляет SIGKILL — поэтому Go-сервис должен уложить завершение в этот интервал. Лучшие практики включают закрытие пулов соединений с базой данных (db.Close()), сброс буферов структурированных логов (Zap logger.Sync()), остановку фоновых воркеров через отмену контекста и использование sync.WaitGroup для ожидания завершения всех goroutines перед возвратом из main.
Как это работает
Graceful shutdown знаменито прост: go build создаёт один статический бинарь, запускаемый на любом хосте с тем же OS+arch. Кросс-компиляция через GOOS=linux GOARCH=amd64 go build. Контейнеризуйте бинарь через FROM scratch или FROM gcr.io/distroless/static (несколько МБ total). go build -ldflags="-s -w" — для удаления debug-символов (меньше бинарь). Health-эндпойнты: /healthz, /readyz. Graceful shutdown через http.Server.Shutdown(ctx).
Когда применять
Multi-stage Dockerfile: builder-образ гонит go build; runner — scratch или distroless с одним бинарём + CA-сертификатами. Всегда graceful SIGTERM — drain in-flight запросы до выхода. Версию встраивайте через -ldflags "-X main.Version=$(git describe)" для вывода myapp version. Запуск под non-root, read-only ФС, минимальные capabilities.
Типичные ошибки
Ловушки Graceful shutdown: FROM alpine, но компиляция против glibc (CGO_ENABLED=1 + alpine = мистические крэши — используйте CGO_ENABLED=0); нет CA-сертификатов в scratch-образах (TLS валится x509-ошибками — добавьте ca-certificates); нет graceful shutdown (k8s rolling-деплои дропают in-flight запросы); огромные бинари из-за забытых -w -s-флагов.