[GKE] Setzen Sie die Bereitstellungsreplikate auf 0 und benachrichtigen Sie die Go-App über das Betriebssystemsignal SIGTERM

Thema

Wie der Titel schon sagt. Ich wollte nur sicherstellen, dass es der eigentliche Schritt war.

Annahme

Entwicklungsumgebung

OS - Linux(Ubuntu)

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"

gcloud

$ gcloud version
Google Cloud SDK 312.0.0

kubectl

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.9", GitCommit:"4fb7ed12476d57b8437ada90b4f93b17ffaeed99", GitTreeState:"clean", BuildDate:"2020-07-15T16:18:16Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"17+", GitVersion:"v1.17.12-gke.2502", GitCommit:"974eff7a63e05b7eb05c9aded92fae8a3ce14521", GitTreeState:"clean", BuildDate:"2020-10-19T17:01:32Z", GoVersion:"go1.13.15b4", Compiler:"gc", Platform:"linux/amd64"}

#Backend

#Language --Golang

$ go version
go version go1.15.2 linux/amd64

Trainieren

Satz von Quellen

https://github.com/sky0621/study-k8sOnGKE/tree/v0.1.0/try01

Quelle

Golang Richten Sie einen Webserver entsprechend ein, und wenn er ein Betriebssystemsignal ("SIGTERM") empfängt, spuckt er ein Protokoll ("GOT_NOTIFY") aus. Bereiten Sie auch ein Protokoll für "Zurückstellen" vor und stellen Sie sicher, dass das Verzögerungsprotokoll nicht angezeigt wird, wenn das Betriebssystemsignal empfangen wird.

main.go


package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	fmt.Println("APP_START")
	defer fmt.Println("DEFER")

	//Goroutine wartet auf OS-Signal (SIGTERM)
	go func() {
		fmt.Println("BEFORE_NOTIFY")
		q := make(chan os.Signal, 1)
		signal.Notify(q, syscall.SIGTERM)
		<-q
		fmt.Println("GOT_NOTIFY")

		os.Exit(-1)
	}()

	//Starten Sie einen HTTP-Server ordnungsgemäß
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if _, err := fmt.Fprint(w, "Hello"); err != nil {
			fmt.Printf("HANDLE_ERROR_OCCURRED: %+v", err)
		}
	})
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Printf("SERVE_ERROR_OCCURRED: %+v", err)
	}

	fmt.Println("APP_END")
}

Dockerfile Eine gewöhnliche mehrstufige Docker-Datei.

FROM golang:1.15 as builder
WORKDIR /app
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o server

FROM gcr.io/distroless/base
COPY --from=builder /app/server /server
CMD ["/server"]

Cloud Build-Einstellungen

Das Docker-Image verwendet Container Registry.

cloudbuild.yaml


steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/golang-app-try01', '.' ]
images:
  - 'gcr.io/$PROJECT_ID/golang-app-try01'

Die Hülle für den Bau mit den oben genannten ist unten.

build.sh


#!/usr/bin/env bash
set -euox pipefail
SCRIPT_DIR=$(dirname "$0")
cd "${SCRIPT_DIR}"

gcloud builds submit --config cloudbuild.yaml .

Bereitstellungseinstellungen

Rufen Sie das Docker-Image aus der Container-Registrierung ab. Es gibt drei Hülsen. Der Container-Port ist 8080 (obwohl ich ihn diesmal nicht verwenden werde).

deployment.yaml


apiVersion: apps/v1
kind: Deployment
metadata:
  name: golang-app-try01
spec:
  replicas: 3
  selector:
    matchLabels:
      app: golang-app-try01
  template:
    metadata:
      labels:
        app: golang-app-try01
    spec:
      containers:
        - name: golang-app-try01
          image: gcr.io/MY_GCP_PROJECT_ID/golang-app-try01
          ports:
            - containerPort: 8080

Die Shell, die mithilfe der oben genannten Informationen bereitgestellt werden soll, befindet sich unten. Ich benötige die ID des von mir verwendeten GCP-Projekts, die selbst über den Befehl gcloud in meiner lokalen Umgebung abgerufen werden kann. Es war schwierig herauszufinden, wie die GCP-Projekt-ID angegeben werden kann, ohne sie direkt in Yaml von k8s zu schreiben (* Möglicherweise über ConfigMap oder Secret, aber wenn möglich, ist dies einfach). Schreiben Sie sie daher mit sed neu.

