Skip to main content

Overview

Automate UltraBalancer testing, building, and deployment with CI/CD pipelines.

GitHub Actions

Automated workflows on GitHub

GitLab CI

GitLab pipelines

Jenkins

Jenkins pipelines

CircleCI

CircleCI configuration

GitHub Actions

Complete Workflow

.github/workflows/deploy.yml
name: Deploy UltraBalancer

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Validate configuration
        run: |
          docker run --rm \
            -v $(pwd)/config.yaml:/config.yaml \
            ultrabalancer/ultrabalancer:latest \
            validate -c /config.yaml

  build:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v3

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

      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3

      - name: Configure kubectl
        uses: azure/k8s-set-context@v3
        with:
          method: kubeconfig
          kubeconfig: ${{ secrets.KUBE_CONFIG }}

      - name: Deploy to Kubernetes
        run: |
          kubectl apply -f k8s/
          kubectl rollout status deployment/ultrabalancer
          kubectl get pods -l app=ultrabalancer

      - name: Verify deployment
        run: |
          kubectl wait --for=condition=ready pod -l app=ultrabalancer --timeout=300s

      - name: Run smoke tests
        run: |
          LB_IP=$(kubectl get svc ultrabalancer -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
          curl -f http://$LB_IP/metrics || exit 1

Load Test in CI

.github/workflows/load-test.yml
name: Load Test

on:
  pull_request:
    branches: [main]

jobs:
  load-test:
    runs-on: ubuntu-latest
    services:
      backend:
        image: nginx:alpine
        ports:
          - 8081:80
          - 8082:80
          - 8083:80

    steps:
      - uses: actions/checkout@v3

      - name: Start UltraBalancer
        run: |
          docker run -d --name ultrabalancer \
            --network host \
            ultrabalancer/ultrabalancer:latest \
            -b localhost:8081 \
            -b localhost:8082 \
            -b localhost:8083 \
            -p 8080

      - name: Install tools
        run: |
          sudo apt-get update
          sudo apt-get install -y apache2-utils

      - name: Run load test
        run: |
          sleep 5
          ab -n 10000 -c 100 http://localhost:8080/ > results.txt
          cat results.txt

      - name: Check performance
        run: |
          RPS=$(grep "Requests per second" results.txt | awk '{print $4}')
          if (( $(echo "$RPS < 5000" | bc -l) )); then
            echo "Performance regression: $RPS RPS < 5000 RPS"
            exit 1
          fi

GitLab CI

Complete Pipeline

.gitlab-ci.yml
stages:
  - validate
  - build
  - test
  - deploy

variables:
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_CERTDIR: "/certs"
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG

validate:
  stage: validate
  image: ultrabalancer/ultrabalancer:latest
  script:
    - ultrabalancer validate -c config.yaml

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

test:
  stage: test
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker run -d --name backend nginx:alpine
    - docker run -d --name ultrabalancer --link backend:backend $IMAGE_TAG -b backend:80
    - sleep 5
    - docker run --link ultrabalancer:ultrabalancer curlimages/curl:latest curl -f http://ultrabalancer:8080/metrics

deploy_staging:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config set-cluster k8s --server="$KUBE_SERVER"
    - kubectl config set-credentials admin --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=admin
    - kubectl config use-context default
    - kubectl set image deployment/ultrabalancer ultrabalancer=$IMAGE_TAG -n staging
    - kubectl rollout status deployment/ultrabalancer -n staging
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy_production:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config set-cluster k8s --server="$KUBE_SERVER"
    - kubectl config set-credentials admin --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=admin
    - kubectl config use-context default
    - kubectl set image deployment/ultrabalancer ultrabalancer=$IMAGE_TAG -n production
    - kubectl rollout status deployment/ultrabalancer -n production
  environment:
    name: production
    url: https://example.com
  when: manual
  only:
    - main

Jenkins

Jenkinsfile

Jenkinsfile
pipeline {
    agent any

    environment {
        DOCKER_REGISTRY = 'docker.io'
        IMAGE_NAME = 'myorg/ultrabalancer'
        KUBE_NAMESPACE = 'production'
    }

    stages {
        stage('Validate') {
            steps {
                sh 'docker run --rm -v $(pwd)/config.yaml:/config.yaml ultrabalancer/ultrabalancer:latest validate -c /config.yaml'
            }
        }

        stage('Build') {
            steps {
                script {
                    docker.build("${IMAGE_NAME}:${env.BUILD_NUMBER}")
                }
            }
        }

        stage('Test') {
            steps {
                sh '''
                    docker run -d --name backend-${BUILD_NUMBER} nginx:alpine
                    docker run -d --name ultrabalancer-${BUILD_NUMBER} --link backend-${BUILD_NUMBER}:backend ${IMAGE_NAME}:${BUILD_NUMBER} -b backend:80
                    sleep 5
                    docker run --link ultrabalancer-${BUILD_NUMBER}:ultrabalancer curlimages/curl:latest curl -f http://ultrabalancer:8080/metrics
                '''
            }
            post {
                always {
                    sh '''
                        docker stop ultrabalancer-${BUILD_NUMBER} backend-${BUILD_NUMBER} || true
                        docker rm ultrabalancer-${BUILD_NUMBER} backend-${BUILD_NUMBER} || true
                    '''
                }
            }
        }

        stage('Push') {
            steps {
                script {
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
                        docker.image("${IMAGE_NAME}:${env.BUILD_NUMBER}").push()
                        docker.image("${IMAGE_NAME}:${env.BUILD_NUMBER}").push('latest')
                    }
                }
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                withKubeConfig([credentialsId: 'kube-config']) {
                    sh """
                        kubectl set image deployment/ultrabalancer ultrabalancer=${IMAGE_NAME}:${env.BUILD_NUMBER} -n ${KUBE_NAMESPACE}
                        kubectl rollout status deployment/ultrabalancer -n ${KUBE_NAMESPACE}
                    """
                }
            }
        }
    }

    post {
        success {
            slackSend color: 'good', message: "Deployed UltraBalancer ${env.BUILD_NUMBER} successfully"
        }
        failure {
            slackSend color: 'danger', message: "Failed to deploy UltraBalancer ${env.BUILD_NUMBER}"
        }
    }
}

