在CSDN学Golang云原生(Kubernetes Pod)

一,pod的定义与基本用法

在 Kubernetes 中,Pod 是最小的可部署单元,它包含一个或多个容器。使用 Golang 来定义和操作 Pod 时,需要使用 kubernetes/client-go 包提供的 API。

以下是 Golang 定义和基本用法 Pod 的示例:

  1. 安装 kubernetes/client-go 包

在 Golang 环境中安装 kubernetes/client-go 包,该包提供了访问 Kubernetes API Server 的客户端库。

go get k8s.io/client-go/...
  1. 编写代码定义 Pod

下面是一个简单的示例代码片段,可以用来创建一个包含两个容器的 Pod:

package main

import (
	"context"
	"fmt"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	config, err := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig")
	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}

	pod := &corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "example-pod",
			Namespace: "default",
			Labels: map[string]string{
				"app": "example-app",
			},
		},
		Spec: corev1.PodSpec{
			RestartPolicy: corev1.RestartPolicyOnFailure,
			Volumes: []corev1.Volume{
				{
					Name: "example-volume",
					VolumeSource: corev1.VolumeSource{
						EmptyDir: &corev1.EmptyDirVolumeSource{},
					},
				},
			},
			Containers: []corev1.Container{
				{
					Name:  "container-1",
					Image: "nginx",
					Ports: []corev1.ContainerPort{
						{
							Name:          "http",
							ContainerPort: 80,
							Protocol:      corev1.ProtocolTCP,
						},
					},
				},
				{
					Name:  "container-2",
					Image: "busybox",
					Command: []string{"sleep", "3600"},
					VolumeMounts: []corev1.VolumeMount{
						{
							Name:      "example-volume",
							MountPath: "/data",
						},
					},
				},
			},
			NodeSelector: map[string]string{
				"node-role.kubernetes.io/worker": "",
			},
			Tolerations: []corev1.Toleration{
				corev1.Toleration{Key: "key", Operator:"Equal", Value:"value"},
			},

			
		
	   },
    }
	
    _, err = clientset.CoreV1().Pods("default").Create(context.Background(), pod, metav1.CreateOptions{})
	if err != nil {
        panic(err.Error())
    }

	fmt.Println("Pod created successfully")
}
  1. 运行代码创建 Pod

使用 Golang 运行上面的示例代码,它会在 Kubernetes 集群中创建一个名为 example-pod 的 Pod,其中包含两个容器:nginx 和 busybox。Nginx 容器将公开 TCP 端口 80,并且 busybox 容器将在 /data 目录中挂载一个名为 example-volume 的空目录。

运行示例代码的命令如下:

go run main.go

以上是 Golang 定义和基本用法 Pod 的示例,可以根据实际需求修改代码。

二,pod生命周期与重启策略

在 Kubernetes 中,Pod 是最小的可部署单元。它包含一个或多个容器,并且有自己的生命周期和重启策略。

Golang 可以通过 Kubernetes 提供的 API 来定义和操作 Pod 的生命周期和重启策略。以下是一些常见的 Pod 生命周期和重启策略:

  1. Pod 生命周期

Pod 的生命周期分为三个阶段:

  • Pending:Pod 已经被创建,但是尚未调度到任何节点上。
  • Running:Pod 已经被调度到某个节点上并且至少有一个容器正在运行。
  • Terminated:Pod 所有容器都已停止运行。
  1. 重启策略

Pod 的重启策略指定了当某个容器失败时 Kubernetes 应该采取哪种行动:

  • Always:无论什么原因导致容器停止运行,Kubernetes 都会自动重新启动该容器。这是默认的重启策略。
  • OnFailure:只有当容器以非正常退出状态(如错误码不为 0)终止时,Kubernetes 才会自动重新启动该容器。
  • Never:当某个容器停止运行时,Kubernetes 不会自动重新启动该容器。

以下是一个 Golang 示例代码片段,用于定义 Pod 的生命周期和重启策略:

package main

