Тестирование корректного завершения работы на HTTP-сервере во время развертывания в Kubernetes - PullRequest
0 голосов
/ 07 ноября 2019

Я следовал некоторым учебникам о том, как настроить HTTP-сервер и протестировать его в локальном кластере Kubernetes (используя minikube).

Я также реализовал изящное отключение из некоторых найденных примеров и ожидалчто после повторного перезапуска в Kubernetes не будет простоев.

Чтобы убедиться в этом, я начал выполнять нагрузочные тесты (используя Apache Benchmark , запустив ab -n 100000 -c 20 <addr>) и запустив kubectl rollout restart во времябенчмаркинг, но ab останавливается, как только выполняется повторный перезапуск.

Вот моя текущая настройка проекта:

Dockerfile

FROM golang:1.13.4-alpine3.10

RUN mkdir /app
ADD . /app
WORKDIR /app

RUN go build -o main src/main.go
CMD ["/app/main"]

src / main.go

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"

    "github.com/gorilla/mux"
)

func main() {
    srv := &http.Server{
        Addr:    ":8080",
        Handler: NewHTTPServer(),
    }

    idleConnsClosed := make(chan struct{})
    go func() {
        sigint := make(chan os.Signal, 1)
        signal.Notify(sigint, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
        <-sigint

        // We received an interrupt signal, shut down.
        if err := srv.Shutdown(context.Background()); err != nil {
            // Error from closing listeners, or context timeout:
            log.Printf("HTTP server Shutdown: %v", err)
        }

        close(idleConnsClosed)
    }()

    log.Printf("Starting HTTP server")
    running = true
    if err := srv.ListenAndServe(); err != http.ErrServerClosed {
        // Error starting or closing listener:
        log.Fatalf("HTTP server ListenAndServe: %v", err)
    }

    <-idleConnsClosed
}

func NewHTTPServer() http.Handler {
    r := mux.NewRouter()

    // Ping
    r.HandleFunc("/", handler)

    return r
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

kubernetes / deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp
spec:
  replicas: 10
  selector:
    matchLabels:
      app: myapp
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 5
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: dickster/graceful-shutdown-test:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 8080

Чего-то не хватает в этой настройке? Согласно стратегии rollingUpdate должно быть не менее пяти работающих модулей, которые должны обслуживать входящие запросы, но ab завершает работу с ошибкой apr_socket_recv: Connection reset by peer (54). Я также попытался добавить тесты готовности / живучести, но не повезло. Я подозреваю, что они здесь тоже не нужны.

1 Ответ

1 голос
/ 07 ноября 2019

Чтобы это работало без простоев, необходимо, чтобы модули перестали получать новые соединения, в то время как модулу разрешено изящно завершать обработку текущих соединений. Это означает, что модуль должен быть запущен, но не готов, чтобы к нему не отправлялись новые запросы.

Ваша служба будет сопоставлять все модули, используя выбранный вами селектор меток (я полагаю app: myapp), и будет использоватьлюбой модуль в состоянии готовности в качестве возможного бэкэнда. Модуль помечен как готовый, пока он проходит готовностьПроба. Поскольку у вас нет настроенного зонда, состояние модуля будет по умолчанию готово, пока он работает.

Просто настроенный readinessProbe очень поможет, но не обеспечит 100% работоспособности,это потребует некоторых изменений в вашем коде, чтобы вызвать сбой readinessProbe (поэтому новые запросы не отправляются), в то время как контейнер изящно завершает текущие соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...