Tương tác với Kubernetes sử dụng Golang (P2)
Bài đăng này đã không được cập nhật trong 4 năm
Giới thiệu

Link bài viết gốc trên blog của mình: https://ductn.info/controller-kubernetes-with-golang-2/
Nối tiếp phần 1
mình thực hiện tiếp 1 tool cho cụm kubernetes sử dụng thư viện client-go.
Ở phần trước, mình đã demo in ra list tên của các pods trong cụm kubernetes,
trong phần này mình sẽ làm 1 tool giúp chúng có thể update phiên bản image
đang được sử dụng trong deployment và deploy lại container theo image mới.
Trông ứng dụng sẽ như thế này :3
Link source code đây nha: https://github.com/ductnn/kugo
Start
Vẫn giống như phần trước,
để bắt đầu anh em cài đặt golang và set up cụm kubernetes, sau đó anh em có
thể xem lại bước 1-2 ở phần 1 để khởi tạo tool nhé :3.
package main
import (
	"context"
	"flag"
	"fmt"
	"os"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)
// Kube config path
func GetKubeConfigPath() string {
	var kubeConfigPath string
	homeDir := homedir.HomeDir()
	if _, err := os.Stat(homeDir + "/.kube/config"); err == nil {
		kubeConfigPath = homeDir + "/.kube/config"
	} else {
		fmt.Println("Enter kubernetes config directory: ")
		fmt.Scanf("%s", kubeConfigPath)
	}
	return kubeConfigPath
}
func main() {
	// Set Kube config
	kubeConfigPath := GetKubeConfigPath()
	fmt.Println(kubeConfigPath)
	// Build configuration from config file
	config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)
	if err != nil {
		panic(err)
	}
	// Create clientser
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}
}
Mình sử dụng flag là package nổi tiếng của golang
hỗ trợ chúng ta truyền vào các flags ở command. Ví dụ như demo ở bên trên
mình truyền vào 3 flags sau khi build file main.go.
-deployment test-app
-app test-app
-image ductn4/green-rain:v2
Chúng ta sẽ dùng flag để tạo những commad flags như ví dụ trên. Chúng ta có
thể sử dụng os.Args[] từ os package. Đối với cli tool nhỏ thì dùng os.Args[]
xong check. Còn không dùng flag sẽ tiện hơn. Ngoài ra, flag hỗ trợ luôn -h
cho chúng ta để show ra ý nghĩa của flag trong command:
➜  kugo git:(master) ✗ ./main -h
/Users/ductn/.kube/config
Usage of ./main:
  -app string
    	application name (default "app")
  -deployment string
    	deployment name
  -image string
    	new image name
OK!!! Bắt đầu tạo ra các flags:
deploymentName := flag.String("deployment", "", "deployment name")
imageName := flag.String("image", "", "new image name")
appName := flag.String("app", "app", "application name")
flag.Parse()
if *deploymentName == "" {
    fmt.Println("The deployment name must be specify.")
    os.Exit(0)
}
if *imageName == "" {
    fmt.Println("The new image name must be specify.")
    os.Exit(0)
}
-deployment name:<string>: Tên của deployment đang chạy.
-app name:<string>: Tên của ứng dụng đang chạy.
-image name:<string>: Tên image mới cần deploy.
Sau khi tạo xong flag, chúng ta khởi tạo deployment, phần này giống như
khởi tạo pods trong phần trước:
// Create Deployment
deployment, err := clientset.AppsV1().Deployments("default").Get(context.TODO(), *deploymentName, metav1.GetOptions{})
if err != nil {
    panic(err)
}
Tiếp theo, chúng ta thực hiện check để kiểm tra trạng thái của deployment
xem có bị lỗi hoặc chưa deploy:
if errors.IsNotFound(err) {
    fmt.Printf("Deployment not found\n")
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
    fmt.Printf("Error getting deployment%v\n", statusError.ErrStatus.Message)
} else if err != nil {
    panic(err)
} else {
    // Next step ...
}
Kiểm tra xong, chúng ta sẽ thực hiện thay thế image cũ thành image mới:
containers := &deployment.Spec.Template.Spec.Containers
found := false
for i := range *containers {
    c := *containers
    if c[i].Name == *appName {
        fmt.Println("Old Version Image: ", c[i].Image)
        fmt.Println("New Version Image: ", *imageName)
        c[i].Image = *imageName
        found = true
    }
}
Cuối cùng, chúng ta sẽ update lại deployment theo phiên bản mới của image
_, err := clientset.AppsV1().Deployments("default").Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {
    panic(err)
}
Demo
Bước 1: Mình sẽ deploy 1 deployment cùng với service: NodePort, mình
có tạo sẵn 1 file deployment ở đây
anh em có thể dùng luôn:
➜  test git:(master) ✗ kubectl apply -f deployment.yml
service/app-service created
deployment.apps/test-app created
➜  test git:(master) ✗ kubectl get all
NAME                            READY   STATUS    RESTARTS   AGE
pod/test-app-64d48d75c7-ctztl   1/1     Running   0          51s
NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/app-service   NodePort    10.99.148.96   <none>        3000:32691/TCP   51s
service/kubernetes    ClusterIP   10.96.0.1      <none>        443/TCP          3m31s
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/test-app   1/1     1            1           51s
NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/test-app-64d48d75c7   1         1         1       51s
Mình sử dụng image: ductn4/green-rain:v1.0.1 để build 1 hiệu ứng nhỏ, anh em
bật vô xem đẹp lắm :3
Bước 2: Build đống code vừa viết nào :3, sau khi build xong sẽ sinh ra 1
file main
➜  kugo git:(master) ✗ go build main.go
➜  kugo git:(master) ✗ ls
README.md go.mod    go.sum    main      main.go   test
Bước 3: Thực thi file main vừa tạo ra:
➜  kugo git:(master) ✗ ./main -deployment test-app -app test-app -image ductn4/green-rain:v2
/Users/ductn/.kube/config
Found deployment
Name deployment:  test-app
Old Version Image:  ductn4/green-rain:v1.0.1
New Version Image:  ductn4/green-rain:v2
Anh em thấy đã có thông báo thay đổi version của image, Check tý coi :3
➜  kugo git:(master) ✗ kubectl describe pods test-app-67c5b469d7-9k6lb
Name:         test-app-67c5b469d7-9k6lb
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Mon, 16 Aug 2021 23:58:39 +0700
Labels:       app=test-app
              pod-template-hash=67c5b469d7
Annotations:  <none>
Status:       Running
IP:           172.17.0.4
IPs:
  IP:           172.17.0.4
Controlled By:  ReplicaSet/test-app-67c5b469d7
Containers:
  test-app:
    Container ID:   docker://bd06a004dee744207fd955191ed1df2e204254b1a44a2e1f0cc8e7c9bef20a4d
    Image:          ductn4/green-rain:v2
    Image ID:       docker-pullable://ductn4/green-rain@sha256:31ec7424010c546d7cc028bf0355ec9dd58e4818e8cc3e266ff44a9ff7a3c109
    Port:           3000/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 16 Aug 2021 23:58:48 +0700
    Ready:          True
    ...
Vậy là image đã được update và deploy thành công, anh em vô xem lại hiệu ứng
nha, ver 2 nhìn xịn hơn ver 1 ở trên :3.
Mình đã làm xong tiếp 1 cái tool nhỏ nữa, anh em nào còn có ý tưởng gì hay hay chia sẻ để có thể cùng làm nha :3
Cảm ơn anh em đã đọc 😄😄😄.
All rights reserved
 
  
 