使用Kubernetes的"client-go"将命令执行到Pod中. [英] Exec command into a Pod using Kubernetes "client-go"

查看:110
本文介绍了使用Kubernetes的"client-go"将命令执行到Pod中.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将命令执行到Pod中,但我不断收到错误unable to upgrade connection: Forbidden

I'm trying to exec a command into a pod, but I keep getting the error unable to upgrade connection: Forbidden

我正在尝试通过执行kubectl proxy来在开发中测试我的代码,该命令可用于所有其他操作,例如创建部署或删除它,但是它不适用于执行命令,我读到我需要pods/exec所以我创建了一个具有类似角色的服务帐户

I'm trying to test my code in development by doing kubectl proxy which works for all other operations such as creating a deployment or deleting it, however it's not working for executing a command, I read that I need pods/exec so I created a service account with such role like

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dev-sa
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-view-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-exec-view-role
rules:
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["get","create"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods-svc-account
  namespace: default
subjects:
- kind: ServiceAccount
  name: dev-sa
roleRef:
  kind: Role
  name: pod-view-role
  apiGroup: rbac.authorization.k8s.io
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods-exec-svc-account
  namespace: default
subjects:
- kind: ServiceAccount
  name: dev-sa
roleRef:
  kind: Role
  name: pod-exec-view-role
  apiGroup: rbac.authorization.k8s.io

然后我检索服务帐户的不记名令牌,并尝试在我的代码中使用它

then I retrieve the bearer token for the service account and try to use it in my code

func getK8sConfig() *rest.Config {
    // creates the in-cluster config
    var config *rest.Config
    fmt.Println(os.Getenv("DEVELOPMENT"))
    if os.Getenv("DEVELOPMENT") != "" {
        //when doing local development, mount k8s api via `kubectl proxy`
        fmt.Println("DEVELOPMENT")
        config = &rest.Config{
            Host:            "http://localhost:8001",
            TLSClientConfig: rest.TLSClientConfig{Insecure: true},
            APIPath:         "/",
            BearerToken:     "eyJhbGciOiJSUzI1NiIsImtpZCI6InFETTJ6R21jMS1NRVpTOER0SnUwdVg1Q05XeDZLV2NKVTdMUnlsZWtUa28ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRldi1zYS10b2tlbi14eGxuaiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJkZXYtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJmZDVhMzRjNy0wZTkwLTQxNTctYmY0Zi02Yjg4MzIwYWIzMDgiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZXYtc2EifQ.woZ6Bmkkw-BMV-_UX0Y-S_Lkb6H9zqKZX2aNhyy7valbYIZfIzrDqJYWV9q2SwCP20jBfdsDS40nDcMnHJPE5jZHkTajAV6eAnoq4EspRqORtLGFnVV-JR-okxtvhhQpsw5MdZacJk36ED6Hg8If5uTOF7VF5r70dP7WYBMFiZ3HSlJBnbu7QoTKFmbJ1MafsTQ2RBA37IJPkqi3OHvPadTux6UdMI8LlY7bLkZkaryYR36kwIzSqsYgsnefmm4eZkZzpCeyS9scm9lPjeyQTyCAhftlxfw8m_fsV0EDhmybZCjgJi4R49leJYkHdpnCSkubj87kJAbGMwvLhMhFFQ",
        }
    } else {
        var err error
        config, err = rest.InClusterConfig()
        if err != nil {
            panic(err.Error())
        }

    }

    return config
}

然后,我尝试运行 OpenShift示例即可执行到广告连播

Then I try to run the OpenShift example to exec into a pod

    // Determine the Namespace referenced by the current context in the
    // kubeconfig file.
    namespace := "default"

    // Get a rest.Config from the kubeconfig file.  This will be passed into all
    // the client objects we create.
    restconfig := getK8sConfig()

    // Create a Kubernetes core/v1 client.
    coreclient, err := corev1client.NewForConfig(restconfig)
    if err != nil {
        panic(err)
    }

    // Create a busybox Pod.  By running `cat`, the Pod will sit and do nothing.
    var zero int64
    pod, err := coreclient.Pods(namespace).Create(&corev1.Pod{
        ObjectMeta: metav1.ObjectMeta{
            Name: "busybox",
        },
        Spec: corev1.PodSpec{
            Containers: []corev1.Container{
                {
                    Name:    "busybox",
                    Image:   "busybox",
                    Command: []string{"cat"},
                    Stdin:   true,
                },
            },
            TerminationGracePeriodSeconds: &zero,
        },
    })
    if err != nil {
        panic(err)
    }

    // Delete the Pod before we exit.
    defer coreclient.Pods(namespace).Delete(pod.Name, &metav1.DeleteOptions{})

    // Wait for the Pod to indicate Ready == True.
    watcher, err := coreclient.Pods(namespace).Watch(
        metav1.SingleObject(pod.ObjectMeta),
    )
    if err != nil {
        panic(err)
    }

    for event := range watcher.ResultChan() {
        switch event.Type {
        case watch.Modified:
            pod = event.Object.(*corev1.Pod)

            // If the Pod contains a status condition Ready == True, stop
            // watching.
            for _, cond := range pod.Status.Conditions {
                if cond.Type == corev1.PodReady &&
                    cond.Status == corev1.ConditionTrue {
                    watcher.Stop()
                }
            }

        default:
            panic("unexpected event type " + event.Type)
        }
    }

    // Prepare the API URL used to execute another process within the Pod.  In
    // this case, we'll run a remote shell.
    req := coreclient.RESTClient().
        Post().
        Namespace(pod.Namespace).
        Resource("pods").
        Name(pod.Name).
        SubResource("exec").
        VersionedParams(&corev1.PodExecOptions{
            Container: pod.Spec.Containers[0].Name,
            Command:   []string{"date"},
            Stdin:     true,
            Stdout:    true,
            Stderr:    true,
            TTY:       true,
        }, scheme.ParameterCodec)

    exec, err := remotecommand.NewSPDYExecutor(restconfig, "POST", req.URL())
    if err != nil {
        panic(err)
    }

    // Connect this process' std{in,out,err} to the remote shell process.
    err = exec.Stream(remotecommand.StreamOptions{
        Stdin:  os.Stdin,
        Stdout: os.Stdout,
        Stderr: os.Stderr,
        Tty:    true,
    })
    if err != nil {
        panic(err)
    }

    fmt.Println("done")

因此,似乎承载令牌已被忽略并且变得僵硬,我正在获得kubectl管理员的特权.

so it seems like the bearer token is getting ignored and isntead I'm getting the privileges of the kubectl admin.

如何强制其余客户端使用提供的承载令牌? 这是将命令执行到Pod中的正确方法吗?

How can I force the rest client to use the provided bearer token? Is this the right way to exec a command into a pod?

推荐答案

您正在获取privileges of the kubectl admin,因为您正在连接 通过kubeproxy公开的localhost端点.这已经授权您 您的管理员凭据.

You are getting the privileges of the kubectl admin because you are connecting through localhost endpoint exposed by kubeproxy. This already authorizes you with your admin credentials.

我已复制了此文件,并提出了以下解决方案:

I have replicated this and I have come up with this solution:

您要做的是直接连接到API服务器. 要检索API地址,请使用以下命令:

What you want to do is to connect directly to the API server. To retrieve API address use this command:

$ kubectl cluster-info

然后用APIserverIP地址替换该localhost地址

...
        config = &rest.Config{
            Host:            "<APIserverIP:port>",
            TLSClientConfig: rest.TLSClientConfig{Insecure: true},

...

您的代码正在创建Pod,因此您还需要添加createdelete权限 到您的Service Account

Your code is creating a pod so you also need to add create and delete permissions to your Service Account

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-view-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create", "delete", "get", "list", "watch"]

让我知道是否有帮助.

这篇关于使用Kubernetes的"client-go"将命令执行到Pod中.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