import (
	"context"
	"fmt"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	config, err := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig")
	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}

	pod := &corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "example-pod",
			Namespace: "default",
			Labels: map[string]string{
				"app": "example-app",
			},
		},
		Spec: corev1.PodSpec{
			RestartPolicy: corev1.RestartPolicyOnFailure,
			Volumes: []corev1.Volume{
				corev1.Volume{
					Name: "example-volume",
					VolumeSource: corev1.VolumeSource{
						ConfigMap: &corev1.ConfigMapVolumeSource{
							LocalObjectReference: corev1.LocalObjectReference{Name:"configmap-name"},
						},
					},
				},
			},
			InitContainers: []corev1.Container{ // 定义 init container
                {
                    Name:"init-container-01",
                    Image:"busybox",
                    Command:["sleep", "10"],
                },
            },
            Containers: []corev1.Container{ // 定义主容器
				corev1.Container{
					Name:  "container-01",
					Image: "nginx",
					Command:["nginx"],
                    Args:["-g", "daemon off;"], 
					
				corev1.Container{
					Name:  "container-02",
					Image: "busybox",
                    Command:["sh", "-c"],
                    Args:[`while true; do echo "$(date) Hello, World!"; sleep 10 ; done`],
					VolumeMounts: []corev1.VolumeMount{
						corev1.VolumeMount{
							Name:      "example-volume",
							MountPath: "/data",
						},
					},
				},
			},
            NodeSelector: map[string]string{
                "node-role.kubernetes.io/worker": "",
            },
            Tolerations: []corev1.Toleration{ // 添加容忍
                corev1.Toleration{Key:"key", Operator:"Equal", Value:"value"},
            },
        },
    }

    _, err = clientset.CoreV1().Pods("default").Create(context.Background(), pod, metav1.CreateOptions{})
	if err != nil {
        panic(err.Error())
    }

	fmt.Println("Pod created successfully")
}

在上面的示例中,我们使用了 RestartPolicy 字段来定义 Pod 的重启策略。我们还使用了 InitContainers 字段来定义 Pod 中的初始化容器。

通过这些示例代码片段,你可以更好地理解 Pod 生命周期和重启策略。

三,容器镜像拉取策略

在 Golang 中,我们可以使用 Kubernetes 提供的 API 来定义容器镜像拉取策略。以下是一些常见的容器镜像拉取策略:

  1. Always

无论本地是否存在该镜像,都会尝试拉取最新版本。如果本地已经有该镜像,则会被更新为最新版本。

container := corev1.Container{
    Name: "example-container",
    Image: "nginx",
    ImagePullPolicy: corev1.PullAlways,
}
  1. IfNotPresent

如果本地已经有该镜像,则直接使用本地版本;否则尝试从远程仓库拉取最新版本。

container := corev1.Container{
    Name: "example-container",
    Image: "nginx",
    ImagePullPolicy: corev1.PullIfNotPresent,
}
  1. Never

只使用本地已经存在的该镜像,不尝试从远程仓库拉取任何版本。

container := corev1.Container{
    Name: "example-container",
    Image: "nginx",
    ImagePullPolicy: corev1.PullNever,
}

需要注意的是,这些策略可能会影响到你的 Pod 的行为和性能。例如,如果你选择了 Always 策略,则每次启动 Pod 时都会去检查并下载最新的镜像,这可能会增加启动时间和网络带宽消耗。因此,在选择镜像拉取策略时,请根据实际情况进行权衡和选择。

另外,还可以在 Pod 或者 Deployment 等资源定义时指定默认的镜像拉取策略。例如:

pod := &corev1.Pod{
    // ...
    Spec: corev1.PodSpec{
        Containers: []corev1.Container{
            {
                Name: "example-container",
                Image: "nginx",
                // 可以覆盖全局配置中定义的策略
                ImagePullPolicy: corev1.PullIfNotPresent,
            },
        },
        // 指定默认的镜像拉取策略
        ImagePullSecrets: []corev1.LocalObjectReference{{Name:"myregistrykey"}},
    },
}

上面的代码片段中,我们通过 ImagePullSecrets 字段来指定使用哪个 Secret 对象来拉取镜像。这里我们使用了名为 myregistrykey 的本地 Secret 对象。

四,init Container

