Search
Close this search box.

MTVLab: Pioneering DevOps Cloud Training

Advanced CI/CD Pipelines: Mastering GitHub Actions for Seamless Software Delivery

By Rajesh Gheware

In the rapidly evolving landscape of software development, Continuous Integration and Continuous Delivery (CI/CD) stand out as crucial practices that streamline the process from code development to deployment. GitHub Actions, a powerful automation tool integrated into GitHub, has transformed how developers implement CI/CD pipelines, offering seamless software delivery with minimal effort. This article delves into mastering GitHub Actions, self hosted runner to build advanced CI/CD pipelines, ensuring faster, more reliable software releases.

Understanding GitHub Actions

GitHub Actions enables automation of workflows directly in your GitHub repository. You can automate your build, test, and deployment phases by defining workflows in YAML files within your repository. This automation not only saves time but also reduces the potential for human error, making your software delivery process more efficient and reliable.

Key Features of GitHub Actions:

  • Event-driven Workflows: Trigger workflows on specific GitHub events, such as push, pull requests, or issue creation.
  • Jobs and Steps: Organize your workflow into jobs, which can run on different runners, and steps, which are individual tasks within a job.
  • Matrix Builds: Test your code across multiple operating systems and language versions simultaneously.
  • Artifact and Log Storage: Automatically store build artifacts and logs for analysis and debugging.
  • Marketplace Integration: Access thousands of pre-built actions in the GitHub Marketplace to extend your workflows.

Building an Advanced CI/CD Pipeline

To harness the full potential of GitHub Actions for your CI/CD pipeline, follow these advanced practices:

1. Workflow Optimization

Optimize your workflows to reduce execution time and resource consumption. Utilize caching for dependencies and build outputs to speed up jobs. For instance, use the actions/cache action to cache node modules:

- name: Cache node modules
  uses: actions/cache@v2
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

2. Environment-Specific Deployments

Use environment secrets and deployment jobs to manage deployments across different environments (development, staging, production). This ensures that the right configurations and secrets are used for each environment.

deploy:
  needs: build
  runs-on: ubuntu-latest
  environment: production
  steps:
  - name: Deploy to Production
    run: ./deploy-prod.sh
    env:
      AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}

3. Advanced Matrix Builds

Leverage matrix builds to test across multiple environments simultaneously. This is particularly useful for ensuring your application works across different versions of languages and operating systems.

test:
  runs-on: ubuntu-latest
  strategy:
    matrix:
      node-version: [12.x, 14.x, 16.x]
      os: [ubuntu-latest, windows-latest, macos-latest]
  steps:
  - uses: actions/checkout@v2
  - name: Use Node.js ${{ matrix.node-version }} on ${{ matrix.os }}
    uses: actions/setup-node@v1
    with:
      node-version: ${{ matrix.node-version }}

4. Security Integrations

Incorporate security checks into your CI/CD pipeline to detect vulnerabilities early. GitHub Actions can integrate with tools like Snyk, CodeQL, and others to automatically scan your codebase for security issues.

- name: Run Snyk to check for vulnerabilities
  uses: snyk/actions/node@master
  with:
    command: test
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

5. Custom Actions

For tasks specific to your workflow that aren’t covered by existing actions, consider developing custom actions. This allows for reusability and can significantly streamline your workflows.

- name: Run custom action uses: ./.github/actions/my-custom-action

Practical Workflow Example: Building, Packaging, and Deploying an Application on EC2 (Github and Self Hosted runners)

Let’s integrate a practical example to illustrate an advanced GitHub Actions workflow. The following YAML script showcases a comprehensive CI/CD pipeline designed for building, packaging, and deploying a Dockerized application to an AWS EC2 instance.

on:
  workflow_dispatch:

name: App Build, Package and Deploy

