0
votes

I have a container running inside Kubernetes cluster (within POD) along side many other containers (in their own PODs) and my container is a common container. Now, I want to pull (copy) the files from other containers to my common container. I investigated for some options and found that kubectl copy can be used. But, for that, I need to include kubectl command line tool inside my common container. I'm not sure if this is right approach. So, I thought of using Java Kubernetes APIs to do the same. Is there equivalent Kubernetes REST API for Kubectl copy command ? I gone through the kubernetes APIs and could not find any such API ..

Thanks

2

2 Answers

4
votes

That's because kubectl cp is implemented via tar, so what is actually happening is kubectl exec $pod -- tar -cf - /the/container/file | tar -xf -, which is what I would expect your Java API would need to do, as well.

However, you may -- depending on your needs -- be able to get away with how I used to do it before kubectl cp arrived: kubectl exec $pod -- /bin/cat /the/container/file > local-file which in your circumstance may be a ton easier since I would expect the API would materialize those bytes as an InputStream, saving you the need to get into the tar-format-parsing business

0
votes

I think you should be able to do this using Fabric8 Kubernetes Java Client. I would divide this into two tasks:

  1. Copy specified file from your container(c1) to your local system
  2. Copy file saved to your local system to your other container (say c2)

Let's say your have a pod running inside Kubernetes with two containers c1 and c2. Let's take this as an example:

apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: c1
    image: nginx:1.19.2
    ports:
    - containerPort: 80  
  - name: c2
    image: alpine:3.12
    command: ["watch", "wget", "-qO-", "localhost"]

Now I want to transfer a file /docker-entrypoint.sh in c1 to /tmp/docker-entrypoint.sh in c2. Fabric8 Kubernetes Client provides fluent DSL to uploading/downloading files from Kubernetes Pods. As @mndanial already pointed out in his answer, copy operation involves encoding/decoding, Fabric8 relies on commons-codec and commons-compress. These are optional dependencies and need to be included in your classpath in order to use copy operations. For maven, it would be adding it to pom.xml like this:

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>${commons-codec.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>${commons-compress.version}</version>
        </dependency>

Copying File from Container c1 to your local system: In order to copy you can use KubernetesClient's fluent DSL to specify which file to copy and where to copy in your local system. Here is example code:

try (KubernetesClient client = new DefaultKubernetesClient()) {
    // Path Where to copy file to local storage
    Path downloadToPath = new File("/home/rohaan/Downloads/docker-entrypoint.sh").toPath();
    // Using Kubernetes Client to copy file from pod
    client.pods()
            .inNamespace("default")             // <- Namespace of pod
            .withName("multi-container-pod")    // <- Name of pod
            .inContainer("c1")                  // <- Container from which file has to be downloaded
            .file("/docker-entrypoint.sh")      // <- Path of file inside pod
            .copy(downloadToPath);              // <- Local path where to copy downloaded file
}

Copying File from your local system to other Container (c2): Now we have to do the opposite of first step, similar to copy() KubernetesClient offers upload() method which allows you to upload file or directories to your target Pod. Here is how you would do it:

try (KubernetesClient client = new DefaultKubernetesClient()) {
    // File which was downloaded in Step 1
    File fileToUpload = new File("/home/rohaan/Downloads/docker-entrypoint.sh");
    client.pods().inNamespace("default")
            .withName("multi-container-pod")
            .inContainer("c2")
            .file("/tmp/docker-entrypoint.sh")  // <- Target location in other container
            .upload(fileToUpload.toPath());     // <- Local path of downloaded file
}

When I executed this, I was able to see my file being copied in desired location:

~ : $ kubectl exec multi-container-pod -c c2 ls /tmp
docker-entrypoint.sh

Fabric8 Kubernetes Client also allows you to read a file as InputStream directly rather than storing it. Here is an example:

try (KubernetesClient client = new DefaultKubernetesClient()) {
    try (InputStream is = client.pods()
            .inNamespace("default")
            .withName("quarkus-84dc4885b-tsck6")
            .inContainer("quarkus")
            .file("/tmp/jobExample.yml").read())  {
        String result = new BufferedReader(new InputStreamReader(is)).lines().collect(Collectors.joining("\n"));
        System.out.println(result);
    }
}