Github Private Packages Docker Containers
Building on the previous posts of publishing a maven jar then keeping that jar dependencies up to date with dependabot. The next step is to create a spring boot service using the jar, then creating a docker container finally publish that to private docker packages for others to use, and eventually be deployed.
The Docker File
First we need to create a docker file this file is rather straight forward, it just starts with a JAVA base, copies the jar and set’s the end point to run on startup.
|
|
GitHub Workflow
The whole process of building the project and publishing the docker container is going to be run by a GitHub Action, I’m just going to show sections of the workflow of which are of importance. I’m not going to cover target branches and conditional jobs with dependencies on other jobs here that’s a subject for another time.
Environment
The first step to make this all work together is tell the workflow to use the GitHub Register, and the image of the image to be created, here for ease of reference it’s simply set to the repository name. This could be hard coded, however I’d like to use this repository as a template repository so have used an easily accessible workflow variable.
|
|
Build and Upload Maven Jar
This section of the workflow purpose is to build the maven project, then share that jar file with the rest of the workflow. The process of building the jar file and docker image could be done in a single job. However, I like to keep this in a different job so that I can use the same workflow for build and test for all PRs and development branches. Then only on the main branch build the docker image.
|
|
This results in a slightly longer and complicated workflow, however it comes with the benefit that it’s consistent with building the software and only requires one place to update if the build process changes. The second part of this job is to upload the jar to the workflow runner, this allows the building of the jar and docker container to remain isolated and share the file. Therefore we will need to add an additional step to the docker build job in order for this process to work.
Docker Image Build and Publish
The next step and the main reason for this workflow to exist is to take the jar from the previous job, build a docker container and then finally publish this to the private GitHub docker register.
Gather Artifacts
In the building of the jar section of the workflow, I uploaded the jar file to be shared between jobs. This therefore requires this job to go and get that file to be used within the construction of the docker container.
|
|
This step is rather simple, however I’ve added a path variable. This is to ensure that from the root of the repository there is a target folder created and the jar file that’s been downloaded is placed inside that folder. This is because the docker file expects to find the jar file within the target folder, which is convention for maven projects. I’ve kept this convention so that the docker file can be used by developers locally on their machine as well without any configuration or changes required.
Build and Publish
The first step after downloading the jar file for the action service to be turned into a docker container is to log into the the GitHub private container registry, this will use the environment variable declared at the top of the workflow, then the standard github actor, and the default GITHUB_TOKEN which is accessible to the workflow. For this to work the workflow has to be given the correct permissions defined within it with the following contents: read, packages: write, attestations: write and id-token: write.
The next step is to extract all the data required to build a docker container with names, tags and labels. To keep things simple I’m just using the metadata action to do this. This means that the register will use the environment variable, the image name will be the repository name, and the tag will just use the branch name, which for my use case is perfect.
|
|
The final step of this job with the id push is where the docker image is built, using the metadata from the previous step. This step is run with the context of root of the repository as that’s where the DockerFile is located, and told to attempt to push the container, using the tags. This will create a new image within the register with the tag of the branch, if there was an image already tagged with the branch name, then the tag is removed from the previous image.
Clean Up Register
The final step is to clean up the GitHub register. This step isn’t completely needed however it’s good practice and keeps storage costs low. This is because when a new container of the same tag is published, then the previous container is untagged. The untagged container is still using storage, which is something that GitHub will charge you for if you go over the allowances. If you’re deploying regularly then this is easily done.
|
|
The above workflow when run, will check the register for all images that are no longer tagged. Then all these containers will be deleted, this is all drive by the repository name. Therefore I’m assuming here that you’re still using the method explained previously to create your docker container as that image name uses the repository name, which I feel is the best approach as it keeps everything easily referenced and consistent.