CI/CD has become an integral part of any software development workflow. It is hard to imagine a world of software without CI/CD as it is indisputably the backbone of DevOps. From affecting lead times and deployment frequencies to changing failure rates and MTTR, a solid CI/CD can mean success or great failure for any development team.
Therefore, it is critical for us to think about solutions that are easily set up and maintained while providing the flexibility required considering the various CI/CD practices of different development teams. It is here, where GitHub’s GitHub Actions emerge, providing ease in configurability and flexibility.
In fact, contrary to popular belief, and even to what the title of this article may have inferred, GitHub Actions is not a CI/CD tool. It is an automation tool that allows development teams to automate their workflows. It just so happens that CI/CD is a major part of the workflow and hence GitHub Actions is often spoken of in this context considering the benefits it brings to the Ci/CD workflow.
This piece aims to highlight these benefits, and also provide a basic intro into how we can leverage GitHub Actions to build a simple CI/CD pipeline.
GitHub Actions 101
As mentioned above, GitHub Actions is not only a CI/CD tool but rather a workflow automation solution. It can be thought of as snippets of instructions that execute parts of the development workflow when triggered by an event. This event is typically on our GitHub repositories.
These triggering repository events indicate repo activities such as
- pull/merge requests are created/closed
- Cron jobs
- Code merges
- Issues created/closed
Overall there are multiple events that can be considered. The full list of GitHub events can be found here.
Therefore, it can be seen that GitHub actions allow automation in response to an event that occurs in or to your repository. The set of automated actions aims to replicate a developer workflow.
As a result, we can have a collection of actions that are executed in sequential order, as a response to these various events. These actions collectively are known as the GitHub Actions Workflow.
In considering these core concepts it becomes easier to understand how GitHub Workflows can be built for Ci/CD purposes.
A major benefit of building out CI/CD workflows is that we will be operating in the same environment which hosts our repositories. Moreover, considering the flexibility that GitHub actions provide, multiple workflows can be linked with our CI/CD workflow. As a result, multiple workflows and repo actions can be configured within a single tool.
Some of the major components to define are as follows:
- Name - The name of the workflow is the various components in the GitHub Workflow file. These components are as follows: triggers the workflow.
- Job - The functionality that is triggered where one workflow has multiple Jobs running in parallel unless defined otherwise through dependencies built.
- On - The events to acknowledge which.
- Step - The specific sequence of actions to be executed under a job.
- Env - A map of the environment variables available for the various Jobs and Steps defined.
- Runs On - The OS on which the defined workflow should be executed on.
To see a full list of configurations available, check out the GitHub documentation here.
As mentioned in the previous sections, we can define our Ci/CD or any other workflow we wish to automate in a GitHub Workflow. There are two ways that this can be done. The first is through the GitHub console itself and the second is through yml files within our repository under the .github directory.
Set up through GitHub Console
Step 1: Navigate to your repo on GitHub, and select the Actions tab.
Step 2: In the actions tab we can see that there is the option to set up the workflow from scratch by selecting the ‘Set up a workflow yourself’ link, or by leveraging one of the multiple templates provided. It is these templates that make building these workflow simple.
Step 3: By clicking on one of the options, we are sent to the console editor where we can begin building our workflow.
Set up with YAML file
The second method involves creating a workflow file under the .github direcoy of the code repo.
The content of the Workflow file will be similar to what we saw in the first method above.
Building the CI Pipeline
Now that we know how we can set up a Workflow, we can continue to build a basic CI pipeline. In the image below we see a workflow for a complete Workflow to execute the CI task of a Java application using Gradle.
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle name: Basic CI with Gradle on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build-java: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK uses: actions/setup-java@v1 with: java-version: 1.8 - name: Grant permission for gradlew run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build - name: Build and Push Docker Image uses: mr-smithers-excellent/docker-build-push@v4 with: image: syusuf/demo-app registry: docker.io username: $ password: $
Step 1: Firstly we need to define the events that will trigger our workflow. The trigger events will be when code is pushed onto master and a pull request is created for the master branch.
Step 2: We want to continue with defining the jobs to be done, with the individual tasks. For this example, we have a single Job that is to build the Java application.
Step 3: Before we begin to define the steps, we need to configure the OS with the ‘Run On’ parameter. The operating systems available include Ubuntu, Microsoft, and iOS.
Step 4: Now we can define our steps, with the first being the setup of the JDK. In this example specifically, we are using Java 1.8
Step 5: After building the JDK we need to ensure that the right permissions are available for executing the Gradle.
Step 6: We can then build the application using Gradle.
Step 7: Finally we can then push the artifact, and in this example, we build a Docker image to be deployed. As can be seen, the user credentials are received from secrets and not hardcoded into the Workflow file itself. We can hard code it into the Workflow file, but we are trying not to lose our jobs :)
With the multiple integrations available, we can connect our Workflow with external tools, such as an AWS-based stack.
As can be seen, the setting up of the workflow was relatively simple. Of course, depending on your specific use case, the Workflow built may be more complex, but the overall creation process is quite an easy task.
For example, we may want to enable CI observability capabilities in our Ci pipeline. For this, we can leverage Thundra Foresight to help provide more insights into our CI tests. To do so, we simply need to add a new Step to our Workflow job.
What we would be adding is the configuration snippet below:
steps: - uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 - name: Thundra Maven Test Instrumentation uses: thundra-io/thundra-maven-test-action@v1 with: apikey: $ project_id: $ command: mvn clean install
Another perk of Github Actions is that after creating these workflows, they are executed on GitHub servers. Hence all this is managed by GitHub itself and there is no need to set up and maintain our separate Ci/CD infrastructure. This greatly reduces the overall complexity of setting up a CI/CD pipeline.
GitHub Actions is not only a CI/CD tool but rather a developer workflow automation tool. As demonstrated in this piece, GitHub actions is an extremely powerful tool. This is mainly due to the available integrations, simplicity of use, and flexibility provided by the tool.
As a result, GitHub Actions enables developers, teams, and entire organizations to perform the necessary ‘left-shift in their development pipelines, and leverage the integrations to truly strengthen the CI/CD backbone of their DevOps practices. This is because it allows teams and organizations to easily evolve their CI/CD pipeline to accommodate changes in practice and developments in DevOps tools.
For example, Thundra.io which provides CI Observability through their new product, Thundra Foresight, is easily integratable with GitHub actions. Considering that CI observability is a relatively new concept now being pursued, the integration between Thundra Foresight and Actions is a testimony to the flexibility of the GitHub Actions.