$npx -y skills add wshobson/agents --skill gitlab-ci-patternsBuild GitLab CI/CD pipelines with multi-stage workflows, caching, and distributed runners for scalable automation. Use when implementing GitLab CI/CD, optimizing pipeline performance, or setting up automated testing and deployment.
| 1 | # GitLab CI Patterns |
| 2 | |
| 3 | Comprehensive GitLab CI/CD pipeline patterns for automated testing, building, and deployment. |
| 4 | |
| 5 | ## Purpose |
| 6 | |
| 7 | Create efficient GitLab CI pipelines with proper stage organization, caching, and deployment strategies. |
| 8 | |
| 9 | ## When to Use |
| 10 | |
| 11 | - Automate GitLab-based CI/CD |
| 12 | - Implement multi-stage pipelines |
| 13 | - Configure GitLab Runners |
| 14 | - Deploy to Kubernetes from GitLab |
| 15 | - Implement GitOps workflows |
| 16 | |
| 17 | ## Basic Pipeline Structure |
| 18 | |
| 19 | ```yaml |
| 20 | stages: |
| 21 | - build |
| 22 | - test |
| 23 | - deploy |
| 24 | |
| 25 | variables: |
| 26 | DOCKER_DRIVER: overlay2 |
| 27 | DOCKER_TLS_CERTDIR: "/certs" |
| 28 | |
| 29 | build: |
| 30 | stage: build |
| 31 | image: node:20 |
| 32 | script: |
| 33 | - npm ci |
| 34 | - npm run build |
| 35 | artifacts: |
| 36 | paths: |
| 37 | - dist/ |
| 38 | expire_in: 1 hour |
| 39 | cache: |
| 40 | key: ${CI_COMMIT_REF_SLUG} |
| 41 | paths: |
| 42 | - node_modules/ |
| 43 | |
| 44 | test: |
| 45 | stage: test |
| 46 | image: node:20 |
| 47 | script: |
| 48 | - npm ci |
| 49 | - npm run lint |
| 50 | - npm test |
| 51 | coverage: '/Lines\s*:\s*(\d+\.\d+)%/' |
| 52 | artifacts: |
| 53 | reports: |
| 54 | coverage_report: |
| 55 | coverage_format: cobertura |
| 56 | path: coverage/cobertura-coverage.xml |
| 57 | |
| 58 | deploy: |
| 59 | stage: deploy |
| 60 | image: bitnami/kubectl:1.31 |
| 61 | script: |
| 62 | - kubectl apply -f k8s/ |
| 63 | - kubectl rollout status deployment/my-app |
| 64 | only: |
| 65 | - main |
| 66 | environment: |
| 67 | name: production |
| 68 | url: https://app.example.com |
| 69 | ``` |
| 70 | |
| 71 | ## Docker Build and Push |
| 72 | |
| 73 | ```yaml |
| 74 | build-docker: |
| 75 | stage: build |
| 76 | image: docker:24 |
| 77 | services: |
| 78 | - docker:24-dind |
| 79 | before_script: |
| 80 | - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY |
| 81 | script: |
| 82 | - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . |
| 83 | - docker build -t $CI_REGISTRY_IMAGE:latest . |
| 84 | - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA |
| 85 | - docker push $CI_REGISTRY_IMAGE:latest |
| 86 | only: |
| 87 | - main |
| 88 | - tags |
| 89 | ``` |
| 90 | |
| 91 | ## Multi-Environment Deployment |
| 92 | |
| 93 | ```yaml |
| 94 | .deploy_template: &deploy_template |
| 95 | image: bitnami/kubectl:1.31 |
| 96 | before_script: |
| 97 | - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true |
| 98 | - kubectl config set-credentials admin --token="$KUBE_TOKEN" |
| 99 | - kubectl config set-context default --cluster=k8s --user=admin |
| 100 | - kubectl config use-context default |
| 101 | |
| 102 | deploy:staging: |
| 103 | <<: *deploy_template |
| 104 | stage: deploy |
| 105 | script: |
| 106 | - kubectl apply -f k8s/ -n staging |
| 107 | - kubectl rollout status deployment/my-app -n staging |
| 108 | environment: |
| 109 | name: staging |
| 110 | url: https://staging.example.com |
| 111 | only: |
| 112 | - develop |
| 113 | |
| 114 | deploy:production: |
| 115 | <<: *deploy_template |
| 116 | stage: deploy |
| 117 | script: |
| 118 | - kubectl apply -f k8s/ -n production |
| 119 | - kubectl rollout status deployment/my-app -n production |
| 120 | environment: |
| 121 | name: production |
| 122 | url: https://app.example.com |
| 123 | when: manual |
| 124 | only: |
| 125 | - main |
| 126 | ``` |
| 127 | |
| 128 | ## Terraform Pipeline |
| 129 | |
| 130 | ```yaml |
| 131 | stages: |
| 132 | - validate |
| 133 | - plan |
| 134 | - apply |
| 135 | |
| 136 | variables: |
| 137 | TF_ROOT: ${CI_PROJECT_DIR}/terraform |
| 138 | TF_VERSION: "1.6.0" |
| 139 | |
| 140 | before_script: |
| 141 | - cd ${TF_ROOT} |
| 142 | - terraform --version |
| 143 | |
| 144 | validate: |
| 145 | stage: validate |
| 146 | image: hashicorp/terraform:${TF_VERSION} |
| 147 | script: |
| 148 | - terraform init -backend=false |
| 149 | - terraform validate |
| 150 | - terraform fmt -check |
| 151 | |
| 152 | plan: |
| 153 | stage: plan |
| 154 | image: hashicorp/terraform:${TF_VERSION} |
| 155 | script: |
| 156 | - terraform init |
| 157 | - terraform plan -out=tfplan |
| 158 | artifacts: |
| 159 | paths: |
| 160 | - ${TF_ROOT}/tfplan |
| 161 | expire_in: 1 day |
| 162 | |
| 163 | apply: |
| 164 | stage: apply |
| 165 | image: hashicorp/terraform:${TF_VERSION} |
| 166 | script: |
| 167 | - terraform init |
| 168 | - terraform apply -auto-approve tfplan |
| 169 | dependencies: |
| 170 | - plan |
| 171 | when: manual |
| 172 | only: |
| 173 | - main |
| 174 | ``` |
| 175 | |
| 176 | ## Security Scanning |
| 177 | |
| 178 | ```yaml |
| 179 | include: |
| 180 | - template: Security/SAST.gitlab-ci.yml |
| 181 | - template: Security/Dependency-Scanning.gitlab-ci.yml |
| 182 | - template: Security/Container-Scanning.gitlab-ci.yml |
| 183 | |
| 184 | trivy-scan: |
| 185 | stage: test |
| 186 | image: aquasec/trivy:0.58.0 |
| 187 | script: |
| 188 | - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA |
| 189 | allow_failure: true |
| 190 | ``` |
| 191 | |
| 192 | ## Caching Strategies |
| 193 | |
| 194 | ```yaml |
| 195 | # Cache node_modules |
| 196 | build: |
| 197 | cache: |
| 198 | key: ${CI_COMMIT_REF_SLUG} |
| 199 | paths: |
| 200 | - node_modules/ |
| 201 | policy: pull-push |
| 202 | |
| 203 | # Global cache |
| 204 | cache: |
| 205 | key: ${CI_COMMIT_REF_SLUG} |
| 206 | paths: |
| 207 | - .cache/ |
| 208 | - vendor/ |
| 209 | |
| 210 | # Separate cache per job |
| 211 | job1: |
| 212 | cache: |
| 213 | key: job1-cache |
| 214 | paths: |
| 215 | - build/ |
| 216 | |
| 217 | job2: |
| 218 | cache: |
| 219 | key: job2-cache |
| 220 | paths: |
| 221 | - dist/ |
| 222 | ``` |
| 223 | |
| 224 | ## Dynamic Child Pipelines |
| 225 | |
| 226 | ```yaml |
| 227 | generate-pipeline: |
| 228 | stage: build |
| 229 | script: |
| 230 | - python generate_pipeline.py > child-pipeline.yml |
| 231 | artifacts: |
| 232 | paths: |
| 233 | - child-pipeline.yml |
| 234 | |
| 235 | trigger-child: |
| 236 | stage: deploy |
| 237 | trigger: |
| 238 | include: |
| 239 | - artifact: child-pipeline.yml |
| 240 | job: generate-pipeline |
| 241 | strategy: depend |
| 242 | ``` |
| 243 | |
| 244 | |
| 245 | ## Best Practices |
| 246 | |
| 247 | 1. **Use specific image tags** (node:20, not node:latest) |
| 248 | 2. **Cache dependencies** appropriately |
| 249 | 3. **Use artifacts** for build outputs |
| 250 | 4. **Implement manual gates** |