OpenShift oc cp File Copy Guide
Use oc cp to copy files and directories between local machine and Pods. Covers tar-based transfer, container selection, large file handling, and comparison
π‘ Quick Answer:
oc cp(same askubectl cp) copies files between your local machine and a Pod using tar over the exec API. Unlikeoc rsync, it works for single files and doesnβt require rsync or tar in the container path β only/bin/tarmust exist.
The Problem
You need to:
- Copy a single file into or out of a running Pod
- Transfer files when
oc rsyncisnβt available or appropriate - Extract crash dumps, config files, or logs quickly
- Work with containers that have minimal tooling
The Solution
Copy from Local to Pod
# Copy a file into a Pod
oc cp ./my-config.yaml my-pod:/etc/app/config.yaml
# Copy a directory into a Pod
oc cp ./configs/ my-pod:/etc/app/configs/
# Copy to a specific container in a multi-container Pod
oc cp ./patch.jar my-pod:/app/lib/patch.jar -c app-container
# Copy to a specific namespace
oc cp ./data.csv my-pod:/tmp/data.csv -n productionCopy from Pod to Local
# Copy a file from Pod to local
oc cp my-pod:/var/log/app/error.log ./error.log
# Copy a directory from Pod
oc cp my-pod:/app/data/ ./pod-data/
# Copy from specific container
oc cp my-pod:/tmp/heapdump.hprof ./heapdump.hprof -c java-app
# Copy with namespace
oc cp production/my-pod:/etc/app/config.yaml ./current-config.yamlPod-to-Pod Copy (via Local)
# No direct Pod-to-Pod copy β use local as intermediate
oc cp source-pod:/data/export.sql /tmp/export.sql
oc cp /tmp/export.sql dest-pod:/docker-entrypoint-initdb.d/import.sql
rm /tmp/export.sqlHandling Large Files
# Copy with retries (wrap in script for reliability)
#!/bin/bash
MAX_RETRIES=3
SRC="my-pod:/data/large-backup.tar.gz"
DST="./large-backup.tar.gz"
for i in $(seq 1 $MAX_RETRIES); do
echo "Attempt $i..."
if oc cp "$SRC" "$DST" 2>/dev/null; then
echo "Success"
# Verify integrity
if tar -tzf "$DST" > /dev/null 2>&1; then
echo "Integrity check passed"
exit 0
fi
fi
echo "Failed, retrying..."
sleep 5
done
echo "ERROR: Copy failed after $MAX_RETRIES attempts"
exit 1Extract Specific Files from Pod
# oc cp copies entire files/directories β for selective extraction:
# Option 1: Copy directory, then filter locally
oc cp my-pod:/var/log/ ./all-logs/
find ./all-logs/ -name "*.log" -mmin -60 # Last hour's logs
# Option 2: Use exec + tar with filtering (advanced)
oc exec my-pod -- tar cf - -C /var/log \
--include='*.log' . | tar xf - -C ./filtered-logs/
# Option 3: Single file via stdout
oc exec my-pod -- cat /etc/app/config.yaml > ./config.yamloc cp vs oc rsync vs oc exec
Feature oc cp oc rsync oc exec + cat/tar
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Single file β
native β οΈ needs filter β
via stdout
Directory β
recursive β
recursive β οΈ manual tar
Incremental β full copy β
delta only β full copy
Watch/live sync β no β
--watch β no
Filtering β no β
--include β
tar patterns
Requires in Pod tar rsync or tar cat/tar
Preserves perms β
yes β
configurable β οΈ depends
Symlink handling β οΈ follows β
configurable β οΈ depends
Progress indicator β no β
--progress β noWhen oc cp Fails (No tar in Container)
# Scratch/distroless container without tar:
# Error: tar: not found
# Workaround 1: Use ephemeral debug container
oc debug my-pod --image=busybox -- \
tar cf - -C /proc/1/root/app/data . > ./backup.tar
# Workaround 2: kubectl exec with base64 (small files only)
oc exec my-pod -- base64 /app/config.yaml | base64 -d > config.yaml
# Workaround 3: Inject ephemeral container with tar
oc debug my-pod --image=busybox:1.36
# Inside: tar cf /tmp/backup.tar /app/data
# Then: oc cp my-pod-debug:/tmp/backup.tar ./backup.tar
# Workaround 4: Mount the PVC in a temporary Pod with tar
cat <<YAML | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
name: pvc-extractor
spec:
containers:
- name: extractor
image: busybox:1.36
command: ["sleep", "3600"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: my-app-data
YAML
# Wait for Pod to start, then copy
oc cp pvc-extractor:/data/ ./pvc-backup/
oc delete pod pvc-extractorGotchas and Edge Cases
# Symlinks: oc cp follows symlinks (copies the target file)
# This can result in larger transfers than expected
# Relative paths in Pod: always use absolute paths
# BAD: oc cp my-pod:app/config.yaml ./config.yaml
# GOOD: oc cp my-pod:/app/config.yaml ./config.yaml
# Directory trailing slash behavior:
# oc cp my-pod:/data ./local/ β creates ./local/data/
# oc cp my-pod:/data/ ./local/ β copies contents into ./local/
# Binary files work fine (tar handles them)
oc cp my-pod:/tmp/core.dump ./core.dumpCommon Issues
βtar: Removing leading β/β from member namesβ
- Cause: Warning from tar stripping absolute paths (harmless)
- Fix: Ignore β files are extracted correctly
βerror: unable to upgrade connectionβ
- Cause: Proxy/route doesnβt support SPDY or WebSocket
- Fix: Use
--retries=3; checkocversion matches cluster
Copy seems to hang (large file)
- Cause: No progress indicator; tar buffers the entire stream
- Fix: Use
oc rsync --progressinstead for large directories
Permission denied writing to container
- Cause: Container runs as non-root; target path owned by root
- Fix: Copy to
/tmpfirst, thenoc execto move with correct perms
βcommand terminated with exit code 2β
- Cause: tar in container canβt read the source file (permissions)
- Fix: Check file permissions inside Pod with
oc exec ls -la
Best Practices
- Use
oc cpfor single files β simpler syntax than rsync - Use
oc rsyncfor directories β incremental, progress, filtering - Always absolute paths in Pod β relative paths cause confusion
- Verify after copy β
oc exec md5sumto confirm integrity /tmpas staging β copy there first if target dir has permission issues- Clean up β donβt leave debug data in production Pods
- Prefer ephemeral containers for containers without tar
Key Takeaways
oc cpuses tar over exec API β requires/bin/tarin the container- Same syntax as
kubectl cp(OpenShift wrapper) - Best for single files;
oc rsyncbetter for directories/incremental - No progress indicator β use rsync for large transfers
- Fallbacks when no tar: ephemeral containers, base64 exec, PVC mount Pod
- Always use absolute paths inside the Pod
- Trailing slash matters:
/datavs/data/changes copy behavior - Binary-safe: works for heap dumps, core files, images, databases

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses β