Skip to content

Commit and Push Image


Every image you’ve used so far — alpine, the ones you pulled while comparing registries — was built by someone else. This section is where that flips: you’ll take a container you’ve changed, turn it into a real image, and put it somewhere other people (or other machines) can pull it from. Two commands do the whole job: docker container commit and docker image push.

Turning a Container Into an Image

docker container commit takes a container’s current filesystem state and freezes it into a new image layer, stacked on top of the image the container was originally created from.

docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

This is different from everything you’ve done with that container so far. Running, stopping, and restarting a container doesn’t change the image it came from — the container’s writable layer just sits on top, holding whatever changes you’ve made. commit is the command that reaches into that writable layer and bakes it permanently into a new image, complete with a manifest and its own layer history — not a flattened snapshot like container export produced.

Warning

commit only captures the container’s filesystem. It does not capture data sitting in a mounted volume — that data lives outside the container’s writable layer by design, so committing won’t pull it in. It also doesn’t preserve a running process; the image just has a filesystem, not a live program in motion.

Naming an Image So It Knows Where to Go

A registry needs to know two things from an image’s name: who owns it, and where it should be pushed. That information lives in the repository name itself.

For Docker Hub specifically, the format is:

<your-dockerhub-username>/<repository>:<tag>

If you commit or tag an image as just myapp:latest, Docker has no idea it belongs to you — pushing it will fail, because myapp on its own isn’t a namespace anyone owns. You either commit directly with the full name, or rename an existing image with docker image tag:

docker image tag myapp:latest <your-dockerhub-username>/myapp:latest

docker image tag doesn’t copy or duplicate anything — it just adds a second name pointing at the same image ID. You can have as many tags on one image as you like; none of them cost extra space.

Authenticating: docker login

Pushing requires proving you’re allowed to write to that namespace. Before your first push, authenticate once:

docker login

This prompts for your Docker Hub username and password (or an access token, if you’ve set one up — Docker Hub lets you generate tokens instead of using your account password, which is worth doing once you’re pushing regularly, since a token can be revoked without changing your actual password). Once logged in, the credential is cached locally, and you won’t be prompted again until it expires or you explicitly log out.

Pushing: docker image push

docker image push <your-dockerhub-username>/myapp:latest

Push mirrors pull’s mechanics from the last two sections, just in the opposite direction: Docker walks the image’s layers and uploads each one — unless the registry already has a layer with that exact content, in which case it reports Layer already exists and skips the upload entirely. If your image is built on a public base like alpine, those base layers are almost certainly already sitting on Docker Hub’s servers already, so in practice, pushing a small change on top of a common base image usually means only your new layer actually transfers.

Hands-On: Commit, Tag, and Push a Real Image

This exercise pushes to Docker Hub, so you’ll need a free Docker Hub account before starting. Replace <your-dockerhub-username> with your actual username throughout.

Step 1 — Run a container and make a change worth keeping.

docker container run -d --name commit-demo alpine sleep 3600
docker container exec commit-demo sh -c "echo 'built by me' > /greeting.txt"

Step 2 — Commit the container’s current state into a new image.

docker container commit commit-demo <your-dockerhub-username>/greeting-demo:v1

Step 3 — Confirm the image exists locally, with the name Docker Hub expects.

docker image ls <your-dockerhub-username>/greeting-demo

Step 4 — Log in and push.

docker login
docker image push <your-dockerhub-username>/greeting-demo:v1

Watch the output line by line — most layers should say Layer already exists (they’re Alpine’s base layers, already public on Docker Hub), while the layer holding your /greeting.txt change is the one that actually uploads.

Step 5 — Prove it landed, by removing it locally and pulling it back.

docker image rm <your-dockerhub-username>/greeting-demo:v1
docker image pull <your-dockerhub-username>/greeting-demo:v1
docker container run --rm <your-dockerhub-username>/greeting-demo:v1 cat /greeting.txt

That last command should print built by me — confirmation that the image you pulled back down is the same one you built and pushed, not just something with the same name.

Step 6 — Clean up.

docker container stop commit-demo
docker container rm commit-demo
docker image rm <your-dockerhub-username>/greeting-demo:v1

Note

This only removes the image from your local machine — it’s still sitting on Docker Hub. Deleting a repository or tag from Docker Hub itself is done through Hub’s web interface, not the CLI, so if you want it gone entirely, that’s a separate step outside Docker itself.

Common Pitfalls

  • Pushing without the namespace prefix. denied: requested access to the resource is denied almost always means the repository name doesn’t start with your username (or your organization’s name).
  • Committing a container that hasn’t actually changed. If you commit without making any modifications first, you’ll just get a new tag pointing at what’s functionally the original base image — harmless, but not useful.
  • Forgetting you’re still logged in on a shared machine. docker login persists until you explicitly docker logout or the token expires — worth remembering on any machine you don’t fully control.

What’s Next

You can now take a container’s state all the way to a pushed, pullable image — the full loop this section has been building toward. What’s still missing is discipline around how you tag and version those images as they change over time, which is exactly what’s next: Image Version Management.

Last updated on