push
The push command uploads container images and Helm charts from a bundle to a registry.
Usage
capsailer push --bundle <bundle-or-archive> [--external-registry <host>] [options]
capsailer push --image <image> [--external-registry <host>] [options]
What Gets Pushed Where
--bundle accepts:
- a Capsailer bundle (
.tar.gz, or an unpacked directory) - a plain
docker savearchive (.taror.tar.gz), such as the image tarballs vendors ship. See Pushing a vendor archive
The destination is one of:
| Destination | How to select | Images | Charts |
|---|---|---|---|
| A registry you already have | --external-registry <host[/path]> |
Pushed | Not pushed. Install from the extracted .tgz (unpack) |
The registry from capsailer registry |
--namespace <ns> (default capsailer-registry) |
Pushed through a temporary kubectl port-forward |
Published to ChartMuseum |
Pushing to an external registry needs only the capsailer binary. Pushing to the built-in registry needs kubectl.
Images are uploaded directly with a built-in registry client. No Docker or skopeo is involved.
Credentials come from --username with --password-stdin, or from ~/.docker/config.json (for example after docker login).
Options
| Option | Description |
|---|---|
--bundle |
Path to a Capsailer bundle (file or directory) or a docker save .tar archive |
--namespace |
Kubernetes namespace where the registry is deployed |
--external-registry |
URL of an external registry to push to |
--username |
Username for authentication with the registry. Without it, credentials come from ~/.docker/config.json |
--password |
Password for authentication with the registry. Visible in the process list and shell history; prefer --password-stdin |
--password-stdin |
Read the password from standard input. The CAPSAILER_PASSWORD environment variable is used when neither option is given |
--kubeconfig |
Path to the kubeconfig file |
--plain-http |
Contact the registry over HTTP instead of HTTPS |
--jobs |
Number of images to push in parallel (default 1) |
--skip-tls-verify |
Skip TLS certificate verification when pushing to the registry. TLS is verified by default |
--image |
Push an image from the local Docker daemon (read through the Docker API; the docker command is not needed). The full repository path is kept: nutanix/nai-api:v2 becomes <registry>/nutanix/nai-api:v2 |
--target-prefix |
Repository path placed in front of every pushed image, for example airgap |
--keep-source-registry |
Keep an explicit source registry as a path element (quay.io/foo/bar becomes <registry>/quay.io/foo/bar) |
--dry-run |
Print the source -> destination mapping for --bundle and push nothing. Needs no cluster access when --external-registry is not given |
Examples
# Push all images and charts from a bundle to the registry
capsailer push --bundle capsailer-bundle.tar.gz --namespace my-registry
# Push artifacts from an unpacked bundle directory
capsailer push --bundle ./unpacked-bundle --namespace my-registry
# Push to an external registry
echo "$REGISTRY_PASSWORD" | capsailer push --bundle capsailer-bundle.tar.gz --external-registry artifactory.example.com --username myuser --password-stdin --jobs 4
# Push a single image to the registry
capsailer push --image nginx:latest --namespace my-registry
# Push every image in a vendor docker save archive to an external registry
capsailer push --bundle nai-images.tar --external-registry 10.55.1.16:5000 --username admin --password-stdin < password.txt
# Preview what a vendor archive would be pushed as
capsailer push --bundle nai-images.tar --external-registry 10.55.1.16:5000 --dry-run
Pushing a vendor docker save archive
A tarball created with docker save contains a manifest.json that names each image in its RepoTags list. These are usually short names without a registry:
[
{
"Config": "b5b2b2...json",
"RepoTags": ["nutanix/nai-inference-ui:v2.8.1", "nutanix/nai-api:v2.8.1"],
"Layers": ["layer1.tar", "layer2.tar"]
}
]
Tools built on go-containerregistry (such as crane) cannot push this as it is. A name like nutanix/nai-api does not say which registry to use, so it resolves to Docker Hub or is rejected under strict validation. An archive with more than one image is also rejected outright (tarball must contain only a single image).
When --bundle points to a .tar file with a root manifest.json, capsailer push reads every image in the archive and rewrites each RepoTag to the target registry before pushing:
RepoTag in the archive |
Pushed as (target 10.55.1.16:5000) |
|---|---|
nutanix/nai-api:v2.8.1 |
10.55.1.16:5000/nutanix/nai-api:v2.8.1 |
nginx |
10.55.1.16:5000/library/nginx:latest |
quay.io/foo/bar:1 |
10.55.1.16:5000/foo/bar:1 (or .../quay.io/foo/bar:1 with --keep-source-registry) |
host:5000/x/y:t |
10.55.1.16:5000/x/y:t (or .../host_5000/x/y:t with --keep-source-registry) |
With --target-prefix airgap, every destination gains that path: 10.55.1.16:5000/airgap/nutanix/nai-api:v2.8.1.
Notes:
- An image that has several tags is uploaded once and then tagged under each name.
- Entries without a
RepoTag, and images that were pulled by digest, are skipped with a message because there is no name to push them under. - If two entries would end up at the same destination (for example
quay.io/a/b:1anddocker.io/a/b:1), the second one is skipped. Use--keep-source-registryto keep both. - A failure on one image does not stop the others. The command exits with an error at the end if anything failed.
- Archives compressed with gzip (
.tar.gz) are accepted; they are decompressed to a temporary file during the push. - Chart publishing is skipped, because a
docker savearchive holds images only. - Images inside a Capsailer bundle are pushed the same way, using the
RepoTagsof eachimages/*.tar. Docker Hub official images are pushed withoutlibrary/(nginx:1.25becomes<registry>/nginx:1.25), which is the namecapsailer build --rewrite-image-referenceswrites into chart values. See How image names are mapped. - If two images would end up under the same name,
pushstops before uploading anything and tells you which.--keep-source-registrykeeps them apart.