Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (2024)

GitHub Action is a CI/CD solution that allows you to create pipeline to automate your software cycle deployment. You can create workflows that can be triggered by many events such as push, pull request, release and create jobs that will be automatically executed when those events are created.

GitHub Container Registry / GHCR is a Docker image repository solution hosted by GitHub. It can be integrated to GitHub so your source code and Dockerfile that you store in GitHub can be easily pushed to GHCR and get pulled to be run on Docker or Kubernetes cluster. Its registry is ghcr.io.

Google Container Registry / GCR is a Docker image repository solution hosted by Google, as part of their Google Cloud Platform / GCP solutions. Because it is part of GCP, it can be easily integrated with Google’s container computing services such as Cloud Run and Google Kubernetes Engine, as well as Google’s own CI/CD tools such as Google Cloud Build and Google Code Source Repositories. It has many hostnames for its registry, such as gcr.io for hosting images in United States (currently, but it can change in the future), asia.gcr.io in Asia, eu.gcr.io for storing images in Europe Union countries, and us.gcr.io for hosting images in US (separate bucket with gcr.io).

This solution may relevant to some use cases in which we want to migrate our container workloads to GCP from our existing container runtime running in Docker or Kubernetes cluster hosted in on-premise or other cloud solution platform using GHCR. By creating automated pipeline in which everytime we build Docker image it will automatically push that image to both repositories (GHCR and GCR) will ease developers since it can be treated as one CI/CD cycle while still maintaining both repositories, without having to manually pull the image and push to another repository everytime we build. It can be treated as initial stage of migration, in which after all images is migrated, we can cut old repository (GHCR) and focusing in GCR.

GCR also allows us to store Docker image without any pull rate limit, meaning we can pull our images as many as we wants. It also can be integrated easily to Google Cloud Run (stateless container computing service) and Google Kubernetes Engine (Google-managed kubernetes solution) to be run as container. Furthermore, we also can create CI/CD pipeline using Google’s own Cloud Build and Build Triggers to automatically build docker image whenever we commit release and push it to GCR. Since Google provides one of the most mature container computation environments, many customers are migrating their containerized workloads to Google, hence GCR is one of the most widely used container registry out there.

This is sample architecture diagram that I created for this case.

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (2)

The whole process is consisted of multiple steps :
1. Create Personal Access Token in your repository so GitHub Action can authenticate to it
2. Create Service Account in Google Cloud with permission to push Docker image to GCR so GitHub Action can authenticate to it
3. Create GitHub Action Pipeline
4. Test the pipeline
5. (Optional) Run published image as container using Google Cloud Run

For this example, I use a very simple NGINX based web app container image provided here https://github.com/dockersamples/linux_tweet_app. I also have forked it to my own repository, https://github.com/ardhnyg/linux_tweet_app/

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (3)

This Docker image should run simple web page in port 80 http. First I try to build it locally in my VM. What I do are :

1. Clone the repository : git clone https://github.com/ardhnyg/linux_tweet_app/
2. Build the docker image : sudo docker build -t linux_tweet_app_demo .
3. Run the container : sudo docker container run -d -p 80:80 linux_tweet_app_demo

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (4)
Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (5)

When we go to web browser typing VM’s public IP Address, this is what we should get

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (6)

After we make sure that our container can run fine, we can proceed to the rest of the steps

  1. Create Personal Access Token in your repository so GitHub Action can authenticate to it

We can do this by going to our GitHub page and go to Settings -> Developer Settings -> Personal access token -> Generate new token

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (7)

Type in your PAT name and its roles. In this example, I create a PAT called ghcrdemo. Since what I want to do is pushing and managing image to repository through GitHub Actions, I included all relevant roles in this PAT (all in repo, workflow, write and delete packages). Remember, least privilege principle is always the best for security when assigning role and privileges to something.

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (8)

Then click Generate Token. You will be presented with newly generated token. Please save this token as you can only see this token once, which is right after the token is created. If you lost the token, you can generate new token out of the same PAT but you have to change all the authentication process to use your new token (which will be troublesome in my opinion).

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (9)

Save the Token in your own notes because this is what we will use for GitHub Action to authenticate to GHCR.

