dcp: docker cp made easy

GitHub Actions Latest version MIT licensed

Summary

Containers are great tools that can encapsulate an application and its dependencies, allowing apps to run anywhere in a streamlined way. Some container images contain commands to start a long-lived binary, whereas others may simply contain data that needs to be available in the environment (for example, a Kubernetes cluster). For example, operator-framework bundles and crossplane packages both use container images to store Kubernetes manifests. These manifests are unpacked on-cluster and made available to end users.

One of the downsides of using container images to store data is that they are necessarily opaque. There's no way to quickly tell what's inside the image, although the hash digest is useful in seeing whether the image has changed from a previous version. The options are to use docker cp or something similar using podman or containerd.

Using docker cp by itself can be cumbersome. Say you have a remote image somewhere in a registry. You have to pull the image, create a container from that image, and only then run docker cp <container-id> using an unintuitive syntax for selecting what should be copied to the local filesystem.

dcp is a simple binary that attempts to simplify this workflow. A user can simply say dcp <image-name> and it can extract the contents of that image onto the local filesystem. It can also just print the contents of the image to stdout, and not create any local files.

Installing

Installing from crates.io

If you're a Rust programmer and have Rust installed locally, you can install dcp by simply entering cargo install dcp, which will fetch the latest version from crates.io.

Download compiled binary

The release section has a number of precompiled versions of dcp for different platforms. Currently only Linux and MacOS are pre-built. For MacOS, both arm and x86 targets are provided, and for Linux only x86 is provided. If your system is not supported, building dcp from the source is straightforward.

Build from source

To build from source, ensure that you have the rust toolchain installed locally. This project does not rely on nightly and uses the 1.62-stable toolchain. Clone the repository and run cargo build --release to build a release version of the binary. From there, you can move the binary to a folder on your $PATH to access it easily.

Implementation

Because there wasn't a suitable containerd client implementation in Rust at the time of writing, dcp relies on APIs provided by external docker and podman crates. This limits dcp to working on systems where docker or podman is the container runtime.

By default, dcp will look for an active docker socket to connect to at the standard path. If the docker socket is unavailable, dcp will fallback to the current user's podman socket based on the $XDGRUNTIMEDIR environment variable.

Flags and Examples

By default, dcp will copy content to the current directory .. For example, lets try issuing the following command:

$ dcp tyslaton/sample-catalog:v0.0.4 -c configs

This command will copy the configs directory (specified via the c flag) from the image to the current directory.

For further configuration, lets try:

$ dcp tyslaton/sample-catalog:v0.0.4 -d output -c configs

This command pulls down the requested image, only extracting the configs directory and copying it to the output directory locally (specified via the -d flag).

Another example, for copying only the manifests directory:

$ dcp quay.io/tflannag/bundles:resolveset-v0.0.2 -c manifests

Lastly, we can reference a private registry by providing a username and password (specified via the -u and -p flags).

$ dcp quay.io/tyslaton/sample-catalog-private:latest -u <username> -p <password>

Note: This serves as a convenient way to connect to private registries but is insecure locally as your credentials are saved in your shell's history. If you would like to remain completely secure then login via <container_runtime> login and pull the image locally. dcp will then be able to notice the image locally pulled and process it.

Testing

If you would like to run the test suite, you just need to run the standard cargo command. This will run all relevant unit, integration and documentation tests.

$ cargo test