deploy.sh


#!/usr/bin/env bash
set -euox pipefail
SCRIPT_DIR=$(dirname "$0")
cd "${SCRIPT_DIR}"

project=$(gcloud config get-value project)
if [[ -z "${project}" ]]; then
  echo -n "need project"
  exit 1
fi
echo "${project}"

sed -i -e "s/MY_GCP_PROJECT_ID/${project}/" deployment.yaml

kubectl apply -f deployment.yaml

sed -i -e "s/${project}/MY_GCP_PROJECT_ID/" deployment.yaml

Shell zum Umschreiben der Anzahl der Pods

replica_n.sh


#!/usr/bin/env bash
set -euox pipefail
SCRIPT_DIR=$(dirname "$0")
cd "${SCRIPT_DIR}"

num=${1:-}

if [ -z "${num}" ]; then
  echo -n "input replicas number: "
  read num
fi

kubectl scale deployment golang-app-try01 --replicas="${num}"

Funktionsprüfung

Erstellen Sie die App (erstellen Sie ein Docker-Image und speichern Sie es in der Container-Registrierung).

$ ./build.sh 
++ dirname ./build.sh
+ SCRIPT_DIR=.
+ echo .
.
+ cd .
+ gcloud builds submit --config cloudbuild.yaml .
Creating temporary tarball archive of 6 file(s) totalling 1.7 KiB before compression.
・
・
・
DONE
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ID                                    CREATE_TIME                DURATION  SOURCE                                                                                   IMAGES                                        STATUS
6452c516-cfbf-4497-b536-378023cbc34d  2020-11-03T19:29:14+00:00  29S       gs://XXXXXXXX_cloudbuild/source/1604431752.38075-ccb069fbb0d0413382dc79d42e5c618a.tgz  gcr.io/XXXXXXXX/golang-app-try01 (+1 more)  SUCCESS

screenshot-console.cloud.google.com-2020.11.04-05_33_09.png

Bereitstellen auf GKE

$ ./deploy.sh 
++ dirname ./deploy.sh
+ SCRIPT_DIR=.
+ echo .
.
+ cd .
・
・
・
+ kubectl apply -f deployment.yaml
deployment.apps/golang-app-try01 created
・
・
・

Es gibt 3 Hülsen.

$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
golang-app-try01   3/3     3            3           4m19s

Wenn Sie sich das Containerprotokoll an dieser Stelle ansehen, können Sie sehen, dass jeder der drei Pods ein Protokoll darüber enthält, wann die App gestartet wird und wann der Betriebssystem-Signal-Standby startet.

screenshot-console.cloud.google.com-2020.11.04-04_52_58.png

Ändern Sie die Anzahl der Pods auf 0

$ ./replica_n.sh 0
++ dirname ./replica_n.sh
+ SCRIPT_DIR=.
+ echo .
.
+ cd .
+ num=0
+ '[' -z 0 ']'
+ kubectl scale deployment golang-app-try01 --replicas=0
deployment.apps/golang-app-try01 scaled

Das Protokoll (GOT_NOTIFY), als das Betriebssystemsignal empfangen wurde, wurde als Protokoll jedes Pods ausgegeben. Das Protokoll (DEFER) der Person, die mit defer erstellt hat, wird nicht angezeigt.

screenshot-console.cloud.google.com-2020.11.04-04_53_28.png

Zusammenfassung

Wenn Sie es auf GKE setzen, ist der Inhalt, den Sie sicher verarbeiten möchten, wenn die Anwendung gestoppt wird, nicht "verzögern", sondern Goroutine zum Empfangen des Betriebssystemsignals ("SIGTERM") wird separat eingerichtet.

Recommended Posts

[GKE] Setzen Sie die Bereitstellungsreplikate auf 0 und benachrichtigen Sie die Go-App über das Betriebssystemsignal SIGTERM
[Einführung in cx_Oracle] (Teil 4) Abrufen und Scrollen der Ergebnismenge