Deployment with GitHub Actions: Quick Tutorial and 5 Best Practices

What Is GitHub Actions Deployment?

GitHub provides GitHub Actions, a CI/CD (Continuous Integration/Continuous Deployment) platform that automates application deployment. It integrates with your GitHub code repository, allowing you to define workflows in YAML files that execute predefined steps when triggered. These actions can deploy code to various environments including VM servers, cloud infrastructures, and Kubernetes clusters.

GitHub Actions supports continuous deployment (CD), which is the practice of deploying every code change to production, following automated testing. You can use GitHub Actions to ensure that every change to the codebase is automatically built, tested, and deployed without manual intervention, thereby speeding up the software delivery process.

GitHub Actions enables you to set up custom workflows that can be triggered by various events, such as code pushes, pull requests, or scheduled times. Each workflow is defined in a YAML file within the repository, specifying the steps required to build, test, and deploy the application.

Setting up a Continuous Deployment Workflow in GitHub Actions

To set up a CD workflow with GitHub Actions, start by defining a workflow YAML file in your repository. This file will outline the steps to build, test, and deploy your application. 

Note: The following example assumes that you have Kubernetes running on your system. You can run a minimal Kubernetes cluster using minikube.

Suppose you have a Python script called app.py that calls an API to get current gold prices. You can configure the workflow to trigger on specific events, such as pushing code to the main branch:

name: Deploy to Kubernetes

on:
  push:
    branches:
      - main  # Deploy on push to main branch

jobs:
  deploy:
    runs-on: ubuntu-latest

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

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Log in to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker image
        run: |
          docker build --no-cache -t ${{ secrets.DOCKER_USERNAME }}/python-app:latest .
          docker push ${{ secrets.DOCKER_USERNAME }}/python-app:latest

      - name: Set up Kubernetes Kubeconfig with Service Account
        run: |
          echo "${{ secrets.KUBERNETES_CA_CRT }}" > /tmp/ca.crt
          kubectl config set-cluster remote-cluster --server=${{ secrets.KUBERNETES_SERVER_URL }} --certificate-authority=/tmp/ca.crt
          kubectl config set-credentials github-actions-sa --token=${{ secrets.KUBERNETES_SERVICE_ACCOUNT_TOKEN }}
          kubectl config set-context github-actions-context --cluster=remote-cluster --user=github-actions-sa
          kubectl config use-context github-actions-context

      - name: Apply Kubernetes Deployment
        run: |
          kubectl apply -f k8s/deployment.yaml
          
      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/python-app-deployment python-app-container=${{ secrets.DOCKER_USERNAME }}/python-app:latest

In this example, the workflow is triggered by a push to the main branch. It includes separate jobs for building and deploying the application. We use a simple Dockerfile to create an image for our Python code. 

The first step logs into Docker Hub using docker hub username and password from Github secrets. 

This second step builds the image and pushes the built image to Dockerhub. 

Let’s make changes to a file in our repository and initiate Github action: 

git add .
git commit -m "Testing github actions"
git push

Now browse to the Actions page of your github repository, you will see an action is automatically triggered:

Once Actions finish running, you can check deployment on your Kubernetes cluster by using the following command:

kubectl get deployments

The output should look something like this:

Dan Garfield
VP of Open Source, Octopus Deploy
Dan is a seasoned leader in the tech industry with a strong focus on open source initiatives. Currently serving as VP of Open Source at Octopus Deploy, contributing as an Argo maintainer, co-creator of Open GitOps, and leveraging extensive experience as a co-founder of Codefresh, now part of Octopus Deploy.

TIPS FROM THE EXPERT

In my experience, here are tips that can help you make better use of GitHub Actions deployment:

  1. Leverage reusable workflows: Utilize reusable workflows to DRY (Don’t Repeat Yourself) your pipeline configurations. This modular approach allows you to define common steps in one place and reference them across multiple workflows, improving maintainability and consistency.
  2. Dynamic environment creation: Create dynamic environments for feature branches using tools like Terraform or Pulumi in your workflows. This can help in isolating changes and conducting thorough testing before merging to the main branch, ensuring stability in production environments.
  3. Use matrix builds for multi-platform support: Configure matrix builds to test your application across different environments and configurations simultaneously. This ensures that your application works correctly on all intended platforms and reduces the time needed for comprehensive testing.
  4. Monitor workflow execution time: Track the execution time of your workflows to identify bottlenecks and optimize steps that are time-consuming. GitHub Actions provides detailed logs and metrics that can help in analyzing and improving the efficiency of your pipeline.
  5. Utilize composite run steps: Use composite run steps to group multiple commands into a single step in your workflows. This can simplify complex tasks, making your workflow definitions cleaner and easier to understand and manage.

Learn more in our detailed guide to GitHub actions workflow 

Deploying With GitHub Actions: Common Operations

These instructions are adapted from the GitHub documentation.

Triggering Your Deployment

You can use a variety of events to trigger your deployment workflow in GitHub Actions. Common triggers include pull_request, push, and workflow_dispatch.

For example, the following workflow triggers on:

  • A push to the main branch
  • A pull request targeting the main branch
  • Manual triggers
