我需要使用 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
但它无法正常工作:
代码有错误吗?您还有其他方法使用 kubernetes python 客户端来做到这一点吗?
祝一切顺利。
谢谢。
我使用以下代码做到了:
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 e
使用此网络套接字文件管理器来读取它。
from websocket import ABNF
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
您还有其他方法使用 kubernetes python 客户端来做到这一点吗?
如果您只想从 Pod 中获取一个文件,则不要使用
tar
,而是使用 /bin/cat
,这样做的另一个好处是您可以直接写入本地文件,而无需处理 tar 文件格式。这种方法的缺点是,您需要负责设置本地文件的权限以匹配您期望的权限,这正是 tar -xf
为您做的事情。但是,如果您要复制远程 tar 文件或 zip 文件,则该限制无论如何都不会适用,并且可能会使代码更容易推理
这是 ICMP/MTU 和 tar 的一个已知问题。
请参阅 github 上的 issue #60140。
有多种解决方法,其中一些可能不适用于您。
--retries=n
不幸的是,--retries(实际上从离开的地方恢复)并没有与
tar
或 kubectl exec
一起开箱即用,并且必须在代码中实现(对于 python kubernetes 客户端 API)。