在集群中的特定容器上执行命令。从另一个容器

Posted

技术标签:

【中文标题】在集群中的特定容器上执行命令。从另一个容器【英文标题】:Execute a command on a particular container in cluster. From another container 【发布时间】:2018-05-14 09:08:16 【问题描述】:

在 kubernetes 中,我有一个容器 X。我想运行一个 cronjob,它在容器 X 中执行一个命令。

我有以下想法:

    使用 busybox 容器运行 cronjob,

    在busybox容器中执行一个脚本,它将:

      确定必须执行的 pod 名称,

      运行 curl,类似

       curl https://35.187.120.184/api/v1/namespaces/my_namespace/pods/my_pod_name/exec?command=my_sh_command&container=my_container_name&stdin=true&stdout=true&tty=true
      

      这里的动态值是:

      我的命名空间 my_pod_name my_sh_command my_container_name

我知道我可能应该使用令牌来访问 kubernetes API,但我不知道如何在 curl 中获取/使用该令牌。

是否可以使用curl 和 kubernetes API 来做到这一点?如果是,怎么做?


我想做这件奇怪的事情是有原因的。我有一个已编译的应用程序,可以识别 CLI 命令。我想运行一个特定的 CLI 命令,而无需通过 Web 服务器路由公开 CLI,随后将通过 k8s 服务访问该命令。

【问题讨论】:

【参考方案1】:

您的一般方法(从容器内调用 Kubernetes API 上的 pod/exec 端点)对我来说似乎完全有效。总的来说,我认为需要考虑两个方面:1)如何使用 curl 与 Kubernetes API 进行通信,以及 2)如何在 Pod 中针对 API 进行身份验证。

使用curl 访问 Kubernetes API

一般来说,Kubernetes API 可以通过curl 轻松调用。但是,exec 端点是该规则的一个例外,因为 API 服务器将该端点上的连接升级为 SPDY 连接,curl 不支持这种连接(该主题甚至有一个discussion in the Kubernetes issue tracker)。出于这个原因,我建议使用 kubectl(正如 @sfgroups 已经建议的那样)或使用其中一个客户端 SDK(例如,Go 或 Python 的)。

验证来自 Pod 内的 exec 调用

如果您在 Pod(或任何客户端 SDK,甚至 curl)中使用 kubectl,则需要针对 API 服务器进行身份验证。为此,您的 Pod 需要与 服务帐户 相关联,并且该服务帐户需要被授权调用 /pods/pod/exec 端点。这是如何工作的,很大程度上取决于您的集群配置:

    在许多集群配置中,默认情况下,您的 Pod 可能已经与服务帐户关联(具有足够的授权)。在 Pod 中,您将在 /var/run/secrets/kubernetes.io/serviceaccount 目录中找到凭据。 kubectl 和常见的客户端 SDK 都会自动找到这个目录,允许它们“正常工作”而无需任何额外配置。使用 curl,您需要从该目录中的 token 文件中提取身份验证令牌,并在 Authorization: Bearer <token> 标头中使用它。

    如果您的 Pod 是使用 automountServiceAccountToken: false 属性创建的,则它可能没有收到服务帐户令牌。

    如果您的集群配置为to use RBAC,您的 Pod 可能仍与一个 Service Account 关联,但该帐户可能无权在其他 Pod 中执行命令。要授予访问权限,您可以创建自己的角色来授予所需的权限,然后创建服务帐户和 RoleBinding:

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

    然后,使用 PodSpec 中的 serviceAccountName: cron 属性将您的 cron runner pod 与新创建的服务帐户相关联。

【讨论】:

【参考方案2】:

我认为我们不能使用 curl 命令触发。另一种选择是在 pod 上安装 kubectl 并使用 kubectl exec 命令运行脚本。

./kubectl exec <POD> -- <script>

【讨论】:

以上是关于在集群中的特定容器上执行命令。从另一个容器的主要内容,如果未能解决你的问题,请参考以下文章

Docker容器相关命令

k8s常用命令

docker下容器怎么执行命令?

Docker基本命令

Docker实践:容器内信息获取命令的执行容器的导入和导出

Docker实践:容器内信息获取命令的执行容器的导入和导出