Blog
Creating Centralized Workflows for CI/CD with GitHub Actions

In this final installment of our blog series on migrating from Jenkins to GitHub Actions, we’ll explore how to set up a centralized CI/CD workflow that runs on our customized self-hosted runners. This centralized approach simplifies the management of multiple repositories by triggering workflows from a central location.

Prerequisites

Before implementing the centralized CI/CD workflow, ensure the following are in place:

  1. Self-hosted GitHub Actions Runners: These runners must be configured in your Kubernetes cluster to execute the workflows. You can follow GitHub’s documentation on sharing runners across your organization.
  2. Repository Permissions: Both the triggering and centralized repositories need appropriate access to each other to run workflows. Ensure you have configured repository permissions correctly, and shared workflows can inherit necessary secrets. Learn more here.
  3. Helm and Docker: Ensure Docker is installed and running on your runner and Helm is set up for managing deployments to Kubernetes.
  4. Secrets Setup: You need to configure the secrets required for Docker authentication (such as Docker credentials) and any necessary environment-specific secrets, which will be shared between the workflows. For guidance on sharing secrets, refer to GitHub’s documentation on workflow secrets.

Reference Documentation

Trigger Workflow

The trigger workflow is defined in the main repository, and it uses the workflow_call event to call the centralized workflow from another repository. Here’s how it works:


name: Trigger Build and Deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:
    inputs:
      repo-name:
        description: 'Repository name to build and deploy'
        required: true
        type: string
      branch:
        description: 'Branch to deploy from'
        required: true
        type: string
        default: 'main'
      environment:
        description: 'Environment for deployment'
        required: true
        type: string
        default: 'dev'

jobs:
  call-workflow:
    uses: your-org/central-repo/.github/workflows/centralized-workflow.yml@main
    with:
      repo-name: ${{ inputs.repo-name }}
      branch: ${{ inputs.branch }}
      environment: ${{ inputs.environment }}
    secrets: inherit

Explanation of Steps:

  • Trigger: This workflow is triggered on a push to the main branch or via manual dispatch (with the workflow_dispatch event), allowing you to choose custom inputs such as the repository name, branch, and environment.
  • Job Execution: It calls the centralized-workflow.yml in a different repository using the uses keyword. This passes inputs and secrets from the triggering workflow to the centralized one.

Centralized Workflow

The centralized workflow is stored in a separate repository, defining reusable CI/CD steps such as building the code, creating a Docker image, and deploying it using Helm.


name: Centralized Build and Deploy

on:
  workflow_call:
    inputs:
      repo-name:
        description: 'Repository name to build'
        required: true
        type: string
      branch:
        description: 'Branch for deployment'
        required: true
        type: string
        default: 'main'
      environment:
        description: 'Deployment environment'
        required: true
        type: string
        default: 'dev'

jobs:
  build:
    runs-on: self-hosted-runner
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        with:
          repository: your-org/${{ inputs.repo-name }}
          ref: ${{ inputs.branch }}

      - name: Build project
        run: |
          ./gradlew build

      - name: Push Docker image
        run: |
          docker build -t gcr.io/your-project/${{ inputs.repo-name }}:latest .
          docker push gcr.io/your-project/${{ inputs.repo-name }}:latest

  deploy:
    runs-on: helm-runner
    needs: build
    steps:
      - name: Deploy using Helm
        run: |
          helm upgrade --install ${{ inputs.repo-name }} helm-chart/ \
            --namespace ${{ inputs.environment }} \
            --set image=gcr.io/your-project/${{ inputs.repo-name }}:latest