on:
  push:
    branches:
      - main
      - feature/*
  pull_request:
    branches:
      - dev
      - qa 
  workflow_dispatch:

Note: You can use multiple branches for push or pull_request triggers. Using a wildcard such as feature/* will start GitHub action for all branches starting with feature/

Using Environments

Environments in GitHub Actions represent deployment targets such as production, staging, or development. They can be used to enforce rules before a job proceeds, such as requiring approvals or limiting access to secrets.

To use environments, define them in your workflow like this:

jobs:
  deployment:
    runs-on: ubuntu-latest
    environment: staging-area
    steps:
      - name: deploy-to-staging-area
        # ...deployment-specific steps

This setup allows you to monitor and control deployments per environment, enhancing security and process adherence.

Using Concurrency

Concurrency in GitHub Actions ensures that only a single job or workflow with the same concurrency group runs at a time. This is useful for preventing multiple deployments to the same environment simultaneously.

To implement concurrency, add the concurrency key in your workflow:

name: Deployment-to-staging
concurrency: staging
on:
  push:
    branches:
      - feature/webform-F21
jobs:
  deployment:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: deploy-to-staging
        # deployment steps for staging environment

This configuration ensures that if a deployment to the production environment is already in progress, any new deployment will be paused until the current one finishes.

Tracking Deployments Through Apps

Integrating GitHub with communication platforms like Microsoft Teams or Slack can help track deployments. You can receive notifications about deployment statuses and approvals, providing real-time updates to your team.

For example, to set up Slack notifications, you would configure your GitHub repository to send updates through a Slack app:

jobs:
  deployment:
    runs-on: ubuntu-latest
    
    steps:
      - name: Notify Slack
        uses: slackapi/[email protected]
        with:
          channel-id: ${{ secrets.SLACK_CHANNEL_ID }}
          slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
          text: "Deployment started"
          
      - name: Deploy
        run: |
          # Your deployment-specific commands here
          echo "Deploying application..."
          
      - name: Notify Slack on Completion
        uses: slackapi/[email protected]
        with:
          channel-id: ${{ secrets.SLACK_CHANNEL_ID }}
          slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
          text: "Deployment completed"

Best Practices for GitHub Actions Deployment

1. Manage Secrets Securely

Secrets like API keys and passwords must be managed carefully in any deployment environment. GitHub Actions allows you to store and manage secrets through the GitHub repository’s settings. Access to these secrets can be granted on a per-environment basis, ensuring that only specified workflows can access them.

Keeping secrets within GitHub’s encrypted storage means they are not stored in plaintext in code repositories. This reduces the risk of accidental leaks, providing a way to handle sensitive information.

2. Use the Least Privilege Principle

Implementing the principle of least privilege means giving only the minimum access required for a task. In GitHub Actions, you can restrict permissions for workflows, ensuring they only have access to what they need. This reduces the risk of malicious actions if a workflow is compromised.

By limiting permissions and using role-based access controls, you can minimize the potential damage caused by an exploited workflow. This is a step in securing your deployment pipeline.

3. Cache Dependencies

Caching dependencies in GitHub Actions can significantly speed up your build and deployment processes. By using the cache action, you can store dependencies like npm packages or Maven repositories between workflow runs. This reduces setup time and improves efficiency.

Effective caching not only accelerates deployments but also reduces external dependency load times, which can be variable. This leads to more predictable and reliable build times.

4. Parallelize Jobs

Running jobs in parallel is a way to reduce the time it takes for your workflows to complete. GitHub Actions supports parallel job execution, allowing you to break down tasks and run them simultaneously. This can expedite complex pipelines, improving productivity.

When parallelizing jobs, make sure that dependent tasks are correctly sequenced to avoid issues. Proper job management can lead to much faster execution without compromising on task reliability or success rates.

5. Maintain Clean and Readable Workflows

Clean and readable workflows are easier to maintain and debug. Use comments, consistent naming conventions, and well-structured YAML files to make workflows understandable. This practice benefits the original authors and helps team members who need to understand or modify the workflows later.

Having well-documented workflows makes onboarding new team members easier and ensures consistency in deployment processes. Readability and maintainability should be prioritized to facilitate workflow management.

Combine GitHub Actions with Codefresh to Support GitOps and Kubernetes Deployments

GitHub actions is a very powerful platform but it is focused mostly on CI and does not support GitOps and native Kubernetes deployments. Codefresh is created specifically for GitOps and Cloud native applications and includes native support for using GitHub Actions for the CI part of the Software lifecycle.

This means that you can get the best of both worlds by keeping all your CI workflows in GitHub Actions, while using Codefresh for advanced features such as:

  • Application dashboards
  • Git source managements
  • Configuration drift management
  • Kubernetes environment dashboards
  • Topology views

In case you are new to Codefresh – we have made it our mission since 2014 to help teams accelerate their pace of innovation. Codefresh recently released a completely rebuilt GitOps CI/CD toolset. Powered by Argo, Codefresh now combines the best of open source with an enterprise-grade runtime allowing you to fully tap the power of Argo Workflows, Events, CD, and Rollouts. It provides teams with a unified GitOps experience to build, test, deploy, and scale their applications.

Ready to Get Started?

Deploy more and fail less with Codefresh and Argo

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.