CircleCI

.circleci/config.yml
version: 2.1

executors:
  docker-publisher:
    environment:
      IMAGE_NAME: myorg/ultrabalancer
    docker:
      - image: circleci/buildpack-deps:stretch

jobs:
  validate:
    docker:
      - image: ultrabalancer/ultrabalancer:latest
    steps:
      - checkout
      - run:
          name: Validate config
          command: ultrabalancer validate -c config.yaml

  build:
    executor: docker-publisher
    steps:
      - checkout
      - setup_remote_docker
      - run:
          name: Build Docker image
          command: docker build -t $IMAGE_NAME:latest .
      - run:
          name: Archive Docker image
          command: docker save -o image.tar $IMAGE_NAME
      - persist_to_workspace:
          root: .
          paths:
            - ./image.tar

  test:
    docker:
      - image: circleci/python:3.9
        environment:
          BACKEND_PORT_1: 8081
          BACKEND_PORT_2: 8082
      - image: nginx:alpine
        name: backend1
      - image: nginx:alpine
        name: backend2
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - setup_remote_docker
      - run:
          name: Load image
          command: docker load -i /tmp/workspace/image.tar
      - run:
          name: Test
          command: |
            docker run -d --name ultrabalancer -p 8080:8080 $IMAGE_NAME -b backend1:80 -b backend2:80
            sleep 5
            curl -f http://localhost:8080/metrics

  deploy:
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run:
          name: Setup kubectl
          command: |
            echo $KUBE_CONFIG | base64 -d > kubeconfig
            export KUBECONFIG=kubeconfig
      - run:
          name: Deploy
          command: |
            kubectl apply -f k8s/
            kubectl rollout status deployment/ultrabalancer

workflows:
  version: 2
  build-test-deploy:
    jobs:
      - validate
      - build:
          requires:
            - validate
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test
          filters:
            branches:
              only: main

Automated Testing Scripts

Integration Test

test-integration.sh
#!/bin/bash
set -e

echo "Starting integration tests..."

# Start backends
docker run -d --name backend1 -p 8081:80 nginx:alpine
docker run -d --name backend2 -p 8082:80 nginx:alpine

# Start UltraBalancer
docker run -d --name ultrabalancer \
  -p 8080:8080 \
  ultrabalancer/ultrabalancer:latest \
  -b host.docker.internal:8081 \
  -b host.docker.internal:8082

sleep 5

# Test connectivity
echo "Testing connectivity..."
curl -f http://localhost:8080/metrics || { echo "Metrics endpoint failed"; exit 1; }

# Test load balancing
echo "Testing load distribution..."
for i in {1..10}; do
  curl -s http://localhost:8080/ > /dev/null || { echo "Request failed"; exit 1; }
done

# Cleanup
docker stop ultrabalancer backend1 backend2
docker rm ultrabalancer backend1 backend2

echo "Integration tests passed!"