https://www.voidking.com/dev-k8s-client-go-deploy/
https://github.com/voidking/k8s-client-go/
一,感興趣的章節(jié)
client-go
《使用client-go操作K8S》一文中,配置好了k8s-client-go項(xiàng)目国葬,可以使用這個(gè)項(xiàng)目對(duì)k8s集群進(jìn)行一些基本操作于颖。在此基礎(chǔ)上古今,本節(jié)會(huì)實(shí)現(xiàn)一些更高階的操作货邓。
判斷發(fā)布狀態(tài)
根據(jù)deployment和pod的狀態(tài)馏艾,怎樣判斷一次發(fā)布成功還是失斁俟濉捣辆?首先,要知道deployment和pod都有哪些狀態(tài)此迅。
1汽畴、通過(guò)kubectl命令獲取發(fā)布數(shù)據(jù)
kubectl get deployments hello-node -o json
kubectl get deployments nginx -o json
kubectl get pods -l app=hello-node -o json
kubectl get pods -l app=nginx -o json
2旧巾、獲取到的發(fā)布數(shù)據(jù)
發(fā)布成功的json數(shù)據(jù):hello-node.json
發(fā)布失敗的json數(shù)據(jù):nginx.json
3、具體可用狀態(tài)有哪些
deployment.generation
deployment.spec.replicas
deployment.status.observedGeneration
deployment.status.replicas
deployment.status.readyReplicas/unavailableReplicas
deployment.status.updatedReplicas
deployment.status.conditions[*].type{Available,Progressing} && deployment.status.conditions[*].status{True,False}
pod.status.phase{Pending,Running}
pod.status.conditions[*].type{Initialized,Ready,ContainersReady,PodScheduled} && pod.status.conditions[*].status{True,False}
pod.status.containerStatuses[*].state.{waiting,running}
4忍些、判斷條件組合
參考k8s-client-go/common/deployment.go文件的GetDeploymentStatus函數(shù)鲁猩。
二,感興趣的代碼
package common
import (
"encoding/json"
"fmt"
"io/ioutil"
apps_v1beta1 "k8s.io/api/apps/v1beta1"
core_v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/kubernetes"
"strings"
"time"
)
// 讀取deployment yaml文件
func ReadDeploymentYaml(filename string) (apps_v1beta1.Deployment) {
// 讀取YAML
deployYaml, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println(err)
return apps_v1beta1.Deployment{}
}
// YAML轉(zhuǎn)JSON
deployJson, err := yaml.ToJSON(deployYaml)
if err != nil {
fmt.Println(err)
return apps_v1beta1.Deployment{}
}
// JSON轉(zhuǎn)struct
var deployment apps_v1beta1.Deployment
err = json.Unmarshal(deployJson, &deployment)
if err != nil {
fmt.Println(err)
return apps_v1beta1.Deployment{}
}
return deployment
}
func ApplyDeployment(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment) {
var namespace string
if deployment.Namespace != "" {
namespace = deployment.Namespace
}else {
namespace = "default"
}
// 查詢k8s是否有該deployment
_, err := clientset.AppsV1beta1().Deployments(namespace).Get(deployment.Name, meta_v1.GetOptions{});
if err != nil {
if !errors.IsNotFound(err) {
fmt.Println(err)
return
}
// 不存在則創(chuàng)建
_, err = clientset.AppsV1beta1().Deployments(namespace).Create(&deployment)
if err != nil {
fmt.Println(err)
return
}
} else { // 已存在則更新
_, err = clientset.AppsV1beta1().Deployments(namespace).Update(&deployment)
if err != nil {
fmt.Println(err)
return
}
}
fmt.Printf("apply deployment %s success!\n", deployment.Name)
}
func DeleteDeployment(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment){
var namespace string
if deployment.Namespace != "" {
namespace = deployment.Namespace
}else {
namespace = "default"
}
err := clientset.AppsV1beta1().Deployments(namespace).Delete(deployment.Name, &meta_v1.DeleteOptions{})
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("delete deployment %s success!\n", deployment.Name)
}
func GetDeploymentStatus(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment) (success bool,reasons []string, err error) {
// 獲取deployment狀態(tài)
k8sDeployment, err := clientset.AppsV1beta1().Deployments("default").Get(deployment.Name, meta_v1.GetOptions{})
if err != nil {
return false,[]string{"get deployments status error"}, err
}
// 獲取pod的狀態(tài)
labelSelector := ""
for key, value := range deployment.Spec.Selector.MatchLabels {
labelSelector = labelSelector + key + "=" + value + ","
}
labelSelector = strings.TrimRight(labelSelector, ",")
podList, err := clientset.CoreV1().Pods("default").List(meta_v1.ListOptions{LabelSelector: labelSelector})
if err != nil {
return false, []string{"get pods status error"}, err
}
readyPod := 0
unavailablePod := 0
waitingReasons := []string{}
for _, pod := range podList.Items {
// 記錄等待原因
for _, containerStatus := range pod.Status.ContainerStatuses{
if containerStatus.State.Waiting != nil {
reason := "pod " + pod.Name + ", container " + containerStatus.Name + ", waiting reason: " + containerStatus.State.Waiting.Reason
waitingReasons = append(waitingReasons, reason)
}
}
podScheduledCondition := GetPodCondition(pod.Status, core_v1.PodScheduled)
initializedCondition := GetPodCondition(pod.Status, core_v1.PodInitialized)
readyCondition := GetPodCondition(pod.Status, core_v1.PodReady)
containersReadyCondition := GetPodCondition(pod.Status, core_v1.ContainersReady)
if pod.Status.Phase == "Running" &&
podScheduledCondition.Status == "True" &&
initializedCondition.Status == "True" &&
readyCondition.Status == "True" &&
containersReadyCondition.Status == "True" {
readyPod++
}else {
unavailablePod++
}
}
// 根據(jù)container狀態(tài)判定
if len(waitingReasons) != 0 {
return false, waitingReasons, nil
}
// 根據(jù)pod狀態(tài)判定
if int32(readyPod) < *(k8sDeployment.Spec.Replicas) ||
int32(unavailablePod) != 0{
return false, []string{"pods not ready!"}, nil
}
// deployment進(jìn)行狀態(tài)判定
availableCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentAvailable)
progressingCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentProgressing)
if k8sDeployment.Status.UpdatedReplicas != *(k8sDeployment.Spec.Replicas) ||
k8sDeployment.Status.Replicas != *(k8sDeployment.Spec.Replicas) ||
k8sDeployment.Status.AvailableReplicas != *(k8sDeployment.Spec.Replicas) ||
availableCondition.Status != "True" ||
progressingCondition.Status != "True" {
return false, []string{"deployments not ready!"}, nil
}
if k8sDeployment.Status.ObservedGeneration < k8sDeployment.Generation {
return false, []string{"observed generation less than generation!"}, nil
}
// 發(fā)布成功
return true, []string{}, nil
}
func PrintDeploymentStatus(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment) {
// 拼接selector
labelSelector := ""
for key, value := range deployment.Spec.Selector.MatchLabels {
labelSelector = labelSelector + key + "=" + value + ","
}
labelSelector = strings.TrimRight(labelSelector, ",")
for {
// 獲取k8s中deployment的狀態(tài)
k8sDeployment, err := clientset.AppsV1beta1().Deployments("default").Get(deployment.Name, meta_v1.GetOptions{})
if err != nil {
fmt.Println(err)
}
// 打印deployment狀態(tài)
fmt.Printf("-------------deployment status------------\n")
fmt.Printf("deployment.name: %s\n", k8sDeployment.Name)
fmt.Printf("deployment.generation: %d\n", k8sDeployment.Generation)
fmt.Printf("deployment.status.observedGeneration: %d\n", k8sDeployment.Status.ObservedGeneration)
fmt.Printf("deployment.spec.replicas: %d\n", *(k8sDeployment.Spec.Replicas))
fmt.Printf("deployment.status.replicas: %d\n", k8sDeployment.Status.Replicas)
fmt.Printf("deployment.status.updatedReplicas: %d\n", k8sDeployment.Status.UpdatedReplicas)
fmt.Printf("deployment.status.readyReplicas: %d\n", k8sDeployment.Status.ReadyReplicas)
fmt.Printf("deployment.status.unavailableReplicas: %d\n", k8sDeployment.Status.UnavailableReplicas)
for _, condition := range k8sDeployment.Status.Conditions {
fmt.Printf("condition.type: %s, condition.status: %s, condition.reason: %s\n", condition.Type, condition.Status, condition.Reason)
}
// 獲取pod狀態(tài)
podList, err := clientset.CoreV1().Pods("default").List(meta_v1.ListOptions{LabelSelector: labelSelector})
if err != nil {
fmt.Println(err)
return
}
for index, pod := range podList.Items {
// 打印pod的狀態(tài)
fmt.Printf("-------------pod %d status------------\n", index)
fmt.Printf("pod.name: %s\n", pod.Name)
fmt.Printf("pod.status.phase: %s\n", pod.Status.Phase)
for _, condition := range pod.Status.Conditions {
fmt.Printf("condition.type: %s, condition.status: %s, conditon.reason: %s\n", condition.Type, condition.Status, condition.Reason)
}
for _, containerStatus := range pod.Status.ContainerStatuses {
if containerStatus.State.Waiting != nil {
fmt.Printf("containerStatus.state.waiting.reason: %s\n", containerStatus.State.Waiting.Reason)
}
if containerStatus.State.Running != nil {
fmt.Printf("containerStatus.state.running.startedAt: %s\n", containerStatus.State.Running.StartedAt)
}
}
}
availableCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentAvailable)
progressingCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentProgressing)
if k8sDeployment.Status.UpdatedReplicas == *(k8sDeployment.Spec.Replicas) &&
k8sDeployment.Status.Replicas == *(k8sDeployment.Spec.Replicas) &&
k8sDeployment.Status.AvailableReplicas == *(k8sDeployment.Spec.Replicas) &&
k8sDeployment.Status.ObservedGeneration >= k8sDeployment.Generation &&
availableCondition.Status == "True" &&
progressingCondition.Status == "True" {
fmt.Printf("-------------deploy status------------\n")
fmt.Println("success!")
}else{
fmt.Printf("-------------deploy status------------\n")
fmt.Println("waiting...")
}
time.Sleep(3 * time.Second)
}
}
// GetDeploymentCondition returns the condition with the provided type.
func GetDeploymentCondition(status apps_v1beta1.DeploymentStatus, condType apps_v1beta1.DeploymentConditionType) *apps_v1beta1.DeploymentCondition {
for i := range status.Conditions {
c := status.Conditions[i]
if c.Type == condType {
return &c
}
}
return nil
}
func GetPodCondition(status core_v1.PodStatus, condType core_v1.PodConditionType) *core_v1.PodCondition {
for i := range status.Conditions {
c := status.Conditions[i]
if c.Type == condType {
return &c
}
}
return nil
}