Alternatively, you can create secret repository containing your Token so you can refer to your token through environment to your Secret Repository later in your GitHub Action script. To do this, go to your GitHub Repository containing your build code -> Settings -> Secrets -> Action -> New repository secret. Type in your Repository Secret name and paste your PAT Token inside it. In this example, I create repository secret called “CR_PAT” containing my token. So later, whenever I need to insert my token in my script, I’ll just refer to this secret name (CR_PAT).

Then we go to next step, which is creating Service Account in GCP.

2. Create Service Account in Google Cloud with permission to push Docker image to GCR so GitHub Action can authenticate to it

Now we configure our Google Cloud environments to have an account in which GitHub Action will log in later to execute the publishing jobs. This account is called as Service Account.

Basically, Service Account is an account that we can attach to a service (Google’s or 3rd party services) so these services can do some task towards Google services. In order for these services (or, in our case, GitHub Action) use Service Account, they have to authenticate using a key. After it authenticates, it can do task’s limited by Service Account’s roles.

Based on above definition, we have to create a Service Account, assign it roles so it can publishes to GCR, and create key attached to this Service Account so our GitHub Action can logged in using this Service Account and its key.

We can start by accessing our Google Cloud console (https://console.cloud.google.com). Then in Navigation Menu, go to IAM and Admin -> Service Accounts. In Service Account window, click Create Service Account

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (11)

When we create Service Account, we have to specify its Name, Roles and later, Key. Type in the name. In this example, I am using “demo” as its name

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (12)

Click Create and Continue. In access page, choose the role which contain the least privileges access for publishing image to GCR. In this case, I choose Storage Admin.

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (13)

After the Service Account is created, time to assign it key. Click on the Service account that just created. In my case, my service account is demo-818@xxxxx

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (14)

In Service Account page, click Keys -> Add Key -> Create new Key -> choose JSON as the key type. The Private key will be downloaded to your computer. Open the private key file, and save all of its value.

Alternatively, same like PAT Token, we can create Repository Secret to contain our JSON key that we generate from Service Acount. The JSON key that we generate should looks like this

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (15)

Then, same like PAT, we create repository secret and copy all value of our JSON key file to that secret. In this example, I create a secret with the name of “SERVICE_ACCOUNT_KEY”

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (16)

So now, we have two repository secret :
CR_PAT containing our PAT Token, and SERVICE_ACCOUNT_KEY containing our Service Account Private Key.

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (17)

We will use these keys so our GitHub Action can log in to GHCR and GCR.

3. Create GitHub Action Pipeline

After our secrets are in place, we can start building our GitHub Action Workflow pipeline. We can go to our GitHub Repository -> Actions -> New Workflow

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (18)

In choosing workflow template, choose Manual Workflow so we can create from scratch.

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (19)

In this example, create new workflow called “pipeline_gcr_ghcr.yml”. Below is the script that I use :

name: Publish to GCR and GHCR# create simple trigger based on everytime we make change to this repository
on: [push]
#define jobs
jobs:
Deploy:
runs-on: ubuntu-latest #run this workflow on ubuntu instance
permissions: #make sure we add permission to read and write package
contents: read
packages: write
steps:
- name: Checkout Code
uses: actions/checkout@v1 #checkouts your repo, so this workflow can access it
- name: Log in to GHCR
env:
REGISTRY: ghcr.io #create env called REGISTRY
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }} #parse REGISTRY env value to here. Make sure it is correctly stating ghcr.io
username: ${{ github.actor }} #this will be our github account
password: ${{ secrets.CR_PAT }} #parse the value of repository secret called CR_PAT that we have created earlier
- name: Login to GCR
env:
PROJECT_ID: service-project-ardhan-1 #create env called PROJECT_ID consisted of our actual GCP Project ID
uses: google-github-actions/setup-gcloud@v0.3.0 #checkouts GCR repo, so this workflow can access it
with:
service_account_key: ${{ secrets.SERVICE_ACCOUNT_KEY }} #parse the value of repository secret called SERVICE_ACCOUNT_KEY that we have created earlier
project_id: ${{ env.PROJECT_ID }} #parse the value of env called PROJECT_ID
export_default_credentials: true

- name: Build Docker Image
env:
IMAGE_NAME: linux_tweet_app #create env called IMAGE_NAME consisted of actual name of Docker Image after we build
PROJECT_ID: service-project-ardhan-1
run: docker build -t $IMAGE_NAME:latest . #build the docker image

- name: Configure Docker Client
run: |-
gcloud auth configure-docker --quiet #authenticate to gcr

