Zia recently started a Spring Boot project where the deliverables are Docker images. Automating the building and storing of images for each of our releases obviously followed as a requirement. With our code already in Bitbucket, we decided on Quay.io for storing our images.
Quay.io integration with Bitbucket
One of the first things we looked at was the integration that Quay.io already has with Bitbucket. However, the list of permissions that Quay.io requests to enable it quickly dissuaded us.
While Quay.io is owned by Red Hat (a reputable company) this feels like more than we’re willing to grant.
Pushing the image from Pipelines
We ended up opting for an approach where Pipelines would be the one building the image and pushing it to Quay.io. This came naturally as we already had Bitbucket Pipelines configured in our repository and running our tests for the sake of continuous integration. (For an introduction to Pipelines, see: https://www.ziaconsulting.com/developer-help/continuous-integration-atlassian-alfresco/). This way, Pipelines will just push the images to Quay.io without giving any of the two systems more access than needed.
Here is what the relevant section of our final bitbucket-pipelines.yml looks like:
image: maven:3.6.3-jdk-11
options:
docker: true
pipelines:
tags:
'*':
- step:
services:
- docker
caches:
- maven
script:
- mvn -B verify
- export LOCAL_IMAGE_NAME="ziaconsuting/my-image:$BITBUCKET_TAG"
- export QUAY_IMAGE_NAME="quay.io/ziadev/my-image:$BITBUCKET_TAG"
- docker build -t $LOCAL_IMAGE_NAME .
- docker login quay.io -u $QUAY_USERNAME -p $QUAY_PASSWORD
- docker tag $LOCAL_IMAGE_NAME $QUAY_IMAGE_NAME
- docker push $QUAY_IMAGE_NAME
Taking it one step at a time
image: maven:3.6.3-jdk-11
This first line decides which image Bitbucket Pipelines uses to run our pipeline steps. As our code runs on Java11, we picked one of the default images with the latest maven version available at the time of this project, and Jdk11 support.
options: docker: true
This is needed to install what is needed in the Pipelines image for it to run Docker commands.
tags:
'*':
In our case, we want to push the image for every commit we tag. For this example, we will just name the tag as the name of the release (e.g. “0.0.1”), but we could have named them with a “release-” prefix, in which case, we would filter on ‘release-*’
services: - docker
This is needed on top of enabling the Docker option for Pipelines to run in an image which has the proper services installed for us to run Docker commands.
caches: - maven
This instructs Pipelines to keep the maven cache. This allows our builds to run faster and save on the Pipelines costs.
- mvn -B verify
This builds our Spring Boot application. It installs the Docker image locally and generates the jar for our application. It also runs our automated tests to ensure everything is right before we package the release.
- export LOCAL_IMAGE_NAME="ziaconsuting/my-image:$BITBUCKET_TAG" - export QUAY_IMAGE_NAME="quay.io/ziadev/my-image:$BITBUCKET_TAG"
We prepare the name for our images, both the local one that this build creates, and the remote one that we’ll push to quay.io. The BITBUCKET_TAG variable is one of the default variables that Bitbucket includes in the Pipelines builds. It gives you the name of a tag when the Pipelines build was triggered by a tag (which is our case here). There are other variables available if you wanted, for example, to base the releases off of commits in a release branch rather than a tag:
https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/
- docker build -t $LOCAL_IMAGE_NAME .
This step builds an image locally with the explicit version number given by the tag. In a way this step is optional as the previous step already installed the image locally with the version number specified in the code. We keep this step to add a little granularity since, even if the code lists the version as 1.2.3, we might want to build a release 1.2.3.1.
- docker login quay.io -u $QUAY_USERNAME -p $QUAY_PASSWORD
We then log in with quay.io. I recommend using a robot account for this, or at least create an encrypted password (which quay.io allows you to do in your account settings) and not using your clear text password here.
Those two variables will be pulled from your Bitbucket repository variables that you can configure in your repository settings.
- docker tag $LOCAL_IMAGE_NAME $QUAY_IMAGE_NAME - docker push $QUAY_IMAGE_NAME
Finally, we tag the image and push it to quay.io
Conclusion
The privacy and security of your code matters, and while quay.io is useful, you might not want to grant it access to delete your Bitbucket repositories that a glitch on their end might trigger. Leveraging Bitbucket Pipelines to push your images achieves the same result without oversharing permissions and with more control over your build process thanks to Pipelines versatility.