perf(container): образ без apt-зависимостей и встроенный healthcheck
- рантайм не тянет ca-certificates/tzdata/curl: bundle сертификатов копируется из официального alpine-образа, healthcheck выполняет сам бинарник - cmd/glchat: подкоманда healthcheck (HTTP-запрос к /healthz с таймаутом) - compose: APP_VERSION передаётся в environment (версия видна в meta без пересборки) - бюджет §9.1: базовый слой debian-slim + 9.2 MB бинарник + 356 KB клиент
This commit is contained in:
@@ -4,11 +4,14 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"glchat/internal/config"
|
||||
"glchat/internal/database"
|
||||
@@ -23,12 +26,51 @@ var (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// healthcheck используется HEALTHCHECK контейнера: собственный бинарник
|
||||
// избавляет образ от curl и лишних пакетов.
|
||||
if len(os.Args) > 1 && os.Args[1] == "healthcheck" {
|
||||
os.Exit(healthcheck())
|
||||
}
|
||||
if err := run(); err != nil {
|
||||
slog.Error("glchat exited with error", slog.Any("error", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func healthcheck() int {
|
||||
addr := config.DefaultListenAddr
|
||||
if cfg, err := config.Load(); err == nil {
|
||||
addr = cfg.ListenAddr
|
||||
}
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
host, port = "127.0.0.1", "8080"
|
||||
}
|
||||
if host == "" || host == "0.0.0.0" || host == "::" {
|
||||
host = "127.0.0.1"
|
||||
}
|
||||
url := "http://" + net.JoinHostPort(host, port) + "/healthz"
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
defer func() {
|
||||
_, _ = io.Copy(io.Discard, resp.Body)
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func run() error {
|
||||
if v := os.Getenv("APP_VERSION"); v != "" {
|
||||
version = v
|
||||
|
||||
Reference in New Issue
Block a user