- name: Push Docker Image to Container Registry GCR
env:
IMAGE_NAME: linux_tweet_app
PROJECT_ID: service-project-ardhan-1
#tag docker image to gcr image format then push to gcr
run: |-
docker tag $IMAGE_NAME:latest gcr.io/$PROJECT_ID/$IMAGE_NAME:latest
docker push gcr.io/$PROJECT_ID/$IMAGE_NAME:latest

- name: Extract metadata (tags, labels) for Docker GHCR
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} #create ghcr image format within as id called meta

- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc #push docker image to ghcr
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

Or you can simply download it from my github : https://github.com/ardhnyg/medium_post_week2_may/blob/main/pipeline_gcr_ghcr.yml

After you finish typing those codes, click on Start Commit -> Commit Changes

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (20)

4. Test the pipeline

Since we create simple trigger (basically any commit that we do in our repository will trigger it), then the act of commiting the action workflow in our repository will also trigger the workflow. But if you want to test it manually, you can do any update to your repository and the workflow should be triggered.

In this example, I want to be simple, so I let the workflow run just by commiting my workflow (triggering the action). We can check any job that is run by our workflow by going to our GitHub Repository -> Actions -> Click on our Workflow name. In my case, since my workflow name is “pipeline_gcr_ghcr”, this is what I see

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (21)

As you can see, the job is successfully executed.

Now if we check to GHCR and GCR, we should see an image called “linux_tweet_app” (since this is the image name that we specify in our workflow code).

To check GHCR, we can go to our GitHub Repository -> Packages -> Click on our Image. We should see one image called “linux_tweet_app”

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (22)

For GCR, we can go to our GCP Console -> Navigation Menu -> Container Registry (under CI/CD section) -> Images. We should see one image also called “linux_tweet_app”

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (23)

To verify that both of this repository is updated at the same time using our workflow, we can click each image and see that the latest version is updated at the same time (in my case it is 12 minutes ago both for GCR and GHCR, by the time this article is written)

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (24)
Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (25)

5. (Optional) Run published image as container using Google Cloud Run

Last part is verifying that our published image can run fine as container. Since now our image is already in GCR, we can test it using Cloud Run. Cloud Run is stateless container computing service that allows you to run container image easily without having to spin off VM instances. Cloud Run will automatically scale out and scale in the required VM instances to host your containers. Moreover, since it is serverless, it also can scale down to 0, meaning you wont be charged for even an instance when Cloud Run is scaling down to 0 because there is no request to your container app.

To do so, we can go to our GCP Console -> Navigation Menu -> Cloud Run (Under Serverless section)

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (26)

In Cloud Run window, click Create Service

In Service creation window, specify the following :
1. Choose Deploy one revision from an existing container image, click on Select and choose linux_tweet_app image that we have pushed
2. In Ingress section, make sure Allow all traffic is checked
3. In Authentication section, select Allow unauthenticated invocations since this is only simple web page and we want anyone can access it without having to be authenticated.
4. Expand Container, Variables & Secrets, Connections, Security section. Under Container tab, type “80” as Container port
5. Click on Create

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (27)
Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (28)

Wait until the service is ready. After it is ready, it will have public URL. Click on the URL to test the web page. In my case, my service URL is https://linux-tweet-app-fga5j2yfaa-uc.a.run.app

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (29)

Click on the URL. You should see the following web page

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (30)

Meaning the container has been successfully deployed.

GitHub Action can automate container image push to multiple repositories, such as Google Container Registry and GitHub Package / Container Registry, thus can streamline CI/CD pipeline that the developers are using while they migrate their container workloads from 3rd party environments to Google.

Automating Docker Image Push to GitHub Packages / GitHub Container Registry (GHCR) and Google… (2024)

References

Top Articles
Latest Posts
Article information

Author: Lakeisha Bayer VM

Last Updated:

Views: 6662

Rating: 4.9 / 5 (69 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Lakeisha Bayer VM

Birthday: 1997-10-17

Address: Suite 835 34136 Adrian Mountains, Floydton, UT 81036

Phone: +3571527672278

Job: Manufacturing Agent

Hobby: Skimboarding, Photography, Roller skating, Knife making, Paintball, Embroidery, Gunsmithing

Introduction: My name is Lakeisha Bayer VM, I am a brainy, kind, enchanting, healthy, lovely, clean, witty person who loves writing and wants to share my knowledge and understanding with you.