6

我需要使用 kubernetes python 客户端将文件从 pod 复制到主机。这将是类似的东西kubectl cp pod:file file

我正在测试来自:https ://github.com/prafull01/Kubernetes-Utilities/blob/master/kubectl_cp_as_python_client.py 的代码。

特别是这段代码:

command_copy = ['tar', 'cf', '-', source_path]
with TemporaryFile() as tar_buffer:
    exec_stream = stream(self.coreClient.connect_get_namespaced_pod_exec, pod_name, name_space,
                         command=command_copy, stderr=True, stdin=True, stdout=True, tty=False,
                         _preload_content=False)
    # Copy file to stream

    try:
        while exec_stream.is_open():
            exec_stream.update(timeout=1)
            if exec_stream.peek_stdout():
                out = exec_stream.read_stdout()
                tar_buffer.write(out.encode('utf-8'))
            if exec_stream.peek_stderr():
                logger.debug("STDERR: %s" % exec_stream.read_stderr())
        exec_stream.close()
        tar_buffer.flush()
        tar_buffer.seek(0)
        with tarfile.open(fileobj=tar_buffer, mode='r:') as tar:
            member = tar.getmember(source_path)
            tar.makefile(member, destination_path)
            return True
    except Exception as e:
        raise manage_kubernetes_exception(e)

我正在使用官方的 Kubernetes Python 库版本 10.0.1 和 Python 3.6.8 稳定

但它不能正常工作:

  • 当我复制小文本文件时它正在工作
  • 但它不适用于其他文件,例如 tar 或 zip 文件。它会复制与原始文件大小相同的损坏文件。

代码中是否有任何错误?你有没有其他方法可以通过使用 kubernetes python 客户端来做到这一点?

一切顺利。

谢谢。

4

2 回答 2

4

我通过使用以下代码做到了:

def stream_copy_from_pod(self, pod_name, name_space, source_path, destination_path):
    """
    Copy file from pod to the host.

    :param pod_name: String. Pod name
    :param name_space: String. Namespace
    :param source_path: String. Pod destination file path
    :param destination_path: Host destination file path
    :return: bool
    """
    command_copy = ['tar', 'cf', '-', source_path]
    with TemporaryFile() as tar_buffer:
        exec_stream = stream(self.coreClient.connect_get_namespaced_pod_exec, pod_name, name_space,
                             command=command_copy, stderr=True, stdin=True, stdout=True, tty=False,
                             _preload_content=False)
        # Copy file to stream
        try:
            reader = WSFileManager(exec_stream)
            while True:
                out, err, closed = reader.read_bytes()
                if out:
                    tar_buffer.write(out)
                elif err:
                    logger.debug("Error copying file {0}".format(err.decode("utf-8", "replace")))
                if closed:
                    break
            exec_stream.close()
            tar_buffer.flush()
            tar_buffer.seek(0)
            with tarfile.open(fileobj=tar_buffer, mode='r:') as tar:
                member = tar.getmember(source_path)
                tar.makefile(member, destination_path)
                return True
        except Exception as e:
            raise manage_kubernetes_exception(e)

使用这个 web socket 文件管理器来阅读它。

class WSFileManager:
"""
WS wrapper to manage read and write bytes in K8s WSClient
"""

def __init__(self, ws_client):
    """

    :param wsclient: Kubernetes WSClient
    """
    self.ws_client = ws_client

def read_bytes(self, timeout=0):
    """
    Read slice of bytes from stream

    :param timeout: read timeout
    :return: stdout, stderr and closed stream flag
    """
    stdout_bytes = None
    stderr_bytes = None

    if self.ws_client.is_open():
        if not self.ws_client.sock.connected:
            self.ws_client._connected = False
        else:
            r, _, _ = select.select(
                (self.ws_client.sock.sock, ), (), (), timeout)
            if r:
                op_code, frame = self.ws_client.sock.recv_data_frame(True)
                if op_code == ABNF.OPCODE_CLOSE:
                    self.ws_client._connected = False
                elif op_code == ABNF.OPCODE_BINARY or op_code == ABNF.OPCODE_TEXT:
                    data = frame.data
                    if len(data) > 1:
                        channel = data[0]
                        data = data[1:]
                        if data:
                            if channel == STDOUT_CHANNEL:
                                stdout_bytes = data
                            elif channel == STDERR_CHANNEL:
                                stderr_bytes = data
    return stdout_bytes, stderr_bytes, not self.ws_client._connected
于 2020-10-15T15:06:13.700 回答
1

你有没有其他方法可以通过使用 kubernetes python 客户端来做到这一点?

如果您只想要 Pod 中的一个文件,那么不要使用tar,而是使用/bin/cat它的额外好处是,您可以直接写入本地文件,而无需处理 tar 文件格式。这种方法的缺点是您将负责设置本地文件的权限以匹配您期望的权限,这tar -xf对您有用。但是,如果您正在复制远程 tar 文件或 zip 文件,则无论如何该限制都不会适用,并且可能会使代码更容易推理

于 2020-01-12T19:49:00.640 回答