Back to all posts
DevOps

Automating Workflows with CI/CD and GitHub Actions

By Huzi

What is CI/CD?

CI/CD is a cornerstone of modern DevOps practices. It's a method to frequently deliver apps to customers by introducing automation into the stages of app development.

  • Continuous Integration (CI): This is the practice of developers merging their code changes into a central repository frequently. Each merge triggers an automated build and test sequence. The goal is to detect integration issues early and maintain a stable codebase.
  • Continuous Deployment (CD): This is the practice of automatically deploying every change that passes the CI stage to a production environment. It's the next step after Continuous Delivery, which ensures the code is always in a deployable state but may require a manual trigger for the final push to production.

Introducing GitHub Actions

GitHub Actions is a powerful and flexible CI/CD platform built directly into GitHub. It allows you to automate, customize, and execute your software development workflows right in your repository. You can use it to build, test, and deploy your code, or to automate any other task associated with your project.

Workflows are defined in YAML files within a .github/workflows directory in your repository.

Creating Your First Workflow

Let's create a simple workflow for a Node.js application that runs tests every time code is pushed to the main branch or a pull request is created.

  1. Create the directory: In your project root, create .github/workflows/.
  2. Create the YAML file: Inside that directory, create a file named ci.yml.
# .github/workflows/ci.yml

name: Node.js CI

# Controls when the workflow will run
on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - name: Checkout repository
        uses: actions/checkout@v3

      # Sets up a specific version of Node.js
      - name: Use Node.js 18.x
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
          cache: 'npm' # Caches npm dependencies for faster builds

      # Installs dependencies
      - name: Install dependencies
        run: npm install

      # Runs your tests
      - name: Run tests
        run: npm test

Breaking Down the Workflow File

  • name: The name of your workflow, which will appear in the "Actions" tab of your GitHub repository.
  • on: The event that triggers the workflow. Here, it's a push or pull_request to the main branch.
  • jobs: A workflow is composed of one or more jobs. Our job is named build.
  • runs-on: Specifies the virtual machine environment to run the job on. ubuntu-latest is a common choice.
  • steps: A sequence of tasks to be executed.
    • uses: This keyword specifies an "action" to run. Actions are reusable units of code. actions/checkout@v3 and actions/setup-node@v3 are popular, official actions.
    • run: This keyword executes command-line commands.

Continuous Deployment Example

Let's extend our workflow to deploy our application to a server after the tests pass. This example assumes you're deploying to a server via SSH.

Important: You must first add your server's credentials (HOST, USERNAME, SSH_PRIVATE_KEY) as "Secrets" in your GitHub repository settings (Settings > Secrets and variables > Actions). Never hardcode secrets in your workflow files.

Add a new job called deploy to your ci.yml file:

# ... (keep the build job as is)

  deploy:
    # This job depends on the 'build' job to succeed
    needs: build
    runs-on: ubuntu-latest
    
    # Only run this job on a push to the main branch, not on pull requests
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Deploy to server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /path/to/your/app
            git pull
            npm install --production
            pm2 restart your-app-name
  • needs: build: Ensures the deploy job only runs if the build job completes successfully.
  • if: A conditional to ensure deployment only happens on a direct push to main.
  • appleboy/ssh-action: A popular marketplace action for executing commands on a remote server over SSH.
  • script: The set of commands to run on your server to pull the latest code and restart the application.

Conclusion

GitHub Actions provides a powerful, integrated way to implement CI/CD pipelines. By automating your build, test, and deployment processes, you can ship features faster, reduce manual errors, and improve the overall quality of your software. Start with a simple testing workflow and gradually add more automation to streamline your development lifecycle.


You Might Also Like


Related Posts