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:
TIPS FROM THE EXPERT
In my experience, here are tips that can help you make better use of GitHub Actions deployment:
- 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.
- 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.
- 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.
- 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.
- 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/slack-github-action@v1.18.0 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/slack-github-action@v1.18.0 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.
Deploy more and fail less with Codefresh and Argo