GitHub Actions Deployment to Different Environments
contents:
Learn how to deploy to different target environments using GitHub Actions.
Intro
If you are using more than one environment for your project, you may be wondering how to deploy to each of the environments (staging/production) using GitHub Actions (GHA). We will show you a simple setup using self-hosted GHA runners which should get you going in no time.
GitHub Actions Runners
You will need to have one GitHub Runner installed per environment (host machine). This way, you can target a specific runner inside of your workflow to deploy to the runner's host machine.
To learn how to install self-hosted GHA runners, see the official documentation.
Workflow File
Adding Environment Selector
In your workflow file, add a workflow_dispatch
trigger, which will enable you to run this workflow manually (see Fig. 1). Afterwards, you can specify the inputs using the inputs
key.
We specify an environment
input, give it a display name, mark it as required and turn it into a select by including type: choice
.
name: deployment
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment'
required: true
type: choice
options:
- 'TEST'
- 'PROD'
default: 'TEST'
Now we will be able to select whether we wish to deploy to the TEST or PROD environment.
Adding Build & Deployment Steps
Now we can add the build
& deployment
jobs. This is a simplified example building and deploying our project on the same machine using a Makefile to automate the process further.
The file will then look like this:
name: deployment
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment'
required: true
type: choice
options:
- 'UAT'
- 'PROD'
default: 'UAT'
jobs:
build:
runs-on: ${{ vars[format('{0}_RUNNER_LABEL', inputs.environment)] }}
steps:
- uses: actions/checkout@v4
- name: Build Project
run: make build
deploy:
runs-on: ${{ vars[format('{0}_RUNNER_LABEL', inputs.environment)] }}
needs: [ build ]
steps:
- uses: actions/checkout@v4
- name: Start Docker Container
run: make run
Setting Up GHA Variables
Now we store the names of each of our runners (test and production) in GHA Variables so that they can be used in the workflow. We will create 2 variables: TEST_RUNNER_LABEL
and PROD_RUNNER_LABEL
.
To create a new GHA variable, go to your repository > Settings > Security > Secrets and variables > Actions > Variables > New repository variable:
Determining Which Runner to Use
As you can see in our workflow above, we are using the variables we have created to determine which runner should be used. When the workflow dispatches a job, the runner which should pick it up is determined using the runs-on
key.
We can use the format()
expression to determine whether TEST_RUNNER_LABEL
or PROD_RUNNER_LABEL
should be used to fill in the name of the runner to pick up the job. We do this by filling in the value of the selected environment from the inputs (inputs.environment
). The value from the input (TEST
or PROD
) is concatenated with _RUNNER_LABEL
which creates the final name of the GHA variable to load the name of the runner from.
More on GHA expressions can be found here.
Note: It would be safer to store these variables in GHA secrets, however, for some reason, it seems that GHA do not support using secrets for the runs-on
value.
Conclusion
Now you should be able to manually dispatch a workflow and select the target environment/runner to execute it. This is a basic but effective setup, which can be improved for example by using centralized GHA runners which can deploy to a selected host using custom scripts. That way you can have a "fleet" of runners, each of which can deploy to any other host machine in your setup.