Explanation of Steps:

  • Triggering via workflow_call: This workflow is designed to be called by other repositories. Inputs such as repo-name, branch, and environment are passed in when the workflow is invoked.
  • Build Job:
    1. Checkout Code: The workflow checks out the source code from the repository specified in the repo-name input, using the branch specified in branch.
    2. Build: It runs a Gradle build (./gradlew build) on the checked-out code. You can customize this step to fit your project’s build system.
    3. Push Docker Image: A Docker image is built from the code and pushed to Google Artifact Registry. The image is tagged with the latest commit or a custom tag.
  • Deploy Job:
    1. Helm Deployment: After building and pushing the Docker image, the deploy job installs or upgrades the application in the specified Kubernetes environment using Helm. The Docker image is referenced by its location in Artifact Registry (gcr.io).

Secret Inheritance

To manage sensitive information such as Docker credentials or Helm configuration, we make use of secret inheritance. Secrets configured in the triggering repository are automatically passed to the centralized workflow using the secrets: inherit statement. This ensures that the sensitive data required for tasks like authenticating with Google Artifact Registry or deploying to Kubernetes is shared securely between the workflows.

Conclusion

With this centralized CI/CD setup, we’ve significantly reduced duplication and improved scalability across multiple repositories. It simplifies the CI/CD process by consolidating workflows and ensuring consistency across various projects.

In the upcoming final blog of this series, I’ll show you how to fine-tune this workflow and provide real-world examples of its execution.

Creating Centralized Workflows for CI/CD with GitHub Actions
26-Sep-2024

In this final installment of our blog series on migrating from Jenkins to GitHub Actions, we’ll explore how to set up a centralized CI/CD workflow that runs on our customized self-hosted runners. This centralized approach simplifies the management of multiple repositories by triggering workflows from a central location.

Prerequisites

Before implementing the centralized CI/CD workflow, ensure the following are in place:

  1. Self-hosted GitHub Actions Runners: These runners must be configured in your Kubernetes cluster to execute the workflows. You can follow GitHub’s documentation on sharing runners across your organization.
  2. Repository Permissions: Both the triggering and centralized repositories need appropriate access to each other to run workflows. Ensure you have configured repository permissions correctly, and shared workflows can inherit necessary secrets. Learn more here.
  3. Helm and Docker: Ensure Docker is installed and running on your runner and Helm is set up for managing deployments to Kubernetes.
  4. Secrets Setup: You need to configure the secrets required for Docker authentication (such as Docker credentials) and any necessary environment-specific secrets, which will be shared between the workflows. For guidance on sharing secrets, refer to GitHub’s documentation on workflow secrets.

Reference Documentation

Trigger Workflow

The trigger workflow is defined in the main repository, and it uses the workflow_call event to call the centralized workflow from another repository. Here’s how it works:


name: Trigger Build and Deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:
    inputs:
      repo-name:
        description: 'Repository name to build and deploy'
        required: true
        type: string
      branch:
        description: 'Branch to deploy from'
        required: true
        type: string
        default: 'main'
      environment:
        description: 'Environment for deployment'
        required: true
        type: string
        default: 'dev'

jobs:
  call-workflow:
    uses: your-org/central-repo/.github/workflows/centralized-workflow.yml@main
    with:
      repo-name: ${{ inputs.repo-name }}
      branch: ${{ inputs.branch }}
      environment: ${{ inputs.environment }}
    secrets: inherit

Explanation of Steps:

  • Trigger: This workflow is triggered on a push to the main branch or via manual dispatch (with the workflow_dispatch event), allowing you to choose custom inputs such as the repository name, branch, and environment.
  • Job Execution: It calls the centralized-workflow.yml in a different repository using the uses keyword. This passes inputs and secrets from the triggering workflow to the centralized one.

Centralized Workflow

The centralized workflow is stored in a separate repository, defining reusable CI/CD steps such as building the code, creating a Docker image, and deploying it using Helm.


name: Centralized Build and Deploy

on:
  workflow_call:
    inputs:
      repo-name:
        description: 'Repository name to build'
        required: true
        type: string
      branch:
        description: 'Branch for deployment'
        required: true
        type: string
        default: 'main'
      environment:
        description: 'Deployment environment'
        required: true
        type: string
        default: 'dev'

