Execute command on Kubernetes POD(multiple containers) using Python client library

Take note of this problem that takes two hours to Google the web.

Environment setup

I run on Ubuntu 22.04, so I assume you also run on Linux.

# install Kubernetes Python client library
pip3 install kubernetes

Check Github for how to execute commands in POD.

Main program

First, we load the default configuration and create CoreV1Api which will be used to invoke API.

#!/usr/bin/python3

from kubernetes import config
from kubernetes.client import Configuration
from kubernetes.client.api import core_v1_api
from kubernetes.client.rest import ApiException
from kubernetes.stream import stream

def main():
    # I put my K8s config under /home/cylee/.kube/config
    config.load_kube_config("/home/cylee/.kube/config")
    try:
        c = Configuration().get_default_copy()
    except AttributeError:
        c = Configuration()
        c.assert_hostname = False
    Configuration.set_default(c)
    core_v1 = core_v1_api.CoreV1Api()

Helper function

Second, let's write execute command part. We use 'stream' and 'connect_get_namespaced_pod_exec' to execute commands.

def exec_commands(api_instance, pod_name, namespace_name):
    exec_command = [
        '/bin/sh',
        '-c',
        'echo This to stderr; echo This goes to stdout']
    resp = stream(api_instance.connect_get_namespaced_pod_exec,
                  pod_name,
                  namespace_name,
                  command=exec_command,
                  stderr=True, stdin=False,
                  stdout=True, tty=False)

    while resp.is_open():
        resp.update(timeout=1)
        if resp.peek_stdout():
            print("STDOUT: {}".format(resp.read_stdout()))
        if resp.peek_stderr():
            print("STDERR: {}".format(resp.read_stderr()))

Put invoke statement in the 'main' section.

    exec_commands(core_v1, 'my_pod_name', 'default')

Save it and run your program. You will find error messages like others encounter before.

Handshake status 400 Bad Request

How to fix it

Remember our POD contains multiple containers?

The correct fix way is by adding the extra 'container' parameter to explicitly specify the container name in the stream function call.

    resp = stream(api_instance.connect_get_namespaced_pod_exec,
                  pod_name,
                  namespace_name,
                  command=exec_command,
                  stderr=True, stdin=False,
                  stdout=True, tty=False,
                  container="target_container_name",
                  _preload_content=True)

That's all I have and thanks ctheisingfl for sharing the solution.