0
点赞
收藏
分享

微信扫一扫

client-go使用总结二,创建podshell并执行命令

IT程序员 2022-06-27 阅读 57

podshell顾名思义就是创建一个可以多次执行shell命令的pod,并且不会自动销毁,多用于需要执行多条一次性命令,并获取其执行结果的场景。

一、创建podshellPod

下面的代码是一个创建podshellPod的示例,包含初始化、容器状态校验、在pod中执行自定义shell命令、pod手动销毁、最终返回自定义shell的执行结果。

代码示例:

func main() {
result, err := ExecPodShell()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)
}

func ExecPodShell() (result string, err error) {

cluster := "c2f-cluster"
namespace := "jenkins"
podName := "dependency-pod-" + strconv.Itoa(int(time.Now().Unix()))
image := "docker.io/alpine:3.13"
//初始化客户端可以参考总结一里面的初始化方法
client, err := selfk8s.InitClient(cluster)
if err != nil {
return "", tracerr.Wrap(err)
}

pod, err := createNewContainerCmdJobPod(namespace, podName, image, client)
if err != nil {
return "", tracerr.Wrap(err)
}

podBox, err := selfk8s.NewPodBox(cluster)
if err != nil {
return "", tracerr.Wrap(err)
}

//验证pod和容器状态,必须要等到容器状态为Running时才可以执行命令,否则会报错
for i := 0; i < 60; i++ {
pod, err = podBox.Get(pod.Name, namespace)
if err != nil {
return "", tracerr.Wrap(err)
}
if len(pod.Status.ContainerStatuses) == 0 {
time.Sleep(time.Second)
continue
}
status := selfk8s.GetContainerStatus(pod.Status.ContainerStatuses[0])
if status == selfk8s.ContainerRunning {
break
}
time.Sleep(time.Second)
}

command1 := "cd /tmp/k8s_repos && xxx"

command2 := "bbb"

command3 := "cd /tmp/k8s_repos && cat failDetail.json"

//可根据需要,获取命令的执行结果,执行命令方法详见总结一
_, err = podBox.ExecCmd(namespace, pod.Name, pod.Spec.Containers[0].Name, command1)
if err != nil {
return "", tracerr.Wrap(err)
}

_, err = podBox.ExecCmd(namespace, pod.Name, pod.Spec.Containers[0].Name, command2)
if err != nil {
return "", tracerr.Wrap(err)
}

bts, err := podBox.ExecCmd(namespace, pod.Name, pod.Spec.Containers[0].Name, command3)
if err != nil {
return "", tracerr.Wrap(err)
}

//使用完毕后,可以手动删除pod,删除方法详见总结一
if err = podBox.Delete(pod.Name, namespace); err != nil {
return "", tracerr.Wrap(err)
}

return string(bts), nil
}

func createPodShell(ns, podName, image string, client *kubernetes.Clientset) (pod *corev1.Pod, err error) {
var bl bool
bl = true

pod = new(corev1.Pod)
pod.Name = podName
pod.Spec.RestartPolicy = corev1.RestartPolicyNever
//节点选择
pod.Spec.NodeSelector = map[string]string{"devops.k8s.ops.seenew/jenkins": "jnlp"}

pod.Spec.Volumes = []corev1.Volume{
{
Name: "volume-0",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
}

pod.Spec.ImagePullSecrets = []corev1.LocalObjectReference{
{Name: "ram-secret"},
{Name: "ram-secret-vpc"},
}

container := corev1.Container{
Name: "dependency-check",
Image: image,
Env: []corev1.EnvVar{
{
Name: "JENKINS_SECRET",
Value: "62cfe4761765cd1aec5f6aa0f83f51ef232",
},
},
Resources: corev1.ResourceRequirements{
Limits: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("4186Mi"),
},
Requests: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("500m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "volume-0",
MountPath: "/tmp/k8s_repos",
},
},
Command: []string{"nsenter"}, //关键
Args: []string{"-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"}, //关键
SecurityContext: &corev1.SecurityContext{
Privileged: &bl,
},
}
pod.Spec.Containers = []corev1.Container{container}

pod, err = client.CoreV1().Pods(ns).Create(context.TODO(), pod, metav1.CreateOptions{})
if err != nil {
return nil, tracerr.Wrap(err)
}

return pod, nil
}

核心在于创建的容器中需要执行nsenter命令,并添加相关参数,可以保证容器一直处于running状态而不是Terminated状态

Command: []string{"nsenter"},                                         
Args: []string{"-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"},

二、创建nodeshellPod

更进一步,利用pod可以和k8s的node节点共享IP的特性,我们可以创建podshell实现在node节点上执行shell命令的功能,也可以称为nodeshell

func CreateNodeShellPod(client *kubernetes.Clientset, podName, nodeName string) (pod *coreV1.Pod, err error) {
var i int64
i = 0
var bl bool
bl = true

pod = &coreV1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: podName,
Namespace: "kube-system",
},
Spec: coreV1.PodSpec{
RestartPolicy: coreV1.RestartPolicyNever,
TerminationGracePeriodSeconds: &i,
HostPID: true, //关键
HostIPC: true, //关键
HostNetwork: true, //关键
Tolerations: []coreV1.Toleration{
{
Operator: coreV1.TolerationOpExists,
},
},
Containers: []coreV1.Container{
{
Name: "shell",
Image: "docker.io/alpine:3.13",
Command: []string{"nsenter"},
Args: []string{"-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"},
SecurityContext: &coreV1.SecurityContext{
Privileged: &bl,
},
},
},
NodeName: nodeName, //关键
},
}

pod, err = client.CoreV1().Pods("kube-system").Create(context.TODO(), pod, metav1.CreateOptions{})
if err != nil {
return nil, tracerr.Wrap(err)
}

return pod, nil
}

与podshell不同的是,需要在pod配置中开启相关共享配置(HostPID等)、并指定NodeName

举报

相关推荐

0 条评论