Week 11

Deployment Strategies

Creating Docker Images

Multi-stage builds

Docker Compose

Container Registries

Deploying to the Cloud

Database Migrations

Practice

Assignment

Backend Track

Shipping the image

Your image now runs your whole backend — but it exists on exactly one machine: yours. Run docker images and there it is, locally. For a teammate or a cloud server to run it, the image needs to be stored somewhere both sides can reach.

Code has GitHub for this. Images have a container registry — and you have been using one all along: every FROM eclipse-temurin and every image: postgres pulled from Docker Hub. The only new thing today is the other direction: pushing your own image up.

Three terms that sound similar but are not:

Image names decode the registry

A full image name tells Docker exactly where the image lives:

ghcr.io / HackYourFuture / shop-api : 1.0
registry  namespace        repository  tag

The parts you can leave out have defaults:

<aside> ⚠️

latest is not automatically the newest version. It is an ordinary tag name that happens to be the default — it points to whatever was last pushed as latest. Never rely on it to mean "most recent".

</aside>

The registries you will meet

<aside> 💭

The commands are identical for every registry. Which registry you talk to is decided by the image name alone — that is why docker tag matters so much.

</aside>

Tagging: one image, many names

docker tag gives an existing image an additional name. Nothing is copied — run docker images afterwards and you will see two names with the same IMAGE ID:

docker tag my-api HackYourFuture/my-api:1.0

A simple versioning strategy that will serve you well:

💬 Question: You fixed a bug and pushed the fix as anna/my-api:1.0 — the same tag as before. A server pulls anna/my-api:1.0 tomorrow. Which version does it get?

Pushing your image

First, create a free account at hub.docker.com (or sign in through Docker Desktop). After that, it is three commands:

docker login                                     # 1. authenticate, once
docker tag my-api <your-username>/my-api:1.0     # 2. name it with your dockerhub username
docker push <your-username>/my-api:1.0           # 3. upload it

Watch the output: Docker uploads the image layer by layer, and prints Layer already exists for layers the registry already knows — for example the JRE base layers that millions of images share. Layers keep paying off: build caching, disk sharing, and now faster uploads.

After a successful upload, verify that your image is available on Docker hub

<aside> ⚠️

docker push my-api:1.0 — without your username in front — fails with an access error. No namespace means Docker Hub's official library, and you are not allowed to push there. The name decides the destination, so tag first.

</aside>

<aside> ❗

A public repository is truly public: anyone on the internet can pull your image, and your compiled JAR is inside it. That is fine for a learning project — but never push an image that contains secrets. No copied password files, no hardcoded credentials: configuration stays in environment variables at runtime, exactly as you set it up in the previous chapters. A secret that was ever pushed inside a layer must be treated as leaked, even if you delete the image afterwards.

</aside>

Pulling: the payoff

On any machine with Docker — a teammate's laptop, a server — your image is now one command away:

docker pull <your-username>/my-api:1.0

You can even skip the pull: docker run downloads the image automatically if it is not on the machine, exactly like the Postgres image in the previous chapter.

Think back to the packaging chapter in the core program: delivery meant the boxes are packaged and on the shelf, ready to pick up. The registry is that shelf. Your application is now delivered — deploying it is the next chapter.

Registries in the real world

The standard flow at companies: the CI pipeline builds the image and pushes it to a private registry, and the servers pull it from there. No developer laptop involved. Next week you automate this exact flow with GitHub Actions.

Deployment platforms consume your app in one of two ways: they pull a ready-made image from a registry, or they build the image for you straight from your Git repository. You will meet the second kind in the next chapter.

Practice

<aside> 🎉

Your application is on the internet as a pullable image — anyone with Docker can run it, without Java, Maven or your source code. That is software delivery at its best.

</aside>

Extra resources


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.