结论

我们合理的配置好下面的参数就能实现先停止接收流量,等待60s 处理完本身已经接收的流量

spec.template.spec.terminationGracePeriodSeconds
spec.template.spec.containers.lifecycle

完整的yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
      nodeSelector:
        kubernetes.io/hostname: test-01-aws-001
      terminationGracePeriodSeconds: 70  # 总的优雅终止时间
      containers:
      - name: example-container
        image: test:v1.0
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 60"]  # 在这里执行摘除操作
        ports:
        - containerPort: 9001

测试过程

测试程序

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

type QueryConcurrency struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    struct {
		GlobalConcurrency int  `json:"globalConcurrency"`
		NodeRatio         int  `json:"nodeRatio"`
		DilatationSwitch  bool `json:"dilatationSwitch"`
	} `json:"data"`
}

func queryConcurrencyHandler(w http.ResponseWriter, r *http.Request) {
	// 设置返回数据
	response := QueryConcurrency{
		Code:    200,
		Message: "Success",
		Data: struct {
			GlobalConcurrency int  `json:"globalConcurrency"`
			NodeRatio         int  `json:"nodeRatio"`
			DilatationSwitch  bool `json:"dilatationSwitch"`
		}{
			GlobalConcurrency: 100,
			NodeRatio:         50,
			DilatationSwitch:  true,
		},
	}

	// 设置响应头
	w.Header().Set("Content-Type", "application/json")

	// 将响应数据编码为 JSON 格式
	jsonData, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 写入响应数据
	w.Write(jsonData)
}
func actuatorInfo(w http.ResponseWriter, r *http.Request) {
	hostname, err := os.Hostname()
	if err != nil {
		fmt.Printf("Error getting hostname: %v\n", err)
		return
	}

	response := QueryConcurrency{
		Code:    200,
		Message: "Success" + hostname,
	}
	jsonData, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 写入响应数据
	w.Write(jsonData)
	count := 0
	count++
	fmt.Println("/actuator/info", count)

}
// 调用接口20s后才返回结果,主要用于测试停止接收流量,原有已经接收的请求能正常返回
func sleepTime(w http.ResponseWriter, r *http.Request) {
	response := QueryConcurrency{
		Code:    200,
		Message: "Success",
	}
	jsonData, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	time.Sleep(time.Second * 30)
	// 写入响应数据
	w.Write(jsonData)
}
func main() {
    // 每隔1s打印一行日志;
	go func() {
		for {
			fmt.Println("Logging every second")
			time.Sleep(1 * time.Second)
		}
	}()
	//http.HandleFunc("/queryConcurrency", queryConcurrencyHandler)
	http.HandleFunc("/actuator/info", actuatorInfo)
	http.HandleFunc("/sleep", sleepTime)
	http.ListenAndServe(":9001", nil)
	fmt.Println(1)
}

构建镜像

FROM busybox:latest
COPY test-http-Query /
CMD /test-http-Query

#docker build -t test:v1.0 .

启动服务

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
      nodeSelector:
        kubernetes.io/hostname: test-01-aws-001
      terminationGracePeriodSeconds: 70  # 总的优雅终止时间
      containers:
      - name: example-container
        image: test:v1.1
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 60"]  # 在这里执行摘除操作
        ports:
        - containerPort: 9001
---
apiVersion: v1
kind: Service
metadata:
  name: example-deployment
spec:
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 9001
  selector:
    app: example

测试过程

  1. 循环请求 /actuator/info 接口
 while  true; do curl http://example-deployment/actuator/info; sleep 1 ; done
  1. 打开pod的日志输出
  2. 请求/sleep 接口的同时设置pod的副本数为0;

结论

当我们设置完pod的副本数为0 的时候,观察步骤1 输出内容为请求失败;说明这个时候新的HTTP流量已经无法进入

然后 pod的日志还在继续输出我们每隔1s打印的日志;说明这个时候pod还在运行

等到20s 后 /sleep 接口得到返回结果,说明本身已经接收到的流量能处理完成