Comme le dit le titre. Je voulais juste m'assurer que c'était le mouvement réel.
gcloud
est prête à être utilisée.)kubectl
est prête à être utilisée.$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"
$ gcloud version
Google Cloud SDK 312.0.0
$ 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"}
$ go version
go version go1.15.2 linux/amd64
https://github.com/sky0621/study-k8sOnGKE/tree/v0.1.0/try01
Golang
Configurez correctement un serveur Web et lorsqu'il reçoit un signal OS (SIGTERM
), il crache un journal ( GOT_NOTIFY
).
Préparez également un journal pour «différer» et vérifiez que le journal de différé n'apparaît pas lorsque le signal du système d'exploitation est reçu.
main.go
package main
import (
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
)
func main() {
fmt.Println("APP_START")
defer fmt.Println("DEFER")
//Goroutine en attente du signal du système d'exploitation (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)
}()
//Démarrez correctement un serveur HTTP
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 Un Dockerfile de construction en plusieurs étapes ordinaire.
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"]
L'image Docker utilise 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'
La coque pour la construction utilisant ce qui précède est ci-dessous.
build.sh
#!/usr/bin/env bash
set -euox pipefail
SCRIPT_DIR=$(dirname "$0")
cd "${SCRIPT_DIR}"
gcloud builds submit --config cloudbuild.yaml .
Obtenez l'image Docker du Container Registry. Il y a trois pods. Le port de conteneurs est 8080 (bien que je ne l'utilise pas cette fois).
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
Le shell à déployer en utilisant ce qui précède est ci-dessous.
J'ai besoin de l'ID du projet GCP que j'utilise, qui lui-même peut être récupéré à partir de la commande gcloud
dans mon environnement local.
Il était difficile de savoir comment spécifier l'ID du projet GCP sans l'écrire directement dans Yaml de k8s (* Cela peut être possible via ConfigMap ou Secret, mais si possible, c'est facile), alors réécrivez-le avec sed
.
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
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}"
$ ./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
$ ./deploy.sh
++ dirname ./deploy.sh
+ SCRIPT_DIR=.
+ echo .
.
+ cd .
・
・
・
+ kubectl apply -f deployment.yaml
deployment.apps/golang-app-try01 created
・
・
・
Il y a 3 pods.
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
golang-app-try01 3/3 3 3 4m19s
Si vous regardez le journal du conteneur à ce stade, vous pouvez voir que chacun des trois pods a un journal lorsque l'application démarre et lorsque la mise en veille du signal du système d'exploitation démarre.
$ ./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
Le journal (GOT_NOTIFY
) lorsque le signal du système d'exploitation a été reçu est sorti comme journal de chaque pod.
Le journal («DEFER») de la personne qui a préparé avec «différer» n'apparaît pas.
Si vous le mettez sur GKE, le contenu que vous souhaitez sûrement traiter lorsque l'application est arrêtée n'est pas «différer», mais Goroutine pour la réception du signal du système d'exploitation («SIGTERM») est configuré séparément.