在 Kubernetes 中,一个 Pod 可以包含多个容器。其中,除了主要的业务容器之外,还可以定义一个或多个 Init Container(初始化容器),用于在业务容器启动之前完成一些必要的预处理工作。

使用 Init Container 有以下几个好处:

  1. 解耦应用逻辑和初始化逻辑,使应用更加清晰可维护。
  2. 避免竞态条件和资源争夺等问题,提高系统可靠性和稳定性。
  3. 灵活控制启动顺序和执行流程,满足不同场景下的需求。

对于 Golang 应用程序来说,在 Kubernetes 中使用 Init Container 的方法与其他语言类似。以下是一个简单的示例代码:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'wget -O /work-dir/myservice https://myservice.com && chmod +x /work-dir/myservice']
    volumeMounts:
    - name: workdir-volume
      mountPath: /work-dir
  containers:
  - name: myapp-container
    image: myapp:v1.0.0
    command: ['/myapp']
    volumeMounts:
    - name: workdir-volume
      mountPath: /work-dir

  volumes:
  - name: workdir-volume
    emptyDir: {}

上面的 YAML 文件定义了一个 Pod,其中包含一个 Init Container 和一个业务容器。Init Container 的作用是下载并安装 myservice 程序到共享目录 /work-dir 中,而业务容器则通过挂载该目录来使用 myservice 程序。

需要注意的是,Init Container 的执行顺序是按照它们在 YAML 文件中的顺序依次执行的。只有当所有 Init Container 成功完成后,才会启动业务容器。如果任何一个 Init Container 失败,则整个 Pod 也将被标记为失败,并重新启动。

另外,还可以在创建 Deployment 或 StatefulSet 时指定 Init Container。例如:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: myapp
    spec:
      initContainers:
      - name: init-myservice
        image: busybox
        command: ['sh', '-c', 'wget -O /work-dir/myservice https://myservice.com && chmod +x /work-dir/myservice']
        volumeMounts:
        - name: workdir-volume
          mountPath: /work-dir
      containers:
      - name: myapp-container
        image: myapp:v1.0.0
        command: ['/myapp']
        volumeMounts:
        - name: workdir-volume
          mountPath: /work-dir

      volumes:
      - name: workdir-volume
        emptyDir: {}

上面的代码片段中,我们在 template 字段中定义了 Init Container 和业务容器,然后通过 Deployment 控制器来创建和管理多个 Pod。

五,容器资源配额

在 Kubernetes 中,可以为 Pod 和容器定义资源配额(Resource Quota),以限制它们所能使用的 CPU、内存等资源数量。这对于避免应用程序过度占用资源、提高系统可靠性和稳定性非常有用。

在 Golang 应用程序中,可以通过设置环境变量或代码方式来定义容器资源配额。以下是示例代码:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp-container
    image: myapp:v1.0.0
    command: ['/myapp']
    env:
    - name: CPU_LIMIT
      value: "500m"
    - name: MEMORY_LIMIT
      value: "256Mi"

上面的 YAML 文件定义了一个 Pod,其中包含一个名为 myapp-container 的容器,并且设置了它的 CPU 和内存限制分别为 500m 和 256Mi。

在 Golang 应用程序中,可以通过读取环境变量获取这些值并进行相应处理。例如:

import (
	"os"
)

func main() {
	cpuLimit := os.Getenv("CPU_LIMIT")
	memoryLimit := os.Getenv("MEMORY_LIMIT")
	// 使用 cpuLimit 和 memoryLimit 进行相应处理...
}

需要注意的是,Kubernetes 支持更多的资源配额类型和更细粒度的控制方式。例如,可以针对不同的命名空间、标签或用户组设置不同的配额规则。此外,还可以使用 Kubernetes 的自动扩缩容功能来根据资源使用情况动态调整 Pod 和容器的数量,以确保系统始终处于最佳状态。

六,容器声明周期处理函数

在 Golang 应用程序中,可以使用以下生命周期处理函数来处理容器的声明周期事件:

  • func init():在容器启动时执行。通常用于初始化应用程序的环境变量、配置等。
  • func main():在容器启动后立即执行。通常用于启动应用程序的服务或者监听端口。
  • func shutdown():在容器关闭之前执行。通常用于清理资源和状态,并停止正在运行的任务。

