In this article I want to give a step-by-step guide for using Github Actions and Github packages to build a Docker container. I started in the industry as a software engineer just before docker containers and CI/CD formed into a standard in the industry. I've had the fortune of learning these technologies while it was being adopted at large.
Docker is a tool that lets you take your code, package it up into an image and deploy that as a runtime (called containers) into different environments in isolation.
In 2025 CI/CD is a big deal, it stands for Continuous Integration and Continuous Deployment. There are a number of tools that you can use to accomplish the same goal for CI/CD, professionally I've used Bitbucket pipelines, CircleCI, Github Actions, and Jenkins. And I know of others like deployment pipeline services in cloud providers like AWS, Azure, and GCP, a few I haven't used, Travis CI, Gitlab CI/CD. I'm sure the list goes on.
Github Packages is a service provided by Github for your packages, in our case we will be placing our Docker images there.
I've become very familiar with Github Actions and Github packages because I like to have my personal projects saved in Github so people can see the code. When a repository is public, these services come as free in Github (at least until you need more resources, they charge for bigger cpu and ram on your build workflows). This makes it very accessible, in this article we will be building a Docker container with Github Actions and pushing it to Github Packages. Let's get into it!
Pre-requisites
You'll need understanding of Docker and Github, I won't be covering how to use either of them in depth in this article.
In order to follow along you'll also need a Github repository with something meaningful in it, in my case I actually will be using this websites github repo, which is a sveltekit app. Just a plug, for sveltekit, it's awesome and easy to get started with, you should try it.
So, once you've created or found a Github repository with some code you'd like to build a docker container for, open it in your local environment and move on to the steps below.
Create a Dockerfile
First step is to create the Dockerfile, simply place this in the root of the repository and make a commit. Here's what mine looks like:
The contents of this are not really all that important for this article, one day I'll write more about how to build these decent containers but here is a guide from Docker if you want to learn. You just need to make sure this container successfully builds.
Now that we have that we can create our Github Actions workflow.
Create a Workflow
With a Dockerfile in the root of the repository, we can build a Github Actions workflow that creates an image from the Dockerfile and pushes it to Github Packages. The result will be that you can see it on the code home page for the repository it's pushed to.
Create a file in the root of the repository at .github/workflows/docker-build.yaml. After we add the file below, this will cause Github Actions to start a workflow for building the container.
Here's the finished file, below it I will step through it section at a time:
The file above generally works, I've passed this workflow file around to a few different repositories. Let me explain what is going on here before you commit and try to build the Dockerfile for the first time.
The first section below gives the workflow a name and defines a few patterns for when conditions for when the workflow will run. In this case, I want to only build and push when committing to main.
Here's the next section:
This defines a few important things, we see that there is a build job, that the build job runs on ubuntu (the runs-on property defines the OS Github Actions uses for the process). You also have permissions and here is where the workflow receives permission to push the built image to Github Packages.
Following this are the commands that create the Docker build, first we clone the repository Github Actions is being run from:
Next is something I like to do with my images, but you can choose a convention that makes sense to you. Your image needs a unique identifier, so I like to use the Git commit SHA so it is tied to the Github repository as a point of reference. I actually don't think I've ever directly referenced a Git commit from the container, but I have taken the commit and referenced it for deployments.
Here it is:
Following that, log in to the Github Packages as a registry to push to:
In the step above, we are using the permissions set for packages at the top of the file that I mentioned in a previous step.
The last section of the code we need is the part that builds the image and pushes it to Github Packages registry we logged into above:
In this step we set up the docker build so we can build a multi-architecture build. I generally always build for both amd64 and arm64, so it's easy to pull on my macbook using Apple silicon, although when it comes time to deploy most providers will use amd64 for the runtime architecture, so they both are necessary for quality of life. Then we tag the container using the repository name and commit sha we created in a previous step.
Conclusion
Now make a commit with both your Dockerfile and the workflow file and you should see Github Actions start a workflow on the Actions tab of your Github repository. This will push the Docker image to Github Packages, you can find the full path to use the Docker image on the home page of your repository. Happy coding!
P.S. - There's a part two
If you're interested in seeing how we can take this docker image and deploy it into a Kubernetes cluster, read Kubernetes Deployments with Github Actions. I reference the workflow in this article, directly using the docker image we just deployed.