GitLab Deploy Pipeline | Complete CI/CD Deployment Guide
GitLab Deploy Pipeline
Section titled โGitLab Deploy PipelineโGitLab CI/CD deployment pipelines automate the process of deploying applications to various environments. This guide covers deploying Angular UIs, .NET Core microservices, and databases using Liquibase.
๐ ฐ๏ธ How to Deploy Angular UI
Section titled โ๐ ฐ๏ธ How to Deploy Angular UIโDeploying Angular applications involves building the production bundle and serving it through web servers or cloud platforms.
Basic Angular Deployment to Static Hosting
Section titled โBasic Angular Deployment to Static Hostingโstages: - build - deploy
variables: NODE_VERSION: "18"
deploy_angular_staging: stage: deploy image: node:${NODE_VERSION} dependencies: - build_angular script: - npm install -g @angular/cli - echo "Deploying to staging environment" - aws s3 sync dist/ s3://$STAGING_S3_BUCKET --delete - aws cloudfront create-invalidation --distribution-id $STAGING_CLOUDFRONT_ID --paths "/*" environment: name: staging url: https://staging.myapp.com only: - develop
deploy_angular_production: stage: deploy image: node:${NODE_VERSION} dependencies: - build_angular script: - npm install -g @angular/cli - echo "Deploying to production environment" - aws s3 sync dist/ s3://$PRODUCTION_S3_BUCKET --delete - aws cloudfront create-invalidation --distribution-id $PRODUCTION_CLOUDFRONT_ID --paths "/*" environment: name: production url: https://myapp.com when: manual only: - main
Angular Deployment with Docker
Section titled โAngular Deployment with Dockerโdeploy_angular_docker: stage: deploy image: docker:20.10.16 services: - docker:20.10.16-dind variables: DOCKER_TLS_CERTDIR: "/certs" script: # Build Docker image - docker build -t $CI_REGISTRY_IMAGE/angular-ui:$CI_COMMIT_SHA . - docker tag $CI_REGISTRY_IMAGE/angular-ui:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE/angular-ui:latest
# Push to registry - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker push $CI_REGISTRY_IMAGE/angular-ui:$CI_COMMIT_SHA - docker push $CI_REGISTRY_IMAGE/angular-ui:latest
# Deploy to Kubernetes - kubectl set image deployment/angular-ui angular-ui=$CI_REGISTRY_IMAGE/angular-ui:$CI_COMMIT_SHA - kubectl rollout status deployment/angular-ui environment: name: production url: https://myapp.com
Angular Deployment with Environment-Specific Configurations
Section titled โAngular Deployment with Environment-Specific Configurationsโ.deploy_angular_template: &deploy_angular image: node:18 dependencies: - build_angular script: - echo "Deploying Angular UI to $ENVIRONMENT" - | if [ "$ENVIRONMENT" = "staging" ]; then ng build --configuration=staging else ng build --configuration=production fi - aws s3 sync dist/ s3://$S3_BUCKET --delete - aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_ID --paths "/*"
deploy_angular_staging: <<: *deploy_angular stage: deploy variables: ENVIRONMENT: "staging" S3_BUCKET: $STAGING_S3_BUCKET CLOUDFRONT_ID: $STAGING_CLOUDFRONT_ID environment: name: staging url: https://staging.myapp.com only: - develop
deploy_angular_production: <<: *deploy_angular stage: deploy variables: ENVIRONMENT: "production" S3_BUCKET: $PRODUCTION_S3_BUCKET CLOUDFRONT_ID: $PRODUCTION_CLOUDFRONT_ID environment: name: production url: https://myapp.com when: manual only: - main
Angular Deployment with Nginx
Section titled โAngular Deployment with Nginxโdeploy_angular_nginx: stage: deploy image: nginx:alpine dependencies: - build_angular script: - cp -r dist/* /usr/share/nginx/html/ - | cat > /etc/nginx/conf.d/default.conf << 'EOF' server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html;
location / { try_files $uri $uri/ /index.html; }
location /api/ { proxy_pass http://backend-service:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } EOF - nginx -g 'daemon off;' environment: name: production url: https://myapp.com
๐ท How to Deploy .NET Core Microservices
Section titled โ๐ท How to Deploy .NET Core MicroservicesโDeploying .NET Core microservices involves containerization, orchestration, and proper service mesh configuration.
Basic .NET Core Deployment
Section titled โBasic .NET Core Deploymentโdeploy_dotnet_service: stage: deploy image: mcr.microsoft.com/dotnet/sdk:8.0 dependencies: - build_dotnet script: - cd publish/ - dotnet MyService.dll & - echo "Service deployed successfully" environment: name: production url: https://api.myapp.com
.NET Core Microservices with Docker Deployment
Section titled โ.NET Core Microservices with Docker Deploymentโvariables: DOCKER_REGISTRY: "registry.gitlab.com/mygroup/myproject" SERVICES: "userservice orderservice paymentservice"
.deploy_microservice_template: &deploy_microservice stage: deploy image: docker:20.10.16 services: - docker:20.10.16-dind variables: DOCKER_TLS_CERTDIR: "/certs" before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - | for service in $SERVICES; do echo "Deploying $service..."
# Build and tag image docker build -f src/$service/Dockerfile -t $DOCKER_REGISTRY/$service:$CI_COMMIT_SHA src/$service/ docker tag $DOCKER_REGISTRY/$service:$CI_COMMIT_SHA $DOCKER_REGISTRY/$service:latest
# Push to registry docker push $DOCKER_REGISTRY/$service:$CI_COMMIT_SHA docker push $DOCKER_REGISTRY/$service:latest
# Deploy to Kubernetes kubectl set image deployment/$service $service=$DOCKER_REGISTRY/$service:$CI_COMMIT_SHA kubectl rollout status deployment/$service done
deploy_microservices_staging: <<: *deploy_microservice environment: name: staging url: https://staging-api.myapp.com only: - develop
deploy_microservices_production: <<: *deploy_microservice environment: name: production url: https://api.myapp.com when: manual only: - main
Kubernetes Deployment with Helm
Section titled โKubernetes Deployment with Helmโdeploy_with_helm: stage: deploy image: alpine/helm:3.10.0 dependencies: - build_dotnet script: - helm repo add stable https://charts.helm.sh/stable - helm repo update - | helm upgrade --install my-microservices ./helm-chart \ --set image.tag=$CI_COMMIT_SHA \ --set environment=$ENVIRONMENT \ --set ingress.host=$INGRESS_HOST \ --namespace $NAMESPACE \ --create-namespace - kubectl get pods -n $NAMESPACE environment: name: $ENVIRONMENT url: https://$INGRESS_HOST
Blue-Green Deployment Strategy
Section titled โBlue-Green Deployment Strategyโdeploy_blue_green: stage: deploy image: kubectl:latest script: - | # Check current active color CURRENT_COLOR=$(kubectl get service myapp-service -o jsonpath='{.spec.selector.color}') if [ "$CURRENT_COLOR" = "blue" ]; then NEW_COLOR="green" else NEW_COLOR="blue" fi
echo "Deploying to $NEW_COLOR environment"
# Deploy to inactive color kubectl set image deployment/myapp-$NEW_COLOR myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA kubectl rollout status deployment/myapp-$NEW_COLOR
# Health check kubectl run health-check --image=curlimages/curl --rm -it --restart=Never \ -- curl -f http://myapp-$NEW_COLOR-service/health
# Switch traffic kubectl patch service myapp-service -p '{"spec":{"selector":{"color":"'$NEW_COLOR'"}}}'
echo "Traffic switched to $NEW_COLOR" environment: name: production url: https://api.myapp.com
Canary Deployment with Istio
Section titled โCanary Deployment with Istioโdeploy_canary: stage: deploy image: istio/istioctl:1.18.0 script: - | # Deploy canary version kubectl set image deployment/myapp-canary myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA kubectl rollout status deployment/myapp-canary
# Configure traffic split (10% to canary) cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: myapp-vs spec: http: - match: - headers: canary: exact: "true" route: - destination: host: myapp-canary-service - route: - destination: host: myapp-service weight: 90 - destination: host: myapp-canary-service weight: 10 EOF
echo "Canary deployment with 10% traffic split completed" environment: name: production url: https://api.myapp.com
๐๏ธ Deploy Database using Liquibase
Section titled โ๐๏ธ Deploy Database using LiquibaseโDatabase deployments with Liquibase ensure consistent schema changes across environments.
Basic Liquibase Deployment
Section titled โBasic Liquibase Deploymentโdeploy_database: stage: deploy image: liquibase/liquibase:4.23 variables: DB_URL: "jdbc:postgresql://postgres:5432/myapp" DB_USERNAME: "dbuser" DB_PASSWORD: "dbpass" script: - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD update - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD status environment: name: production
Multi-Environment Database Deployment
Section titled โMulti-Environment Database Deploymentโ.deploy_database_template: &deploy_database image: liquibase/liquibase:4.23 script: - echo "Deploying database changes to $ENVIRONMENT" - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD validate - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD update - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD status
deploy_database_staging: <<: *deploy_database stage: deploy variables: ENVIRONMENT: "staging" DB_URL: $STAGING_DB_URL DB_USERNAME: $STAGING_DB_USERNAME DB_PASSWORD: $STAGING_DB_PASSWORD environment: name: staging only: - develop
deploy_database_production: <<: *deploy_database stage: deploy variables: ENVIRONMENT: "production" DB_URL: $PRODUCTION_DB_URL DB_USERNAME: $PRODUCTION_DB_USERNAME DB_PASSWORD: $PRODUCTION_DB_PASSWORD environment: name: production when: manual only: - main
Database Deployment with Rollback Support
Section titled โDatabase Deployment with Rollback Supportโdeploy_database_with_rollback: stage: deploy image: liquibase/liquibase:4.23 variables: DB_URL: $PRODUCTION_DB_URL DB_USERNAME: $PRODUCTION_DB_USERNAME DB_PASSWORD: $PRODUCTION_DB_PASSWORD script: # Create rollback script before deployment - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD rollbackSQL $(date +"%Y-%m-%d") > rollback-script.sql
# Validate changes - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD validate
# Generate update SQL for review - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD updateSQL > update-script.sql
# Apply changes - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD update
# Verify deployment - liquibase --url=$DB_URL --username=$DB_USERNAME --password=$DB_PASSWORD status artifacts: paths: - rollback-script.sql - update-script.sql expire_in: 1 week environment: name: production
Database Deployment with Health Checks
Section titled โDatabase Deployment with Health Checksโdeploy_database_with_health_check: stage: deploy image: liquibase/liquibase:4.23 services: - postgres:13 variables: POSTGRES_DB: myapp POSTGRES_USER: dbuser POSTGRES_PASSWORD: dbpass DB_URL: "jdbc:postgresql://postgres:5432/myapp" script: # Wait for database to be ready - | for i in {1..30}; do if liquibase --url=$DB_URL --username=$POSTGRES_USER --password=$POSTGRES_PASSWORD status; then echo "Database is ready" break fi echo "Waiting for database... ($i/30)" sleep 10 done
# Deploy changes - liquibase --url=$DB_URL --username=$POSTGRES_USER --password=$POSTGRES_PASSWORD update
# Run health checks - | cat > health_check.sql << 'EOF' SELECT table_name, column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' ORDER BY table_name, ordinal_position; EOF
- psql $DB_URL -f health_check.sql environment: name: production
Database Migration with Multiple Databases
Section titled โDatabase Migration with Multiple Databasesโdeploy_multi_database: stage: deploy image: liquibase/liquibase:4.23 parallel: matrix: - DATABASE: [userdb, orderdb, inventorydb] script: - | case $DATABASE in userdb) DB_URL=$USER_DB_URL DB_USER=$USER_DB_USERNAME DB_PASS=$USER_DB_PASSWORD ;; orderdb) DB_URL=$ORDER_DB_URL DB_USER=$ORDER_DB_USERNAME DB_PASS=$ORDER_DB_PASSWORD ;; inventorydb) DB_URL=$INVENTORY_DB_URL DB_USER=$INVENTORY_DB_USERNAME DB_PASS=$INVENTORY_DB_PASSWORD ;; esac
- echo "Deploying $DATABASE database changes" - liquibase --url=$DB_URL --username=$DB_USER --password=$DB_PASS --changeLogFile=changelog-$DATABASE.xml update - liquibase --url=$DB_URL --username=$DB_USER --password=$DB_PASS status environment: name: production
๐ง Advanced Deployment Strategies
Section titled โ๐ง Advanced Deployment StrategiesโProgressive Deployment with Monitoring
Section titled โProgressive Deployment with Monitoringโdeploy_with_monitoring: stage: deploy script: - echo "Deploying application with monitoring" - kubectl apply -f deployment.yaml - kubectl rollout status deployment/myapp
# Setup monitoring - | for i in {1..10}; do HEALTH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://myapp-service/health) if [ "$HEALTH_STATUS" = "200" ]; then echo "Health check passed" break fi echo "Health check failed, retrying... ($i/10)" sleep 30 done
# Monitor metrics for 5 minutes - | for i in {1..5}; do ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=rate(http_requests_total{status=~'5..'}[5m])" | jq -r '.data.result[0].value[1]') if (( $(echo "$ERROR_RATE > 0.05" | bc -l) )); then echo "Error rate too high: $ERROR_RATE" kubectl rollout undo deployment/myapp exit 1 fi echo "Monitoring... Error rate: $ERROR_RATE" sleep 60 done environment: name: production url: https://myapp.com
Zero-Downtime Deployment
Section titled โZero-Downtime Deploymentโdeploy_zero_downtime: stage: deploy script: - | # Scale up new version kubectl scale deployment myapp-new --replicas=3 kubectl rollout status deployment myapp-new
# Health check new version kubectl run health-check --image=curlimages/curl --rm -it --restart=Never \ -- curl -f http://myapp-new-service/health
# Gradually shift traffic for weight in 25 50 75 100; do echo "Shifting $weight% traffic to new version" kubectl patch service myapp-service -p "{\"spec\":{\"selector\":{\"version\":\"new\",\"weight\":\"$weight\"}}}" sleep 120
# Monitor during traffic shift ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=rate(http_requests_total{status=~'5..'}[2m])" | jq -r '.data.result[0].value[1]') if (( $(echo "$ERROR_RATE > 0.02" | bc -l) )); then echo "Error rate increased, rolling back" kubectl patch service myapp-service -p '{"spec":{"selector":{"version":"old"}}}' exit 1 fi done
# Scale down old version kubectl scale deployment myapp-old --replicas=0 environment: name: production url: https://myapp.com
This comprehensive deployment guide covers the essential aspects of deploying Angular UIs, .NET Core microservices, and databases using Liquibase in GitLab CI/CD pipelines.