Github: Github Actions overview and ArgoCD deployment example
Tags: devops, github, tutorial, todayilearned
Published: 2021-05-07 11:32:19

---
title: Github: Github Actions overview and ArgoCD deployment example
published: true
date: 2021-05-07 05:01:37 UTC
tags: devops,github,tutorial,todayilearned
canonical_url: https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/
---

![](https://cdn-images-1.medium.com/max/1024/1*k99_arb0x9B7LI4I5hhCPw.png)

[Github Actions](https://github.com/features/actions) actually is very similar to the [TravisCI](https://rtfm.co.ua/category/ci-cd-ru/travis-ru/), but have much more closer integration with Github, and even its interface is included in the Github WebUI:

![](https://cdn-images-1.medium.com/max/1024/0*4MzGdk3-Rpy1w4TY.png)

So, let’s take a closer look at its abilities, how to use it, and in the following posts will deploy its self-hosted runners to a Kubernetes cluster and will build a CI/CD pipeline to deploy applications using Github Actions and [ArgoCD](https://rtfm.co.ua/tag/argocd/).

- [Github Actions pricing](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Github_Actions_pricing)
- [Github Actions: an overview](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Github_Actions_an_overview)
- [A workflow file structure](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#A_workflow_file_structure)
- [Getting started: Creating workflow file](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Getting_started_Creating_workflow_file)
- [Events](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Events)
- [Manual trigger — workflow\_dispatch](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Manual_trigger_-_workflow_dispatch)
- [Workflow inputs](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Workflow_inputs)
- [Webhooks: create](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Webhooks_create)
- [Environment variables](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Environment_variables)
- [Secrets](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Secrets)
- [Conditions and if](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Conditions_and_if)
- [needs — jobs dependency](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#needs_-_jobs_dependency)
- [Actions](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Actions)
- [An ArgoCD application](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#An_ArgoCD_application)
- [Github Actions workflow for ArgoCD](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/#Github_Actions_workflow_for_ArgoCD)

### Github Actions pricing

Documentation is [here>>>](https://docs.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/about-billing-for-github-actions).

GitHub Actions is free for all account types but with some limitations:

![](https://cdn-images-1.medium.com/max/664/1*xkja8X0wpaLl5FGZaN2-BQ.png)

For example, our project uses GitHub Team, thus we can have 2 gigabytes and 3000 minutes per month.

With this, minutes are different for Linux, macOS, and Windows:

![](https://cdn-images-1.medium.com/max/658/1*_kZLyMrsVKOLMez-7Zw7AA.png)

I.e. from our 3000 total, we can use only 300 minutes if we’re using macOS agents and every additional minute will cost additional money:

![](https://cdn-images-1.medium.com/max/658/1*_sg9ddJgwzfcS2mCGUcN3g.png)

Also, Github Actions can be working in Github Cloud, and as [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners), which can solve an issue with access to your secured resources because Github haven’t static IP ranges, so you’re not able to configure your SecurityGroup/firewalls.

[Github suggests](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#ip-addresses) periodically download a json-file with updated networks (btw, Github Actions is working on [Microsoft Azure](https://rtfm.co.ua/azure-pochemu-nikogda/)), but I’m too lazy to create some additional automation to update the security configuration.

### Github Actions: an overview

In the Actions, build flow is the following (see [Introduction to GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions)):

1. an _event_ (for example, a pull-request or a commit to a repository, see the full list [here>>>](https://docs.github.com/en/actions/reference/events-that-trigger-workflows)) triggers a _workflow_, which contains _jobs_
2. a _job_ contains a list of _steps_, and every step consist of one or more _actions_
3. _actions_ are running on a _runner_, and multiply actions of a workflow can be running simultaneously

The main components are:

- _runner_: a server running on Github Cloud or self-hosted, which will execute a job
- _workflow_: a procedure described in YAML, that includes one or more job, and is triggered by an event
- _jobs_: a set of steps that are running on the same runner. If a workflow has multiple jobs, by default they will be started in parallel, but also can be configured with dependencies from each other
- _steps_: зa task to execute a common command or _actions_. As steps of the same job are running on the same runner, they can share data with each other.
- _actions_: main “execution blocks” — can be a set of already prepared tasks, or run simple commands

#### A workflow file structure

In short, let’s see how a workflow file is built:

- `name`: a workflow name
- `on`: an event(s), that will trigger this workflow
- `jobs`: a list of tasks of this workflow
- `<JOB_NAME>`
- `runs-on`: a runner, which will execute job(s)
- `steps`: tasks in this job to be executed with uses or run
- `uses`: an _action_ to execute
- `run`: a command to execute

#### Getting started: Creating workflow file

Let’s start with a simple file to see how it works.

In your repository root create a directory called `.github/workflows/` - here we will store all workflows, that can be trigger with different events:

```
$ mkdir -p .github/workflows
```

In this directory, create a file for your flow, for example, named as `.github/workflows/actions-test.yaml`:

```
name: actions-test
on: [push]
jobs:
  print-hello:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Hello, world"
```

Save it and push to Github:

```
$ git add .github/workflows/actions-test.yaml && git commit -m “Test flow” && git push
```

Go to the Github WebUI, switch to the Actions tab, you’ll see this workflow execution:

![](https://cdn-images-1.medium.com/max/1024/0*apMBT90-goY1VegN.png)

![](https://cdn-images-1.medium.com/max/665/0*BqAsYfr9wnntUlq3.png)

#### Events

In Events, you can describe conditions to run that flow.

Such a condition can be a pull request or commit to a repository, a schedule, or some event outside of Github that will run a webhook to your repository.

Also, you can configure those conditions for different branches of the repository:

```
name: actions-test
on: 
  push:
    branches:
      - master
  pull_request:
    branches:
      - test-branch
...
```

Or use a cronjob, see the [Scheduled events](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events):

```
name: actions-test
on: 
  schedule:
    - cron: '* * * *'
```

#### Manual trigger — workflow\_dispatch

Also, you can configure an ability to execute a workflow manually by using the [`workflow_dispatch`](https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#workflow_dispatch) in the `on`:

```
name: actions-test
on: 
   workflow_dispatch
jobs:
  print-hello:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Hello, world"
```

And after this, in the Actions you’ll get a button to run that flow:

![](https://cdn-images-1.medium.com/max/1024/0*SHYN_d11qFVgtZBD.png)

#### Workflow inputs

In your workflow, you also can add some [`inputs`](https://docs.github.com/en/actions/learn-github-actions/finding-and-customizing-actions#using-inputs-and-outputs-with-an-action) that will be available as variables in steps via the [`github.event`](https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) context:

```
name: actions-test
on: 
   workflow_dispatch:
     inputs:
       userName:
         description: "Username"
         required: true
         default: "Diablo"
jobs:
  print-hello:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Username: ${{ github.event.inputs.username }}"
      - run: echo "Actor's username: ${{ github.actor }}"
```

Here, in the `${{ github.event.inputs.username }}` we are getting a value of the `workflow_dispatch.inputs.userName`, and in the [`github.actor`](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) receiving the Github Actions metadata :

![](https://cdn-images-1.medium.com/max/1024/0*RYsPLseZZuTzIh-0.png)

![](https://cdn-images-1.medium.com/max/658/0*JHmsEHLpWWcB4U3v.png)

A use case can be, for example, to pass a Docker image tag to deploy with ArgoCD.

#### Webhooks: create

Beside of the push which we've used above we can configure our workflow on any other event in a repository.

See the full list in the [Webhook events](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#webhook-events).

As another example let’s configure our flow to be running when a new branch or tag is created by using the [`create`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#create):

```
name: actions-test
on: 
  create
jobs:
  print-hello:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "Event name: ${{ github.event_name }}"
          echo "Actor's username: ${{ github.actor }}"
```

Here the `${{ github.event_name }}` is used to display the trigger name.

Create a new branch and push it:

```
$ git checkout -b a-new-branch
Switched to a new branch ‘a-new-branch’
$ git push -u origin a-new-branch
```

Check:

![](https://cdn-images-1.medium.com/max/692/0*eU3YJ3-wZBUKQYJ5.png)

#### Environment variables

Also, Github Actions supports environment variables in workflows.

There is a list of the default variables, see the [Default environment variables](https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables), and you can create your own on a workflow level, jobs level, per a job, or per a step.

During this, pay attention that you access variables in different ways, see the [About environment variables](https://docs.github.com/en/actions/reference/environment-variables#about-environment-variables):

- _context variable_  —  `${{ env.VARNAME }}`: a value will be set during a workflow file preprocessing before it will be sent to a runner, use it everywhere excepting the run, for example in the if conditions (will be discussed below)
- _environment variable_  —  `$VARNAME`: a value will set during a task execution from the run on a runner
- to create an own variable during a job’s execution, use a specific file that is set in the default `$GITHUB_ENV` variable

Variables example:

```
name: vars-test

on:
  push

env:
  VAR_NAME: "Global value"

jobs:
  print-vars:
    runs-on: ubuntu-latest
    steps:

      # using own varibales
      - name: "Test global var as $VAR_NAME"
        run: echo "Test value $VAR_NAME"

      - name: "Test global var as ${{ env.VAR_NAME }}"
        run: echo "Test value ${{ env.VAR_NAME }}"

      # using default variables
      - name: "Test job var as $GITHUB_REPOSITORY"
        run: echo "Test value $GITHUB_REPOSITORY"

      # this will be empty, as default variables are not in the context
      - name: "Test job var as ${{ env.GITHUB_REPOSITORY }}"
        run: echo "Test value ${{ env.GITHUB_REPOSITORY }}"

      # using 'dynamic' variables
      - name: "Set local var"
        run: echo "local_var=local value" >> $GITHUB_ENV

      - name: "Print local var as $local_var"
        run: echo "$local_var"

      - name: "Print local var as ${{ env.local_var }}"
        run: echo "${{ env.local_var }}"
```

And result:

![](https://cdn-images-1.medium.com/max/477/0*pdrYenkr-weGnGJB.png)

#### Secrets

Documentation is [here>>>](https://docs.github.com/en/actions/reference/encrypted-secrets).

A secret can be added in a repository _Settings > Secrets_:

![](https://cdn-images-1.medium.com/max/1024/0*yub9_3jCJvok6nNG.png)

![](https://cdn-images-1.medium.com/max/640/0*t9Osmi9g6ElcqeaA.png)

Now, add its use in a workflow. A secret can be cases directly via the `${{ secret.SECRETNAME }}` or can be set to a variable:

```
name: actions-test

on: 
  push

env:
  TEST_ENV: ${{ secrets.TEST_SECRET }}

jobs:
  print-hello:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "Test secret: ${{ secrets.TEST_SECRET }}"
          echo "Test secret: ${{ env.TEST_ENV }}"
```

Run the flow:

![](https://cdn-images-1.medium.com/max/392/0*3nIbhLFDkZ7auBEg.png)

#### Conditions and `if`

Github Actions supports a conditions check for jobs by using the `if` operator followed by an expression, see the [About contexts and expressions](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#about-contexts-and-expressions).

An example:

```
name: actions-test

on:
  push
  
jobs:
  print-hello:
    runs-on: ubuntu-latest
    steps:

      - id: 'zero'
        run: echo "${{ github.actor }}"

      - id: 'one'
        run: echo "Running because of 'github.actor' contains a 'setevoy' string"
        if: "contains(github.actor, 'setevoy')"

      # this will not run
      - id: 'two'
        run: echo "Skipping because of 'github.actor' contains a 'setevoy' string"
        if: "!contains(github.actor, 'setevoy')"

      - id: 'three'
        run: echo "Running because of Step Two was skipped"
        if: steps.two.conclusion == 'skipped'

      - id: 'four'
        run: echo "Running because of commit message was '${{ github.event.commits[0].message }}'"
        if: contains(github.event.commits[0].message, 'if set')

      - id: 'five'
        run: echo "Running because of previous Step was successful and the trigger event was 'push'"
        if: success() && github.event_name == 'push'
```

Here, we are using the [`github context`](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context), the [`contains()`](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#contains) function, `!=` and `&&` [operators](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#operators), and [`steps` context](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#steps-context) to check the condition.

The result will be:

![](https://cdn-images-1.medium.com/max/1024/0*5x0AyQ9RaTzkgbMO.png)

#### needs - jobs dependency

Beside of the `if: success()` in steps, you can add jobs dependency on each other by using the [`needs`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds):

```
name: actions-test

on: 
  push

jobs:

  init:
    runs-on: ubuntu-latest
    steps:
      - run: echo "An init job"

  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "A build job" && exit 1
    needs: 'init'

  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: echo "A deploy job"
    if: always()
    needs: ['init', 'build']
```

Here, in the _build_ job we are waiting for the _init_ job to finish, and in the _deploy_ job waiting for both _init_ and _build_, and by using the `if: always()` we've set to run the _deploy_ job regardless of the result of execution of the dependency jobs:

![](https://cdn-images-1.medium.com/max/1024/0*zxZu91ripN3zqrAx.png)

### Actions

And the last thing to take a look at is the main component of the Github Actions — the Actions.

Actions allows us to use already existing scripts and utilities from the [Github Actions Marketplace](https://github.com/marketplace?type=actions), or Docker images from the Docker Hub.

See the [Finding and customizing actions](https://docs.github.com/en/actions/learn-github-actions/finding-and-customizing-actions).

In the example below, we will use the [actions/checkout@v2](https://github.com/actions/checkout) to clone a repository roo a runner-agent, and [omegion/argocd-app-actions](https://github.com/marketplace/actions/argocd-application-sync-action) to synchronize an ArgoCD application (see the [ArgoCD: an overview, SSL configuration, and an application deploy](https://rtfm.co.ua/en/argocd-an-overview-ssl-configuration-and-an-application-deploy/) post for details).

#### An ArgoCD application

Let’s create a testing application:

![](https://cdn-images-1.medium.com/max/1024/0*UtaZHVRVVe8YjP5y.png)

Update the `argocd-cm` ConfigMap, as by default the _admin_ user have no permissions to use ArgoCD tokens (do not do this on Production!:

```
...
data:
  accounts.admin: apiKey,login
...
```

Log in:

```
$ argocd login dev-1–18.argocd.example.com
Username: admin
Password:
‘admin’ logged in successfully
Context ‘dev-1–18.argocd.example.com’ updated
```

Create a token:

```
$ argocd account generate-token
eyJ***3Pc
```

#### Github Actions workflow for ArgoCD

Add a Secret with this token:

![](https://cdn-images-1.medium.com/max/789/0*xyPSpkl6D80MIFXh.png)

Create a new workflow:

```
name: "ArgoCD sync"
on: "push"
jobs:
  build:
    runs-on: ubuntu-latest
    steps:

      - name: "Clone reposiory"
        uses: actions/checkout@v2
        with:
          repository: "argoproj/argocd-example-apps.git"
          ref: "master"

      - name: "Sync ArgoCD Application"
        uses: omegion/argocd-app-actions@master
        with:
          address: "dev-1-18.argocd.example.com"
          token: ${{ secrets.ARGOCD_TOKEN }}
          appName: "guestbook"
```

Push it to a repository, and check its execution:

![](https://cdn-images-1.medium.com/max/768/0*eRwq_djz4dN25Waf.png)

And the application in ArgoCD now is synchronized:

![](https://cdn-images-1.medium.com/max/1024/0*Qf_sO76SirSKw96D.png)

Done.

_Originally published at_ [_RTFM: Linux, DevOps, and system administration_](https://rtfm.co.ua/en/github-github-actions-overview-and-argocd-deployment-example/)_._

* * *