[Troubleshooting] kubectl cp exit code 255 - exec: \"tar\": executable file not found in $PATH"

发布时间 2023-12-20 14:32:14作者: lubanseven

0. 背景

kubectl cp container 文件到本地 host 报错:

$ kubectl cp test/po-test-pod-0:/tmp ./ -c ctr-test-container
time="2023-12-20T02:17:29Z" level=error msg="exec failed: unable to start container process: exec: \"tar\": executable file not found in $PATH"
command terminated with exit code 255

1. 分析

报错的原因是 kubectl 在拷贝容器文件到本地时,使用 tar 打包 container 的文件,如果容器文件系统没有装 tar 或者 $PATH 系统目录没有指定 tar 包,就会报这样的错。

2. 解决

解决方案有两点:

  • 容器内装 tar
  • host 上拷贝文件

2.1 容器内装 tar

2.1.1 拷贝 tar 到容器

如分析所示,在容器内装 tar 可以解决拷贝报错的问题。容器内装 tar 可以通过 kubectl cp 拷贝本地 tar 工具到容器系统环境目录,从本地拷贝到容器是不需要 tar 工具的。

当然,这种拷贝可能会有问题,有问题的地方是涉及到 OS 系统库的调用就比较复杂。比如执行 tar 包依赖 Linux 系统库 lib.so(示例),而容器内没有 lib.so 这个库,就会在容器内执行 tar 时报错。

2.1.2 image 安装 tar

编容器 image 的时候安装 tar 包,这是比较保险的方式。当然,需要重新编,重新安装容器,比较麻烦。

2.2 host 上拷贝文件

这种做法比较省事,不需要装 tar,不需要编 image ,有点黑科技的意味。在解释这种方式之前先说明下,image 是静态的容器,容器是动态的 image 。理解这句话就知道下面为什么要这么干了。

这里并不打算介绍其中的原理,侧重于解决,直接给出操作步骤:

1) 查看容器所在 host

$ kubectl get pods po-test-pod-0 -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP              NODE                                                   NOMINATED NODE   READINESS GATES
po-test-pod-0       16/16   Running   0          17m   172.21.24.249   worker13.hztt-pz2-10-100-xxx-xx.ocp.hz.nsn-rdnet.net   <none>           <none>

Note: 注意我们想看的是容器所在的 host ,pod 是 kubernetes 的概念,在 Kubernetes/OpenShift 上看容器所在的 host,首先要知道容器在哪个 pod 下。

2)login 到 work13 并切换为 root  用户

$ ssh worker13.hztt-pz2-10-100-xxx-xx.ocp.hz.nsn-rdnet.net
$ sudo su
#

3)获取容器 id

# crictl ps | grep ctr-test-container
cd9b94522939a       image-registry.openshift-image-registry.svc:5000/test/container@sha256:9516f2783c28faa796f44d670ea46d551384bacb16bef102d66d084efcc43094                                   20 minutes ago      Running             ctr-test-container                   0                   7168da119742f       po-test-pod-0

Note: 要查看容器 id,需要看平台用的 cri-o 是什么,有些用 docker,有些用 crio。这里环境用的是 crio,我们可以用 crictl 去看容器的 id。

4)inspect 容器

inspect  容器是为了看容器的文件系统在 host  上的目录,知道了 host  上的目录就能找到要拷贝的容器的文件了:

# crictl inspect 32bfea1ad0f77 | grep io.kubernetes.cri-o.MountPoint
        "io.kubernetes.cri-o.MountPoint": "/var/lib/containers/storage/overlay/37eb5dc59ec82566122bc0a61504afb3b6d092fcd74953362d84d8f8b3ef1262/merged",
# cd /var/lib/containers/storage/overlay/37eb5dc59ec82566122bc0a61504afb3b6d092fcd74953362d84d8f8b3ef1262/merged
# ls
afs  bin  boot  dev  etc  ffs  home  lib  lib64  logs  lost+found  media  mnt  opt  proc  ram  rom  root  rpram  run  sbin  srv  sys  tmp  tmp_repo  usr  var

可以看到,mountPoint 即为本地 host 上 mount 到容器内的文件系统,我们在本地进入容器文件系统可以实现文件的拷贝。