jobs:
  build:
    runs-on: self-hosted-runner
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        with:
          repository: your-org/${{ inputs.repo-name }}
          ref: ${{ inputs.branch }}

      - name: Build project
        run: |
          ./gradlew build

      - name: Push Docker image
        run: |
          docker build -t gcr.io/your-project/${{ inputs.repo-name }}:latest .
          docker push gcr.io/your-project/${{ inputs.repo-name }}:latest

  deploy:
    runs-on: helm-runner
    needs: build
    steps:
      - name: Deploy using Helm
        run: |
          helm upgrade --install ${{ inputs.repo-name }} helm-chart/ \
            --namespace ${{ inputs.environment }} \
            --set image=gcr.io/your-project/${{ inputs.repo-name }}:latest

Explanation of Steps:

  • Triggering via workflow_call: This workflow is designed to be called by other repositories. Inputs such as repo-name, branch, and environment are passed in when the workflow is invoked.
  • Build Job:
    1. Checkout Code: The workflow checks out the source code from the repository specified in the repo-name input, using the branch specified in branch.
    2. Build: It runs a Gradle build (./gradlew build) on the checked-out code. You can customize this step to fit your project’s build system.
    3. Push Docker Image: A Docker image is built from the code and pushed to Google Artifact Registry. The image is tagged with the latest commit or a custom tag.
  • Deploy Job:
    1. Helm Deployment: After building and pushing the Docker image, the deploy job installs or upgrades the application in the specified Kubernetes environment using Helm. The Docker image is referenced by its location in Artifact Registry (gcr.io).

Secret Inheritance

To manage sensitive information such as Docker credentials or Helm configuration, we make use of secret inheritance. Secrets configured in the triggering repository are automatically passed to the centralized workflow using the secrets: inherit statement. This ensures that the sensitive data required for tasks like authenticating with Google Artifact Registry or deploying to Kubernetes is shared securely between the workflows.

Conclusion

With this centralized CI/CD setup, we’ve significantly reduced duplication and improved scalability across multiple repositories. It simplifies the CI/CD process by consolidating workflows and ensuring consistency across various projects.

In the upcoming final blog of this series, I’ll show you how to fine-tune this workflow and provide real-world examples of its execution.

Subscribe To Our Newsletter

Do get in touch with us to understand more about how we can help your organization in building meaningful and in-demand products
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Blog

Creating Centralized Workflows for CI/CD with GitHub Actions

Written by:  

Rajan Suri

September 26, 2024

10 mins

Creating Centralized Workflows for CI/CD with GitHub Actions

In this final installment of our blog series on migrating from Jenkins to GitHub Actions, we’ll explore how to set up a centralized CI/CD workflow that runs on our customized self-hosted runners. This centralized approach simplifies the management of multiple repositories by triggering workflows from a central location.

Prerequisites

Before implementing the centralized CI/CD workflow, ensure the following are in place:

  1. Self-hosted GitHub Actions Runners: These runners must be configured in your Kubernetes cluster to execute the workflows. You can follow GitHub’s documentation on sharing runners across your organization.
  2. Repository Permissions: Both the triggering and centralized repositories need appropriate access to each other to run workflows. Ensure you have configured repository permissions correctly, and shared workflows can inherit necessary secrets. Learn more here.
  3. Helm and Docker: Ensure Docker is installed and running on your runner and Helm is set up for managing deployments to Kubernetes.
  4. Secrets Setup: You need to configure the secrets required for Docker authentication (such as Docker credentials) and any necessary environment-specific secrets, which will be shared between the workflows. For guidance on sharing secrets, refer to GitHub’s documentation on workflow secrets.

Reference Documentation

Trigger Workflow

The trigger workflow is defined in the main repository, and it uses the workflow_call event to call the centralized workflow from another repository. Here’s how it works:


