←back to thread

726 points psviderski | 9 comments | | HN request time: 2s | source | bottom

I got tired of the push-to-registry/pull-from-registry dance every time I needed to deploy a Docker image.

In certain cases, using a full-fledged external (or even local) registry is annoying overhead. And if you think about it, there's already a form of registry present on any of your Docker-enabled hosts — the Docker's own image storage.

So I built Unregistry [1] that exposes Docker's (containerd) image storage through a standard registry API. It adds a `docker pussh` command that pushes images directly to remote Docker daemons over SSH. It transfers only the missing layers, making it fast and efficient.

  docker pussh myapp:latest user@server
Under the hood, it starts a temporary unregistry container on the remote host, pushes to it through an SSH tunnel, and cleans up when done.

I've built it as a byproduct while working on Uncloud [2], a tool for deploying containers across a network of Docker hosts, and figured it'd be useful as a standalone project.

Would love to hear your thoughts and use cases!

[1]: https://github.com/psviderski/unregistry

[2]: https://github.com/psviderski/uncloud

1. matt_kantor ◴[] No.44319187[source]
Functionality-wise this is a lot like docker-pushmi-pullyu[1] (which I wrote), except docker-pushmi-pullyu is a single relatively-simple shell script, and uses the official registry image[2] rather than a custom server implementation.

@psviderski I'm curious why you implemented your own registry for this, was it just to keep the image as small as possible?

[1]: https://github.com/mkantor/docker-pushmi-pullyu

[2]: https://hub.docker.com/_/registry

replies(3): >>44319559 #>>44320936 #>>44328525 #
2. matt_kantor ◴[] No.44319559[source]
After taking a closer look it seems the main conceptual difference between unregistry/docker-pussh and docker-pushmi-pullyu is that the former runs the temporary registry on the remote host, while the latter runs it locally. Although in both cases this is not something users should typically have to care about.
3. westurner ◴[] No.44320936[source]
Do docker-pussh or docker-pushmi-pullyu verify container image signatures and attestations?

From "About Docker Content Trust (DCT)" https://docs.docker.com/engine/security/trust/ :

  > Image consumers can enable DCT to ensure that images they use were signed. If a consumer enables DCT, they can only pull, run, or build with trusted images. 

  export DOCKER_CONTENT_TRUST=1
cosign > verifying containers > verify attestation: https://docs.sigstore.dev/cosign/verifying/verify/#verify-at...

/? difference between docker content trust dct and cosign: https://www.google.com/search?q=difference+between+docker+co...

replies(1): >>44328629 #
4. matt_kantor ◴[] No.44328525[source]
> I'm curious why you implemented your own registry for this

Answering my own question: I think it's because you want to avoid the `docker pull` side of the equation (when possible) by having the registry's backing storage be the same as the engine's on the remote host.

replies(1): >>44332853 #
5. matt_kantor ◴[] No.44328629[source]
docker-pushmi-pullyu does a vanilla `docker pull`[1] on the remote side, so you should be able to set `DOCKER_CONTENT_TRUST` in the remote environment to get whatever behavior you want (though admittedly I have not tested this).

If there's desire for an option to specify `--disable-content-trust` during push and/or pull I'll happily add it. Please file an issue if this is something you want.

[1]: https://github.com/mkantor/docker-pushmi-pullyu/blob/12d2893...

replies(1): >>44338927 #
6. psviderski ◴[] No.44332853[source]
Exactly, although my main motivation was to reduce the distinction between docker engine and docker registry. To make it possible for a user to push/pull to the docker daemon as if it was a registry, hence a registry wrapper.

This is a prerequisite for what I want to build for uncloud, a clustering solution I’m developing. I want to make it possible to push an image to a cluster (store it right in the docker on one or multiple machines) and then run it on any machine in the cluster (pull from a machine that has the image if missing locally) eliminating a registry middleman.

replies(1): >>44338493 #
7. matt_kantor ◴[] No.44338493{3}[source]
Very cool. As others have said: "push/pull to the docker daemon as if it was a registry" is how docker should always have worked.

This is next level but I can imagine distributing resource usage across the cluster by pulling different layers from different peers concurrently.

8. westurner ◴[] No.44338927{3}[source]
Should it be set in both the local and remote envs?

What does it do if there's no signature?

Do images built and signed with podman and cosign work with docker; are the artifact signatures portable across container CLIs docker, nerdctl, and podman?

replies(1): >>44339020 #
9. westurner ◴[] No.44339020{4}[source]
From nerdctl/docs/cosign.md "Container Image Sign and Verify with cosign tool" https://github.com/containerd/nerdctl/blob/main/docs/cosign.... ; handily answering my own question aloud:

Sign the container image while pushing, verify the signature on fetch/pull:

  # Sign the image with Keyless mode
  $ nerdctl push --sign=cosign devopps/hello-world
  
  # Sign the image and store the signature in the registry
  $ nerdctl push --sign=cosign --cosign-key cosign.key devopps/hello-world

  # Verify the image with Keyless mode
  $ nerdctl pull --verify=cosign --certificate-identity=name@example.com --certificate-oidc-issuer=https://accounts.example.com devopps/hello-world


  # You can not verify the image if it is not signed
  $ nerdctl pull --verify=cosign --cosign-key cosign.pub devopps/hello-world-bad