๐ AlmaLinux GitLab CI/CD: Complete DevOps Pipeline Guide
Welcome to the world of automated software delivery on AlmaLinux! ๐ Whether youโre shipping code hourly, managing complex deployments, or building a DevOps culture, this comprehensive guide will transform you into a CI/CD master who can build pipelines that deploy code from commit to production automatically! ๐
GitLab on AlmaLinux provides everything you need for modern DevOps โ source control, CI/CD, container registry, and Kubernetes integration all in one platform! Letโs build deployment pipelines that make releases boring (in the best way)! ๐ช
๐ค Why is GitLab CI/CD Important?
Imagine deploying to production 100 times a day with zero fear โ thatโs the power of CI/CD! ๐ฏ Hereโs why mastering GitLab on AlmaLinux is absolutely game-changing:
- ๐ Continuous Delivery - Ship features to users in minutes, not months
- ๐ Automated Testing - Catch bugs before they reach production
- ๐ฆ Container Integration - Build, test, and deploy Docker images
- ๐ก๏ธ Security Scanning - Detect vulnerabilities automatically
- ๐ Pipeline Visibility - Track every deployment and its status
- ๐ง Infrastructure as Code - Version control your entire stack
- ๐ฐ Cost Reduction - Eliminate manual deployment errors
- ๐ GitOps Ready - Git as single source of truth
๐ฏ What You Need
Letโs prepare your environment for DevOps excellence! โ
System Requirements:
- โ AlmaLinux 8.x or 9.x server
- โ Minimum 4 CPUs and 8GB RAM
- โ 50GB+ available disk space
- โ Domain name or static IP
- โ Root or sudo access
Software Weโll Install:
- โ GitLab Community Edition
- โ GitLab Runner for job execution
- โ Docker for containerization
- โ Kubernetes CLI (kubectl)
- โ SSL certificates for HTTPS
๐ Installing GitLab on AlmaLinux
Letโs install and configure GitLab for your DevOps platform! ๐ง
Installing GitLab CE
# Install dependencies
sudo dnf install -y curl policycoreutils openssh-server openssh-clients
sudo dnf install -y postfix
# Enable services
sudo systemctl enable sshd
sudo systemctl start sshd
sudo systemctl enable postfix
sudo systemctl start postfix
# Add GitLab repository
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
# Install GitLab CE
# Replace gitlab.example.com with your domain
sudo EXTERNAL_URL="https://gitlab.example.com" dnf install -y gitlab-ce
# Configure GitLab
sudo gitlab-ctl reconfigure
# Check status
sudo gitlab-ctl status
# Get initial root password
sudo cat /etc/gitlab/initial_root_password
# Configure firewall
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
Configuring GitLab Settings
# Edit GitLab configuration
sudo vi /etc/gitlab/gitlab.rb
# Essential configurations to add/modify:
external_url 'https://gitlab.example.com'
gitlab_rails['time_zone'] = 'UTC'
# Email configuration
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.gmail.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "[email protected]"
gitlab_rails['smtp_password'] = "your-app-password"
gitlab_rails['smtp_domain'] = "gmail.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
# Backup settings
gitlab_rails['backup_path'] = "/var/opt/gitlab/backups"
gitlab_rails['backup_keep_time'] = 604800 # 7 days
# Container Registry
registry_external_url 'https://registry.example.com'
gitlab_rails['registry_enabled'] = true
# Apply configuration
sudo gitlab-ctl reconfigure
# Create backup schedule
echo "0 2 * * * /opt/gitlab/bin/gitlab-backup create SKIP=artifacts,registry,pages,uploads" | sudo crontab -
๐ง Setting Up GitLab Runners
GitLab Runners execute your CI/CD jobs. Letโs set them up! ๐โโ๏ธ
Installing GitLab Runner
# Add GitLab Runner repository
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash
# Install GitLab Runner
sudo dnf install -y gitlab-runner
# Install Docker for container jobs
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable --now docker
# Add gitlab-runner to docker group
sudo usermod -aG docker gitlab-runner
# Register runner with GitLab
sudo gitlab-runner register
# Interactive prompts:
# GitLab URL: https://gitlab.example.com
# Registration token: (get from GitLab Admin Area > Runners)
# Description: docker-runner
# Tags: docker,linux
# Executor: docker
# Docker image: alpine:latest
# Start GitLab Runner
sudo systemctl enable --now gitlab-runner
# Verify runner
sudo gitlab-runner verify
sudo gitlab-runner list
Configuring Shared Runners
# Edit runner configuration
sudo vi /etc/gitlab-runner/config.toml
# Add/modify runner configuration:
concurrent = 4
check_interval = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "docker-runner"
url = "https://gitlab.example.com/"
token = "YOUR_RUNNER_TOKEN"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "alpine:latest"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
shm_size = 0
# Restart runner
sudo gitlab-runner restart
๐ Creating CI/CD Pipelines
Letโs build powerful CI/CD pipelines! ๐
Basic Pipeline Configuration
# Create .gitlab-ci.yml in your project root
stages:
- build
- test
- deploy
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
IMAGE_NAME: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
before_script:
- echo "Starting CI/CD Pipeline..."
- echo "Project: $CI_PROJECT_NAME"
- echo "Branch: $CI_COMMIT_REF_NAME"
# Build stage
build-job:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $IMAGE_NAME .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $IMAGE_NAME
only:
- main
- develop
# Test stage
test-job:
stage: test
image: node:16-alpine
script:
- npm install
- npm test
- npm run lint
coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
# Deploy to staging
deploy-staging:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
script:
- ssh -o StrictHostKeyChecking=no [email protected] "
docker pull $IMAGE_NAME &&
docker stop app || true &&
docker rm app || true &&
docker run -d --name app -p 80:80 $IMAGE_NAME
"
environment:
name: staging
url: https://staging.example.com
only:
- develop
# Deploy to production
deploy-production:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
script:
- ssh -o StrictHostKeyChecking=no [email protected] "
docker pull $IMAGE_NAME &&
docker stop app || true &&
docker rm app || true &&
docker run -d --name app -p 80:80 $IMAGE_NAME
"
environment:
name: production
url: https://production.example.com
when: manual
only:
- main
Advanced Pipeline with Security Scanning
# Advanced .gitlab-ci.yml with security and quality gates
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
stages:
- build
- test
- security
- deploy
- monitor
# Build Docker image
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
# Run unit tests
unit-tests:
stage: test
image: python:3.9
script:
- pip install -r requirements.txt
- pytest tests/ --cov=app --cov-report=xml
artifacts:
reports:
junit: test-results.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
# Code quality check
code-quality:
stage: test
image: python:3.9
script:
- pip install pylint black flake8
- black --check .
- flake8 .
- pylint app/
# Security scanning (using GitLab templates)
sast:
stage: security
container_scanning:
stage: security
variables:
CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
dependency_scanning:
stage: security
# Deploy to Kubernetes
deploy-k8s:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl config use-context $KUBE_CONTEXT
- sed -i "s|IMAGE_TAG|$CI_COMMIT_SHA|g" k8s/deployment.yaml
- kubectl apply -f k8s/
- kubectl rollout status deployment/app -n production
environment:
name: production
url: https://app.example.com
only:
- main
โ Kubernetes Integration
Letโs deploy to Kubernetes directly from GitLab! โธ๏ธ
Setting Up Kubernetes Integration
# Create Kubernetes manifests
mkdir k8s
cat > k8s/deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: registry.example.com/project:IMAGE_TAG
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: app-service
namespace: production
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
EOF
# Create GitLab CI for Kubernetes deployment
cat > .gitlab-ci-k8s.yml << 'EOF'
deploy-kubernetes:
stage: deploy
image:
name: bitnami/kubectl:latest
entrypoint: [""]
before_script:
- kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true
- kubectl config set-credentials gitlab --token="$KUBE_TOKEN"
- kubectl config set-context default --cluster=k8s --user=gitlab
- kubectl config use-context default
script:
- sed -i "s|IMAGE_TAG|$CI_COMMIT_SHA|g" k8s/deployment.yaml
- kubectl apply -f k8s/deployment.yaml
- kubectl rollout status deployment/app -n production
environment:
name: production
url: https://app.example.com
only:
- main
EOF
GitOps with ArgoCD
# Install ArgoCD on Kubernetes
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Create ArgoCD application
cat > argocd-app.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://gitlab.example.com/team/app.git
targetRevision: HEAD
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
EOF
kubectl apply -f argocd-app.yaml
๐ฎ Quick Examples
Example 1: Multi-Environment Pipeline
# Pipeline with multiple environments
stages:
- build
- deploy-dev
- deploy-staging
- deploy-prod
.deploy-template: &deploy-template
image: alpine:latest
before_script:
- apk add --no-cache curl
script:
- echo "Deploying to $CI_ENVIRONMENT_NAME"
- curl -X POST $DEPLOY_WEBHOOK_URL
build:
stage: build
script:
- echo "Building application..."
- docker build -t app:$CI_COMMIT_SHA .
deploy-dev:
<<: *deploy-template
stage: deploy-dev
environment:
name: development
url: https://dev.example.com
variables:
DEPLOY_WEBHOOK_URL: $DEV_WEBHOOK
only:
- develop
deploy-staging:
<<: *deploy-template
stage: deploy-staging
environment:
name: staging
url: https://staging.example.com
variables:
DEPLOY_WEBHOOK_URL: $STAGING_WEBHOOK
only:
- main
deploy-production:
<<: *deploy-template
stage: deploy-prod
environment:
name: production
url: https://www.example.com
variables:
DEPLOY_WEBHOOK_URL: $PROD_WEBHOOK
when: manual
only:
- main
Example 2: Database Migration Pipeline
# Pipeline with database migrations
stages:
- test
- migrate
- deploy
test-migrations:
stage: test
image: postgres:14
services:
- postgres:14
variables:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_pass
script:
- apt-get update && apt-get install -y postgresql-client
- PGPASSWORD=$POSTGRES_PASSWORD psql -h postgres -U $POSTGRES_USER -d $POSTGRES_DB < schema.sql
- ./run-migration-tests.sh
migrate-staging:
stage: migrate
image: migrate/migrate
script:
- migrate -path ./migrations -database "$STAGING_DB_URL" up
environment:
name: staging
only:
- main
migrate-production:
stage: migrate
image: migrate/migrate
script:
- migrate -path ./migrations -database "$PROD_DB_URL" up
environment:
name: production
when: manual
only:
- main
deploy-app:
stage: deploy
script:
- echo "Deploying application after migrations..."
needs: ["migrate-staging"]
Example 3: Monitoring and Alerting Integration
# Create monitoring job in pipeline
cat >> .gitlab-ci.yml << 'EOF'
# Health check after deployment
health-check:
stage: monitor
image: curlimages/curl:latest
script:
- |
for i in {1..30}; do
if curl -f https://app.example.com/health; then
echo "Application is healthy!"
exit 0
fi
echo "Waiting for application to be ready... ($i/30)"
sleep 10
done
echo "Application health check failed!"
exit 1
needs: ["deploy-production"]
# Send notification to Slack
notify-slack:
stage: .post
image: curlimages/curl:latest
script:
- |
curl -X POST $SLACK_WEBHOOK_URL \
-H 'Content-Type: application/json' \
-d "{
\"text\": \"Deployment to production completed!\",
\"attachments\": [{
\"color\": \"good\",
\"fields\": [{
\"title\": \"Project\",
\"value\": \"$CI_PROJECT_NAME\",
\"short\": true
},{
\"title\": \"Environment\",
\"value\": \"Production\",
\"short\": true
},{
\"title\": \"Version\",
\"value\": \"$CI_COMMIT_SHORT_SHA\",
\"short\": true
}]
}]
}"
when: on_success
only:
- main
EOF
๐จ Fix Common CI/CD Problems
Letโs solve frequent GitLab CI/CD issues! ๐ ๏ธ
Problem 1: Pipeline Fails with Docker Permission Denied
Symptoms: Cannot connect to Docker daemon Solution:
# Add gitlab-runner to docker group
sudo usermod -aG docker gitlab-runner
# Restart services
sudo systemctl restart docker
sudo systemctl restart gitlab-runner
# In .gitlab-ci.yml, use privileged mode:
services:
- docker:dind
variables:
DOCKER_TLS_CERTDIR: ""
DOCKER_HOST: tcp://docker:2375
Problem 2: SSH Deployment Fails
Symptoms: Permission denied during deployment Solution:
# Generate SSH key for deployments
ssh-keygen -t ed25519 -C "gitlab-deploy" -f deploy_key
# Add public key to target server
ssh-copy-id -i deploy_key.pub user@server
# Add private key to GitLab CI variables
# Go to Settings > CI/CD > Variables
# Add SSH_PRIVATE_KEY with the private key content
# In pipeline, use:
before_script:
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
- mkdir -p ~/.ssh
- ssh-keyscan -H 'server.example.com' >> ~/.ssh/known_hosts
Problem 3: Container Registry Login Fails
Symptoms: unauthorized: authentication required Solution:
# Use GitLab CI predefined variables
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# Or use deploy token
# Create deploy token in Settings > Repository > Deploy Tokens
script:
- docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
Problem 4: Job Timeout
Symptoms: Job exceeded maximum execution time Solution:
# Increase timeout in .gitlab-ci.yml
job-name:
timeout: 2 hours
script:
- long-running-command
# Or globally in project settings
# Settings > CI/CD > General pipelines > Timeout
๐ GitLab CI/CD Commands Reference
Essential GitLab commands for DevOps operations! โก
Command | Purpose |
---|---|
gitlab-ctl reconfigure | Apply configuration changes |
gitlab-ctl status | Check GitLab services |
gitlab-ctl tail | View GitLab logs |
gitlab-backup create | Create backup |
gitlab-runner register | Register new runner |
gitlab-runner verify | Verify runners |
gitlab-runner exec | Test job locally |
gitlab-rake cache:clear | Clear cache |
๐ก CI/CD Best Practices
Master these DevOps best practices! ๐ฏ
- ๐ Fail Fast - Run quick tests first, expensive ones later
- ๐ฆ Cache Dependencies - Speed up builds with caching
- ๐ Secure Secrets - Never hardcode credentials
- ๐ Monitor Pipelines - Track success rates and duration
- ๐ฏ Small Commits - Make debugging easier
- ๐ง Pipeline as Code - Version control your CI/CD
- ๐ Document Pipelines - Help team understand workflow
- ๐ Progressive Delivery - Use feature flags and canary deployments
- ๐ก๏ธ Security Scanning - Integrate SAST/DAST/dependency scanning
- ๐พ Artifact Management - Store and version build artifacts
๐ What Youโve Accomplished
Congratulations on mastering GitLab CI/CD on AlmaLinux! ๐ Youโve achieved:
- โ Complete GitLab installation and configuration
- โ GitLab Runners deployed for job execution
- โ CI/CD pipelines created with multiple stages
- โ Docker integration for containerized workflows
- โ Kubernetes deployments automated
- โ Security scanning integrated in pipelines
- โ Multi-environment deployment strategies
- โ GitOps workflows implemented
- โ Monitoring and notifications configured
- โ Best practices applied throughout
๐ฏ Why These Skills Matter
Your CI/CD expertise accelerates software delivery! ๐ With these skills, you can:
Immediate Benefits:
- ๐ Deploy code to production in minutes
- ๐ก๏ธ Catch bugs before they reach users
- ๐ Increase deployment frequency by 100x
- ๐ฐ Reduce deployment failures by 90%
Long-term Value:
- ๐ Lead DevOps transformation initiatives
- ๐ผ Implement enterprise CI/CD strategies
- ๐ Build globally distributed delivery pipelines
- ๐ Enable continuous innovation culture
Youโre now equipped to build and manage CI/CD pipelines that transform how software is delivered! From startup MVPs to enterprise applications, you can automate the entire software delivery lifecycle! ๐
Keep automating, keep delivering! ๐