38

I need to rsync a file tree to a specific pod in a kubernetes cluster. It seems it should be possible if only one can convince rsync that kubectl acts sort of like rsh. Something like:

rsync --rsh='kubectl exec -i podname -- ' -r foo x:/tmp

... except that this runs into problems with x since rsync assumes a hostname is needed:

exec: "x": executable file not found in $PATH

I can not seem to find a method to help rsync construct the rsh command. Is there a way to do this? Or some other method by which relatively efficient file transfer can be achieved over a pipe?

(I am aware of gcloud compute copy-files, but it can only be used onto the node?)

Bittrance
  • 3,210
  • 4
  • 26
  • 28

8 Answers8

71

To rsync to a Pod I use the following helper.

pod=$1;shift;kubectl exec -i $pod -- "$@"

I put this in a file called "rsync-helper.sh" and then run the rsync like so.

rsync -av --progress --stats -e './rsync-helper.sh' source-dir/ thePodName:/tmp/dest-dir

If you'd like a simple script that wraps this all up, save this as krsync.

#!/bin/bash

if [ -z "$KRSYNC_STARTED" ]; then export KRSYNC_STARTED=true exec rsync --blocking-io --rsh "$0" $@ fi

Running as --rsh

namespace='' pod=$1 shift

If user uses pod@namespace, rsync passes args as: {us} -l pod namespace ...

if [ "X$pod" = "X-l" ]; then pod=$1 shift namespace="-n $1" shift fi

exec kubectl $namespace exec -i $pod -- "$@"

Then you can use krsync where you would normally rsync.

krsync -av --progress --stats src-dir/ pod:/dest-dir

You can also set the namespace.

krsync -av --progress --stats src-dir/ pod@namespace:/dest-dir

NOTE: The Pod must have the rsync executable installed for this to work.

David Xia
  • 115
4

The answer from @karl-bunch was perfect. For those who prefer using tar this is how I use it:

tar -cvz -C /orig-dir . | kubectl exec -ti podname -- sh -c 'cd /var/www && tar -xzv'
Uwe Keim
  • 2,490
leumasino
  • 141
  • 2
4

In the end, I wrote a Python script to act as a receiver of tar files. You can do thus:

tar cf - . | kubectl exec shinken -i catcher -v /etc/shinken/custom_configs

Note that this only works if you cluster nodes are kubernetes 1.1 or later.

Bittrance
  • 3,210
  • 4
  • 26
  • 28
2

I ran into the same problem today. I had to sync files from the pod to my local machine.

My solution for this was this rsync command

rsync -aOv --blocking-io --rsync-path="/some/path/on/pod" --rsh="kubectl exec somePod -c someContainer -i -- " rsync:"/some/path/on/pod /some/local/path
Dave M
  • 4,494
Adam H.
  • 21
  • 1
2

If the tar binary is available on the container, you can transfer files using the new cp command.

Though possibly not as efficient as rsync.

rcoup
  • 167
Chris Stryczynski
  • 2,138
  • 3
  • 24
  • 30
2

A one-liner, just edit to you names and paths:

p_user=$USER;p_name=$POD_NAME; rsync -avurP --blocking-io --rsync-path= --rsh="$(which kubectl) exec $p_name -i -- " /home/$USER/target_dir rsync:/home/$p_user/
Nico
  • 121
0

@karl-bunch created a beautiful solution, which we were able to implement as a baseline for our own push / pull mechanisms.

In our case, we wanted to be able to explicitly pass a --context option to the underlying kubectl command so that we weren't relying on the user to select the correct cluster every time they needed to run a sync.

I've augmented the script a little to support an extra argument to ensure our own scripts could pass this information along. Here's where I ended up:

#!/bin/bash
RSH=$0
CTX=$1
RSYNC_ARGS=${@:2}
shift

if [ -z "$KRSYNC_STARTED" ]; then export KRSYNC_STARTED=true exec rsync --blocking-io --rsh="$RSH $CTX" $RSYNC_ARGS fi

Running as --rsh

NS='' POD=$1 shift

If user uses pod@namespace, rsync passes args as: {us} -l pod namespace ...

if [ "X$POD" = "X-l" ]; then POD=$1 shift NS="-n $1" shift fi

exec kubectl --context $CTX $NS exec -i $POD -- "$@"

0

It is not supported, but there is an issue for adding support which you can +1 or even contribute to: https://github.com/kubernetes/kubernetes/issues/18007#issuecomment-164797262

Eric Tune
  • 155
  • 5