name: Trigger Build and Deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:
    inputs:
      repo-name:
        description: 'Repository name to build and deploy'
        required: true
        type: string
      branch:
        description: 'Branch to deploy from'
        required: true
        type: string
        default: 'main'
      environment:
        description: 'Environment for deployment'
        required: true
        type: string
        default: 'dev'

jobs:
  call-workflow:
    uses: your-org/central-repo/.github/workflows/centralized-workflow.yml@main
    with:
      repo-name: ${{ inputs.repo-name }}
      branch: ${{ inputs.branch }}
      environment: ${{ inputs.environment }}
    secrets: inherit

Explanation of Steps:

  • Trigger: This workflow is triggered on a push to the main branch or via manual dispatch (with the workflow_dispatch event), allowing you to choose custom inputs such as the repository name, branch, and environment.
  • Job Execution: It calls the centralized-workflow.yml in a different repository using the uses keyword. This passes inputs and secrets from the triggering workflow to the centralized one.

Centralized Workflow

The centralized workflow is stored in a separate repository, defining reusable CI/CD steps such as building the code, creating a Docker image, and deploying it using Helm.


name: Centralized Build and Deploy

on:
  workflow_call:
    inputs:
      repo-name:
        description: 'Repository name to build'
        required: true
        type: string
      branch:
        description: 'Branch for deployment'
        required: true
        type: string
        default: 'main'
      environment:
        description: 'Deployment environment'
        required: true
        type: string
        default: 'dev'

jobs:
  build:
    runs-on: self-hosted-runner
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        with:
          repository: your-org/${{ inputs.repo-name }}
          ref: ${{ inputs.branch }}

      - name: Build project
        run: |
          ./gradlew build

      - name: Push Docker image
        run: |
          docker build -t gcr.io/your-project/${{ inputs.repo-name }}:latest .
          docker push gcr.io/your-project/${{ inputs.repo-name }}:latest

  deploy:
    runs-on: helm-runner
    needs: build
    steps:
      - name: Deploy using Helm
        run: |
          helm upgrade --install ${{ inputs.repo-name }} helm-chart/ \
            --namespace ${{ inputs.environment }} \
            --set image=gcr.io/your-project/${{ inputs.repo-name }}:latest

Explanation of Steps:

  • Triggering via workflow_call: This workflow is designed to be called by other repositories. Inputs such as repo-name, branch, and environment are passed in when the workflow is invoked.
  • Build Job:
    1. Checkout Code: The workflow checks out the source code from the repository specified in the repo-name input, using the branch specified in branch.
    2. Build: It runs a Gradle build (./gradlew build) on the checked-out code. You can customize this step to fit your project’s build system.
    3. Push Docker Image: A Docker image is built from the code and pushed to Google Artifact Registry. The image is tagged with the latest commit or a custom tag.
  • Deploy Job:
    1. Helm Deployment: After building and pushing the Docker image, the deploy job installs or upgrades the application in the specified Kubernetes environment using Helm. The Docker image is referenced by its location in Artifact Registry (gcr.io).

Secret Inheritance

To manage sensitive information such as Docker credentials or Helm configuration, we make use of secret inheritance. Secrets configured in the triggering repository are automatically passed to the centralized workflow using the secrets: inherit statement. This ensures that the sensitive data required for tasks like authenticating with Google Artifact Registry or deploying to Kubernetes is shared securely between the workflows.

Conclusion

With this centralized CI/CD setup, we’ve significantly reduced duplication and improved scalability across multiple repositories. It simplifies the CI/CD process by consolidating workflows and ensuring consistency across various projects.

In the upcoming final blog of this series, I’ll show you how to fine-tune this workflow and provide real-world examples of its execution.

About Greyamp

Greyamp is a boutique Management Consulting firm that works with large enterprises to help them on their Digital Transformation journeys, going across the organisation, covering process, people, culture, and technology. Subscribe here to get our latest digital transformation insights.