CI/CD Enterprise Guide: GitHub Actions, Jenkins, GitLab CI and Production Pipelines
A practical enterprise CI/CD guide with pipeline architecture, real YAML and Jenkinsfile examples, Docker builds, Terraform plans, Ansible deployments, Kubernetes rollouts, security gates, troubleshooting and production checklists.
Architecture → Automation → Production
Enterprise DevOps
CI/CD Overview
CI/CD is the automation layer between code and production. Continuous Integration validates every change with build, test, lint and security checks. Continuous Delivery prepares a release so it can be deployed safely. Continuous Deployment goes one step further and deploys automatically when all checks pass.
In enterprise DevOps, CI/CD connects Git, Docker, Terraform, Ansible, Kubernetes, security scanning, artifact registries and monitoring into one repeatable workflow.
| Concept | Meaning | Production Rule |
|---|---|---|
| CI | Build and test every change | Run on every pull request |
| CD | Prepare and deploy releases | Use approvals for production |
| Artifact | Immutable build output | Build once, promote many times |
| Runner/Agent | Machine executing pipeline jobs | Harden and isolate runners |
Pipeline Design
Enterprise CI/CD Architecture
A good pipeline is split into clear stages. Each stage has one responsibility. The pipeline should fail early, keep logs, protect secrets and create traceable artifacts.
Git Repository
│
▼
Pull Request
│
├── Lint
├── Unit Tests
├── Build
├── SAST / Dependency Scan
└── Docker Image Build
│
▼
Container Registry
│
▼
Deployment Pipeline
│
├── Terraform Plan / Apply
├── Ansible Configuration
├── Kubernetes Rollout
└── Smoke Test + Monitoring| Layer | Tool Examples | Risk if Missing |
|---|---|---|
| Source Control | GitHub, GitLab | No audit trail |
| CI Engine | GitHub Actions, Jenkins, GitLab CI | Manual validation |
| Artifact Store | Harbor, Nexus, GitHub Packages | Untrusted releases |
| Deployment | Helm, kubectl, Ansible | Manual production changes |
| Observability | Prometheus, Grafana, logs | No feedback after deploy |
Workflow
Pipeline Stages
Do not make one huge script. Use clear stages. This makes failures easier to understand and makes the pipeline easier to maintain.
| Stage | Purpose | Example Command |
|---|---|---|
| Format | Consistent style | terraform fmt -check |
| Lint | Static quality check | ansible-lint |
| Test | Validate logic | npm test |
| Build | Create package/image | docker build |
| Scan | Security validation | trivy image |
| Deploy | Release to environment | kubectl apply |
GitHub
GitHub Actions Pipeline
GitHub Actions workflows are YAML files stored in .github/workflows/. A workflow contains jobs. Jobs run on runners. Jobs contain steps. Use permissions, environments and secrets carefully.
# .github/workflows/ci.yml
name: CI
on:
pull_request:
push:
branches: ["main"]
permissions:
contents: read
packages: write
security-events: write
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: Test application
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
docker:
name: Build Docker image
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t ghcr.io/my-org/my-app:${{ github.sha }} .
- name: Login to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image
run: docker push ghcr.io/my-org/my-app:${{ github.sha }}Production advice: never give broad workflow permissions by default. Start with read-only permissions and add only what each job needs.
Jenkins
Jenkins Declarative Pipeline
Jenkins pipelines are often defined in a Jenkinsfile. Declarative Pipeline gives a structured syntax with stages, agents, environment variables and post actions.
// Jenkinsfile
pipeline {
agent any
options {
timestamps()
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '20'))
}
environment {
REGISTRY = 'registry.example.com'
IMAGE = 'platform/my-app'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'mvn -B clean package'
}
}
stage('Unit Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Docker Build') {
steps {
sh 'docker build -t $REGISTRY/$IMAGE:$BUILD_NUMBER .'
}
}
stage('Deploy to Test') {
steps {
sh 'kubectl set image deployment/my-app my-app=$REGISTRY/$IMAGE:$BUILD_NUMBER -n test'
sh 'kubectl rollout status deployment/my-app -n test'
}
}
}
post {
success {
echo 'Pipeline completed successfully'
}
failure {
echo 'Pipeline failed. Check logs and rollback if needed.'
}
}
}Jenkins is powerful but needs strong governance. Keep plugins updated, restrict admin access, isolate agents and store credentials in Jenkins credentials or an enterprise secret manager.
GitLab
GitLab CI Pipeline
GitLab CI uses a .gitlab-ci.yml file. Pipelines contain stages and jobs. Jobs run on GitLab runners.
# .gitlab-ci.yml
stages:
- validate
- test
- build
- scan
- deploy
variables:
IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
validate:
stage: validate
image: alpine:3.20
script:
- echo "Validate repository"
unit_test:
stage: test
image: node:22-alpine
script:
- npm ci
- npm test
artifacts:
when: always
reports:
junit: junit.xml
build_image:
stage: build
image: docker:27
services:
- docker:27-dind
script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
- docker build -t "$IMAGE_TAG" .
- docker push "$IMAGE_TAG"
production_deploy:
stage: deploy
image: bitnami/kubectl:latest
when: manual
environment:
name: production
script:
- kubectl set image deployment/my-app my-app="$IMAGE_TAG" -n production
- kubectl rollout status deployment/my-app -n productionUse protected branches, protected variables and manual production deployments for high-risk environments.
Containers
Docker Image Pipeline
A production container pipeline should build the image once, scan it, push it to a trusted registry and deploy the exact same digest or tag to each environment.
# Dockerfile example
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]# Pipeline commands
docker build -t registry.example.com/platform/my-app:${GIT_SHA} .
docker image inspect registry.example.com/platform/my-app:${GIT_SHA}
docker push registry.example.com/platform/my-app:${GIT_SHA}| Bad Practice | Better Practice |
|---|---|
Use latest in production | Use Git SHA or semantic version |
| Rebuild per environment | Build once and promote |
| No image scanning | Scan before deployment |
| Secrets in image | Use secret manager |
Infrastructure
Terraform Pipeline
Terraform should run in a controlled pipeline with remote state, state locking, validation and approval before production apply.
# Terraform CI steps
terraform fmt -check -recursive
terraform init -backend-config=backend-prod.hcl
terraform validate
terraform plan -out=tfplan
terraform show -no-color tfplan# Apply should be protected
terraform apply tfplanRecommended pull request workflow:
Pull Request
├── terraform fmt
├── terraform validate
├── terraform plan
└── Comment plan result on PR
Merge to main
├── Approval gate
└── terraform applyConfiguration
Ansible Pipeline
Ansible pipelines should validate YAML, run ansible-lint, test syntax, run check mode and then execute with limited scope before production rollout.
# CI validation
ansible-lint
yamllint .
ansible-playbook playbooks/site.yml --syntax-check
ansible-playbook playbooks/site.yml --list-hosts# Safe production run
ansible-playbook playbooks/site.yml \
-i inventories/prod/hosts.yml \
--check --diff \
--limit web01.example.com
ansible-playbook playbooks/site.yml \
-i inventories/prod/hosts.yml \
--limit webservers \
--tags nginxUse Vault or an enterprise secrets tool. Do not print secrets in pipeline logs.
Deployment
Kubernetes Deployment Pipeline
A Kubernetes pipeline should deploy manifests or Helm charts, wait for rollout status and automatically stop if the deployment fails.
kubectl apply -f k8s/deployment.yaml -n production
kubectl rollout status deployment/my-app -n production --timeout=180s
kubectl get pods -n production -l app=my-app
kubectl logs deployment/my-app -n production --tail=100# Rollback commands
kubectl rollout history deployment/my-app -n production
kubectl rollout undo deployment/my-app -n production
kubectl rollout status deployment/my-app -n productionProduction deployments should include readiness probes, liveness probes, resource requests, resource limits and a rollback procedure.
Release Control
Deployment Strategies
| Strategy | Downtime | Rollback | Best Use |
|---|---|---|---|
| Rolling Update | No | Easy | Standard Kubernetes apps |
| Blue/Green | No | Very fast | Critical enterprise services |
| Canary | No | Controlled | High-traffic systems |
| Recreate | Yes | Manual | Small internal apps |
# Kubernetes rolling update example
kubectl set image deployment/my-app my-app=registry.example.com/my-app:1.2.0 -n production
kubectl rollout status deployment/my-app -n production
# Rollback
kubectl rollout undo deployment/my-app -n productionHardening
CI/CD Security
CI/CD systems are powerful because they can deploy to production. That also makes them high-value attack targets. Treat pipelines like production systems.
- Use least privilege tokens.
- Use short-lived cloud credentials with OIDC where possible.
- Never store secrets in repository files.
- Protect production environments with approvals.
- Use protected branches.
- Pin third-party actions and dependencies.
- Scan dependencies and container images.
- Separate build runners from production deployment runners.
- Disable debug logs when secrets may be printed.
- Rotate credentials regularly.
| Risk | Control |
|---|---|
| Secret leak | Use secret manager and masked variables |
| Compromised action/plugin | Pin versions and review dependencies |
| Over-privileged token | Job-level least privilege permissions |
| Unsafe production deploy | Manual approval and environment protection |
Release Quality
Artifacts and Promotion
Artifacts should be immutable. Do not rebuild the same application separately for test and production. Build once, sign or scan it, then promote the same artifact through environments.
Build artifact: my-app-1.2.0.jar
Docker image: registry.example.com/my-app:1.2.0
Image digest: sha256:abc123...
Environment promotion: dev → test → staging → productionThis gives traceability. If production fails, you know exactly which commit, build and image caused it.
Feedback
Pipeline Observability
Measure pipeline health. A CI/CD system is not only successful when it runs. It is successful when it gives fast, reliable and actionable feedback.
| Metric | Meaning | Why It Matters |
|---|---|---|
| Lead Time | Commit to production time | Delivery speed |
| Change Failure Rate | Deployments causing incidents | Release quality |
| MTTR | Time to recover | Operational resilience |
| Deployment Frequency | How often releases happen | Team flow |
| Pipeline Duration | Time for pipeline completion | Developer feedback speed |
Operations
Troubleshooting
| Problem | Likely Cause | Check |
|---|---|---|
| Pipeline does not start | Wrong trigger or branch rule | Check workflow on or GitLab rules |
| Build fails | Dependency or compile error | Check build logs |
| Docker push fails | Registry auth issue | Check token and registry URL |
| Terraform plan fails | Provider/backend issue | Run init and validate |
| Ansible unreachable | SSH, DNS or firewall | Run ansible ping |
| Kubernetes rollout fails | Image, probe or resource issue | Describe pod and check events |
# Debug commands
git status
docker build --no-cache -t test .
terraform validate
terraform plan
ansible all -m ping -i inventories/prod/hosts.yml
kubectl describe pod my-app -n production
kubectl get events -n production --sort-by=.lastTimestamp
kubectl logs deployment/my-app -n productionCheat Sheet
Useful Commands
# Git
git status
git log --oneline --graph
git diff
git push origin feature/my-change
# Docker
docker build -t app:dev .
docker run --rm app:dev
docker push registry.example.com/app:1.0.0
# Terraform
terraform fmt -recursive
terraform init
terraform validate
terraform plan
terraform apply
# Ansible
ansible-lint
ansible-playbook site.yml --syntax-check
ansible-playbook site.yml --check --diff
ansible-playbook site.yml
# Kubernetes
kubectl apply -f k8s/
kubectl rollout status deployment/app
kubectl rollout undo deployment/app
kubectl describe pod app-123
kubectl logs deployment/appSummary
Key Takeaways
A strong CI/CD platform is not just automation. It is controlled, secure and observable delivery. The best pipelines are readable, version-controlled, repeatable and safe. They build once, test early, scan continuously, deploy with approvals and monitor after release.