Best practise for seperation of test and prod build/deployment

Hi,

Im fairly new to github actions. I want to understand what the best practise is for my usecase.

I am trying to deploy my application to a test and production environment using a tagged image.

Right now i have a pipeline that builds a docker image, pushes it to aws and updates a k8 deployment with the new docker image. This pipeline right now will only trigger when there is a tag and it only supports the “-test” version of building and deploying.

.github/workflows/pipeline.yml

name: pipeline

on: [ push ]

env:
  AWS_DEFAULT_REGION: us-east-2
  AWS_DEFAULT_OUTPUT: json
  AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  KUBECONFIG_B64DATA: ${{ secrets.KUBECONFIG_B64DATA }}
  CONTAINER_IMAGE: haproxy
  CI: true

jobs:
  build-test:
    name: Build Test
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@master
      with:
        persist-credentials: false
    - name: Setup ECR
      run: |
        ls
        $( aws ecr get-login --no-include-email )
    - name: Build and tag the image
      run: |  
        docker build --build-arg ENV="test" -t $CONTAINER_IMAGE:${GITHUB_REF#refs/*/}-test .
        docker tag $CONTAINER_IMAGE:${GITHUB_REF#refs/*/}-test $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$CONTAINER_IMAGE:${GITHUB_REF#refs/*/}-test
        docker image ls
    - name: Push
      run: |
        docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$CONTAINER_IMAGE:${GITHUB_REF#refs/*/}-test

  deploy-test:
    name: Deploy Test
    needs: build
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@master
    
    - name: Setup Kubectl
      run: |
        sudo apt-get -y install curl
        curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
        chmod +x ./kubectl
        sudo mv ./kubectl /usr/local/bin/kubectl
        echo "${KUBECONFIG_B64DATA// /}" | base64 --decode > /tmp/config
        sudo mkdir -p ~/.kube
        sudo mv /tmp/config ~/.kube/
    - name: Update Deployment Config
      run: |
        echo ${GITHUB_REF#refs/*/}
        sed -i 's#$TAG#'"${GITHUB_REF#refs/*/}"'#g' deploy/test.yml
        cat deploy/test.yml
    - name: Release
      run: |
        kubectl apply -f deploy/test.yml

I would like to begin implementing a production version of this pipeline which would require an exact copy of build-test and deploy-test except with a few variable changes. So i will end up with a build-prod and a deploy-prod stages.

What is the best way to handle this, should prod stages be within the same pipeline file or should there be second pipeline file.

Also i want the ability to ONLY build/deploy to test and ONLY build/deploy to prod, right now this pipeline will trigger the stages whenever there is a tag. So what is the best practise from your experience on how i can trigger building/deploying to only test or only prod.

@kaykhan,

  1. About the first question:
    Unlike Azure Pipelines that supports defining stages in the YAML file, GitHub Actions requires you to separate stages into separate YAML workflow files.
    To view more details, you can reference here.

  2. About the second question:
    Due to branches filter (branches or branches-ignore) and tags filter (tags or tags-ignore) are available to push events, there are two methods to only trigger build/deploy to test or only build/deploy to prod.

  • Using branches filter
    Create two branches test and prod, and setup two workflows like as below.
# .github/workflows/pipeline-test.yml
name: pipeline-test

on:
  push:
    branches:
      - 'test'
  . . .
# .github/workflows/pipeline-prod.yml
name: pipeline-prod

on:
  push:
    branches:
      - 'prod'
  . . .

In this way, pushes to test branch only trigger pipeline-test, and pushes to prod branch only trigger pipeline-prod.

  • Using tags filter
    Setup two workflows like as below.
# .github/workflows/pipeline-test.yml
name: pipeline-test

on:
  push:
    tags:
      - '**-test'
  . . .
# .github/workflows/pipeline-prod.yml
name: pipeline-prod

on:
  push:
    tags:
      - '**-prod'
  . . .

In this way, pushes to tags that end with ‘-test’ (e.g. v1.1-test, v1.2-test) only trigger “pipeline-test”, and pushes to tags that end with ‘-prod’ (e.g. v1.1-prod, v1.2-prod) only trigger “pipeline-prod”.