这些函数是可选的,您可以根据需要选择使用其中一个或多个。例如,如果您的应用程序不需要进行特殊初始化或清理操作,则无需编写 initshutdown 函数。

以下是示例代码,展示如何使用生命周期处理函数:

package main

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

func init() {
	fmt.Println("Initializing...")
}

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello World!"))
	})

	srv := &http.Server{Addr: ":8080"}

	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			fmt.Printf("listen: %s\n", err)
			os.Exit(1)
		}
	}()

	fmt.Println("Started server at :8080")

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	sig := <-c
	fmt.Println("Got signal:", sig)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	srv.Shutdown(ctx)
	fmt.Println("Server stopped gracefully")
}

func shutdown() {
	fmt.Println("Shutting down...")
	// 清理资源和状态
}

在上面的示例中,init 函数用于输出一个初始化消息。main 函数启动了一个 HTTP 服务器,并使用 signal.Notify() 监听 os.Interrupt 信号(即 Ctrl+C),以便在接收到该信号时优雅地关闭服务器。最后,当服务器关闭时,shutdown 函数被调用以清理资源。

需要注意的是,在 Kubernetes 中管理容器生命周期的方式有所不同。Kubernetes 使用一种称为控制器(Controller)的机制来管理容器和 Pod 的运行状态,并提供了相应的生命周期钩子函数来处理容器事件。

七,容器健康检查与服务可用性

在 Golang 应用程序中,可以使用以下方法来实现容器健康检查和服务可用性:

  1. HTTP 接口健康检查

HTTP 接口是最常见的容器健康检查方式之一。您可以在应用程序中添加一个简单的 /healthz 接口来提供健康状态信息。

示例代码如下:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello World!"))
	})

	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println(err)
	}
}

在上面的示例中,我们添加了一个 /healthz 接口来返回 200 OK 状态码和 "OK" 字符串表示应用程序正常运行。当 Kubernetes 发现该容器的该接口返回非 200 的 HTTP 状态码时,将会认为该容器不健康并重启该容器或者 Pod。

  1. TCP Socket 健康检查

除了 HTTP 接口外,还可以通过监听一个 TCP 端口来进行健康检查。这种方式要求 Kubernetes 配置 livenessProbereadinessProbe 分别使用 TCP socket 进行探测。

示例代码如下:

package main

import (
    "fmt"
    "net"
)

func main() {
    l, err := net.Listen("tcp", ":8080")
    if err != nil {
        fmt.Println(err)
    }
    
    defer l.Close()

    for {
        conn, err := l.Accept()
        if err != nil {
            fmt.Println(err)
            continue
        }

        go func(c net.Conn) {
            c.Write([]byte("OK\n"))
            c.Close()
        }(conn)
    }
}

在上面的示例中,我们监听 8080 端口并返回 "OK" 字符串表示容器健康。当 Kubernetes 发现该容器的 TCP Socket 不可用时,将会认为该容器不健康并重启该容器或者 Pod。

需要注意的是,在使用 TCP Socket 进行健康检查时,需要确保应用程序在启动后尽快开始监听端口,并且能够正确响应连接请求。否则 Kubernetes 将无法正常进行健康检查。

相关推荐
007php0072 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
aherhuo4 小时前
kubevirt网络
linux·云原生·容器·kubernetes
catoop5 小时前
K8s 无头服务(Headless Service)
云原生·容器·kubernetes
小峰编程6 小时前
独一无二,万字详谈——Linux之文件管理
linux·运维·服务器·云原生·云计算·ai原生
小马爱打代码6 小时前
云原生服务网格Istio实战
云原生
liuxuzxx6 小时前
1.24.1-Istio安装
kubernetes·istio·service mesh
道一云黑板报7 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes
运维小文7 小时前
K8S中的PV、PVC介绍和使用
docker·云原生·容器·kubernetes·存储
ζั͡山 ั͡有扶苏 ั͡✾8 小时前
Kubeadm+Containerd部署k8s(v1.28.2)集群(非高可用版)
云原生·容器·kubernetes
Hadoop_Liang8 小时前
Kubernetes ConfigMap的创建与使用
云原生·容器·kubernetes