# GitHub Action to Publish Docker Images on Harbor

This task is part of the [Custom CI/CD Pipeline](https://blog.wilfredalmeida.com/series/custom-ci-cd-pipeline) for the application [ChaturMail: AI Email Generator](https://play.google.com/store/apps/details?id=com.wilfredalmeida.chaturmail)

The GitHub action does the following tasks:

1. Builds & Pushes Docker Image to Harbor
    
2. Update ArgoCD Config
    

tl;dr following is the complete YAML for the action followed by an explanation

```yaml
name: BuildAndPushImageOnHarborAndUpdateArgoCDConfig

on:
  push:
    branches: [ "master" ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: docker/login-action@v1
      with:
        registry: harbor.example.com
        username: ${{ secrets.HARBOR_USERNAME  }}
        password: ${{ secrets.HARBOR_PASSWORD }}

    - uses: actions/checkout@v3
    - name: BuildAndPushImageOnHarbor
      run: |
        docker build ./ -t harbor.example.com/chaturmail/chaturmail-backend:${{ github.run_number }}
        docker push harbor.example.com/chaturmail/chaturmail-backend:${{ github.run_number }}

    - name: Clone Repository
      run: |
        git clone <argocd-config-repo-url>
    - name: Install yq
      run: |
        sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
        sudo chmod a+x /usr/local/bin/yq
    - name: Update YAML File
      run: |
        yq -i '.spec.template.spec.containers[0].image = "harbor.example.com/chaturmail/chaturmail-backend:${{ github.run_number }}"' 'argocd-configs/chaturmail-pod.yaml'

    - name: Push to Repo
      run: |
        git config --global user.name "${{secrets.USERNAME_GITHUB}}"
        git config --global user.email "${{secrets.EMAIL_GITHUB}}"
        cd argocd-test-configs
        git add .
        git commit -m "Updated by GitHub Actions"
        git push <argocd-config-repo-url> --all
```

## Building and Pushing Docker Image to Harbor

Harbor is self-hosted on a VPS server and is exposed as a registry.

### Logging in to Harbor

Login is done using the docker login action. The registry URI, username, and password need to be provided. Since Harbor is a docker registry the login works the same as for Docker Hub.

```yaml
    - uses: docker/login-action@v1
      with:
        registry: harbor.example.com
        username: ${{ secrets.HARBOR_USERNAME  }}
        password: ${{ secrets.HARBOR_PASSWORD }}
```

### Building & Pushing the Image

Shell commands are executed to update and push.

The image is tagged with the desired string which is of the format  
`<registry-uri>/<harbor-project-name>/<image-tag>:<github.run.number>`

The `github.run_number` is added to keep the tags unique for each image.

Since the action runs on the `master` branch, the directory is specified as `./`

```yaml
    - uses: actions/checkout@v3
    - name: BuildAndPushImageOnHarbor
      run: |
        docker build ./ -t harbor.example.com/chaturmail/chaturmail-backend:${{ github.run_number }}
        docker push harbor.example.com/chaturmail/chaturmail-backend:${{ github.run_number }}
```

## Updating ArgoCD Config

YAML config for ArgoCD to execute is maintained in a GitHub repo. ArgoCD watches the repo. Any changes to the master branch of the config repo trigger a deployment on the server.

The action updates the image name in the YAML config. ArgoCD detects this change and does a deployment using the config file with the new image name.

A shell utility `yq` is used to edit YAML.

```yaml
    - name: Clone Repository
      run: |
        git clone <argocd-config-repo-url>

    - name: Install yq
      run: |
        sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
        sudo chmod a+x /usr/local/bin/yq

    - name: Update YAML File
      run: |
        yq -i '.spec.template.spec.containers[0].image = "harbor.example.com/chaturmail/chaturmail-backend:${{ github.run_number }}"' 'argocd-configs/chaturmail-pod.yaml'
```

## Pushing ArgoCD config changes

Shell commands to login into GitHub, add changes to git staging, commit & push

```yaml
    - name: Push to Repo
      run: |
        git config --global user.name "${{secrets.USERNAME_GITHUB}}"
        git config --global user.email "${{secrets.EMAIL_GITHUB}}"
        cd chaturmail-argocd-configs
        git add .
        git commit -m "Updated by GitHub Actions"
        git push <argocd-config-repo-url> --all
```

That's all. Check out the pipeline [series](https://blog.wilfredalmeida.com/custom-ci-cd-pipeline) of blogs.

Check out [ChaturMail: AI Email Generator](https://play.google.com/store/apps/details?id=com.wilfredalmeida.chaturmail)

*Keep your secrets safe :-)*
