Dokku Deploy from Container Registry with Github Action

Photo by Dominik Lückmann.

After years of working with Jenkins as a build system for your Docker images, VM images, RPM packages, jar files, and so on, Github Actions feels as a breeze of fresh air in desert land. Your free Github plan comes with 2,000 free minutes of execution time, so definitely give it a shot.

This specific post will focus on a particular matter on hand: build and push your application Docker image to Github Packages Container Registry and then deploying the same image to Dokku host.

Dokku is a lightweight, fast, and open source alternative to Heroku, bring your own hardware and have your PaaS ready for action.

All the necessary introductions have been made, so let’s jump to business.


Prerequisites

This post assumes that you’ve done your homework and you have your Dockerfile with your application ready. You can docker build on your machine as well as on the cloud (or somebody else’s machine).

I also assume that you have your Dokku host provisioned, you have root access over ssh to the host machine or you can sudo without a password.

The rest of the guide will cover from there.

Prepare the Github Action Secrets

In your Github repository, you will need to add your credentials to Dokku host. After the image is built and published to the Container Registry, Github Action will ssh to your Dokku host and deploy the newly built image.

In this case add the following secrets:

  • DOKKU_HOST - the hostname of your Dokku host
  • DOKKU_USER - the username to login to your Dokku host
  • DOKKU_PRIVATE_KEY - the private key to acess your Dokku host. Don’t forget to add the public key to your ~/.ssh/authorized_keys file on Dokku host.

Authorize Dokku to work with Container Registry

Your Dokku host needs access to the Github Container Registry to pull down the images on deployment. I rather recommend pre-authorizing Dokku host with the registry instead of doing the authorization every time you deploy. The latter option can leak your Personal Access Token (PAT) to the deployment logs, which would be unfortunate (Github Copilot auto suggests security risk).

Get your Github Personal Access Token and make sure that the token has access to read private packages as shown on the image below:

Personal Access Token Permissions

As you’ve generated the PAT, copy it’s value to the clipboard and execute the following on Dokku host:

sudo -s -u dokku  # Configure authentication for dokku user
 export PAT=<your-access-token-here>  # Space is the beginning of this command is on purpose
echo $PAT | docker login --username your-github-username --password-stdin ghcr.io
exit  # Exit from dokku user

Once executed, you shall observe Login Succeeded in the output.

Install Dokku plugin for Deployment from Registry

Dokku has a plugin for deploying your application from container registry. This essentially helps us eliminate the need to build the application image on Dokku host. Deploy-from-registry Dokku Plugin github repository. These are the short instructions on setup:

dokku plugin:install https://github.com/yurihs/dokku-deploy-from-registry.git deploy-from-registry
dokku deploy-from-registry:set-remote-image-repo testapp ghcr.io/${{ github.repository_owner }}/${{ github.repository }}

Github Action

Github Action definition is another flavor of yaml file. You have to put it in your repository under .github/workflows/ directory. Example file path is .github/workflows/delivery.yml, but get creative and name it whatever you prefer.

name: Deployment

on:
  push:
    branches: [ main ]

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push
        uses: docker/build-push-action@v3
        with:
          context: .
          platforms: linux/amd64
          push: true
          tags: ghcr.io/${{ github.repository_owner }}/${{ github.repository }}:latest,ghcr.io/${{ github.repository_owner }}/${{ github.repository }}:${{ github.sha }}

  deploy:
    needs: docker
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Deploy application
        uses: D3rHase/ssh-command-action@v0.2.1
        with:
          HOST: ${{ secrets.DOKKU_HOST }}
          USER: ${{ secrets.DOKKU_USER }}
          PRIVATE_SSH_KEY: ${{ secrets.DOKKU_PRIVATE_KEY }}
          COMMAND: |
            dokku deploy-from-registry testapp ${{ github.sha }}
            docker tag dokku/testapp:${{ github.sha }} dokku/testapp:latest            

In case you access your dokku host with unprivileged user, add sudo to the beginning of the last three lines of the COMMAND section.

Now, your application will be deployed to your Dokku host every time you push to main branch of your repository.

Thanks for reading, stay active, close your rings, and see you next time.