env:
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
  DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
  IMAGE_NAME: brainupgrade/nodejsappdocker:latest

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ env.DOCKERHUB_USERNAME }}
          password: ${{ env.DOCKERHUB_PASSWORD }}
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          tags: ${{env.IMAGE_NAME}}
  ec2-deploy:
    needs: [build]
    runs-on: 
      labels: ['Linux','codespaces','self-hosted']
    steps:
    - name: Deploy to EC2
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.AWS_EC2_HOST }}
        username: ec2-user
        key: ${{ secrets.AWS_EC2_SSH_KEY }}
        script: |
          docker pull ${{ env.IMAGE_NAME }}
          docker stop app || true
          docker rm app || true
          docker run -d --name app ${{ env.IMAGE_NAME }}

Workflow Review

This YAML workflow demonstrates an efficient and secure pipeline for software delivery, comprising two main jobs: build and ec2-deploy.

  • Build Job: It starts with checking out the code, then setting up Docker Buildx for building multi-platform images. Following that, it logs into DockerHub (using secrets for username and password) and pushes the built Docker image to DockerHub, tagging it with the IMAGE_NAME environment variable.
  • EC2 Deploy Job: This job depends on the successful completion of the build job. It utilizes a self-hosted runner with specific labels (‘Linux’, ‘codespaces’, ‘self-hosted’) for deployment. See the following section for details. The deployment step involves SSH-ing into an AWS EC2 instance (credentials securely stored as GitHub secrets) and executing a script to pull the Docker image from DockerHub, stop any currently running container named ‘app’, remove it, and finally run a new container from the pulled image.

Self Hosted Runner

The below provided screenshots illustrate the use of GitHub Codespaces to create and configure a self-hosted runner for GitHub Actions. The process involves downloading the runner package, configuring it with a token, and executing a script to start listening for jobs.

Steps to executed on the runner
Launch the codespace and execute the steps

The runner is successfully connected to GitHub, as indicated by its readiness to listen for jobs. See the following image. It depicts the GitHub repository settings page, confirming the successful setup of a self-hosted runner named codespaces-88db72. This runner is listed as idle, indicating it is online and waiting for jobs to execute, and it is configured for a Linux x64 environment within GitHub Codespaces.

When runner is connected to GitHub

The follwoing image shows the successful execution of a GitHub Actions workflow titled “App Build, Package and Deploy #7”. The workflow, triggered manually from the repository’s Actions tab, consists of two jobs: ‘build’ and ‘ec2-deploy’, both completed without errors, as indicated by the green checkmarks next to them.

Key Takeaways

  • Security and Secrets Management: This workflow effectively uses GitHub secrets to manage sensitive information, ensuring the security of DockerHub credentials and SSH keys.
  • Efficient Docker Image Management: The use of Docker’s Buildx and Login actions simplifies the process of building and pushing images to DockerHub, demonstrating an efficient way to handle Docker images in CI/CD pipelines.
  • Deployment Automation: By automating the deployment process to EC2, this pipeline reduces manual intervention and potential human error, showcasing the power of GitHub Actions in automating deployment tasks.

This example embodies the advanced capabilities of GitHub Actions in automating and optimizing CI/CD pipelines for seamless software delivery, aligning perfectly with the strategic insights and innovative problem-solving approaches required for mastering advanced CI/CD practices.

Best Practices for GitHub Actions

  • Modularize Workflows: Break down your workflows into smaller, reusable parts to improve maintainability.
  • Review and Refine: Regularly review your workflows for opportunities to optimize and refine.
  • Security: Keep your secrets secure, use minimal permissions, and regularly audit access and usage.
  • Collaboration: Encourage team members to contribute to workflow definitions to spread knowledge and improve efficiency.

Conclusion

Mastering GitHub Actions for advanced CI/CD pipelines empowers teams to deliver software more efficiently, reliably, and securely. By optimizing workflows, leveraging matrix builds, integrating security checks, and utilizing custom actions, developers can ensure that their CI/CD pipelines are robust and effective. As GitHub Actions continues to evolve, staying informed

Share:

More Posts

Send Us A Message