Senior DevOps Engineer
Overview
Design, build, and maintain production infrastructure and deployment pipelines. This skill covers Docker containerization, Kubernetes orchestration, CI/CD with GitHub Actions, infrastructure-as-code with Terraform/Pulumi, monitoring with Prometheus/Grafana, alerting strategies, zero-downtime deployments, and rollback procedures.
Phase 1: Infrastructure Design
- Define deployment topology (single server, cluster, multi-region)
- Choose containerization strategy (Docker, Buildpacks)
- Select orchestration platform (Kubernetes, ECS, Cloud Run)
- Plan networking (load balancers, DNS, TLS)
- Design secret management approach
STOP — Present infrastructure design to user for approval before implementation.
Infrastructure Decision Table
| Scale |
Topology |
Orchestration |
Recommended |
| Hobby / MVP |
Single server |
Docker Compose |
Railway, Fly.io |
| Startup (< 100k users) |
Small cluster |
ECS, Cloud Run |
AWS ECS, GCP Cloud Run |
| Growth (100k - 1M users) |
Multi-AZ cluster |
Kubernetes |
EKS, GKE |
| Enterprise (1M+ users) |
Multi-region |
Kubernetes + service mesh |
EKS/GKE + Istio |
| Compliance-heavy |
Dedicated/private cloud |
Kubernetes |
Self-managed K8s |
Phase 2: Pipeline Implementation
- Build CI pipeline (lint, test, build, security scan)
- Build CD pipeline (deploy to staging, production)
- Configure environment-specific settings
- Set up artifact registry (container images, packages)
- Implement deployment strategy (blue-green, canary, rolling)
STOP — Validate pipeline config syntax and present for review.
Phase 3: Observability
- Deploy monitoring stack (Prometheus, Grafana)
- Configure alerting rules and escalation
- Set up log aggregation
- Implement distributed tracing
- Create runbooks for common incidents
STOP — Verify monitoring covers all critical services before declaring complete.
Dockerfile Best Practices
# 1. Use specific version tags (not :latest)
FROM node:20-alpine AS base
# 2. Set working directory
WORKDIR /app
# 3. Install dependencies in separate layer (cache optimization)
FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile --prod
FROM base AS build-deps
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
# 4. Build in separate stage
FROM build-deps AS builder
COPY . .
RUN pnpm build
# 5. Production image — minimal size
FROM base AS runner
ENV NODE_ENV=production
# 6. Don't run as root
RUN addgroup --system --gid 1001 app && \
adduser --system --uid 1001 app
USER app
# 7. Copy only what's needed
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
# 8. Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
CMD wget -qO- http://localhost:3000/health || exit 1
# 9. Expose port and set entrypoint
EXPOSE 3000
CMD ["node", "dist/server.js"]
Key Dockerfile Rules
| Rule |
Why |
| Multi-stage builds |
Minimize image size |
.dockerignore file |
Exclude node_modules, .git, tests |
| Non-root user |
Security hardening |
| Specific base image versions |
Reproducible builds |
| Layer ordering (deps before src) |
Cache efficiency |
| HEALTHCHECK instruction |
Container health monitoring |
| No secrets in build args/layers |
Prevent credential leaks |
Docker Compose Patterns
services:
app:
build:
context: .
dockerfile: Dockerfile
target: runner
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/app
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: app
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
cache:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
GitHub Actions Workflow
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm typecheck
- run: pnpm test -- --coverage
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx audit-ci --moderate
- uses: aquasecurity/trivy-action@master
with:
scan-type: fs
severity: HIGH,CRITICAL
build-and-push:
needs: [lint-and-test, security-scan]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build-and-push
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to production
run: echo "Deploying ${{ github.sha }}"
Terraform / Pulumi Patterns
Terraform Structure
modules/
vpc/
main.tf, variables.tf, outputs.tf
ecs/
main.tf, variables.tf, outputs.tf
environments/
staging/
main.tf, terraform.tfvars
production/
main.tf, terraform.tfvars
Key IaC Rules
| Rule |
Why |
| Remote state backend (S3 + DynamoDB) |
Shared state, locking |
| State locking |
Prevent concurrent modifications |
| Environment-specific variable files |
Separation of concerns |
| Module versioning |
Reproducible shared infra |
terraform plan in CI |
Catch issues before apply |
| Drift detection on schedule |
Detect manual changes |
| Tag all resources |
Ownership, cost allocation |
Monitoring (Prometheus + Grafana)
USE Method (Resources)
| Resource |
Utilization |
Saturation |
Errors |
| CPU |
cpu_usage_percent |
cpu_throttled |
— |
| Memory |
memory_usage_bytes |
oom_kills |
— |
| Disk |
disk_usage_percent |
io_wait |
disk_errors |
| Network |
bytes_total |
queue_length |
errors_total |
RED Method (Services)
- Rate: requests per second
- Errors: error rate per second
- Duration: latency distribution (p50, p95, p99)
Alerting Rules
groups:
- name: app-alerts
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
- alert: HighLatency
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
for: 5m
labels:
severity: warning
Alerting Best Practices
| Practice |
Why |
| Alert on symptoms, not causes |
Reduces noise, focuses on impact |
| Every alert has a runbook link |
Enables fast response |
| Tiered severity |
critical=page, warning=ticket, info=log |
| Aggregate before alerting |
Avoid flapping |
| Review and prune quarterly |
Prevent alert fatigue |
Zero-Downtime Deployment Strategies
| Strategy |
How It Works |
Risk |
Rollback Speed |
| Rolling |
Replace instances one at a time |
Low |
Medium |
| Blue-Green |
Switch traffic between two environments |
Low |
Instant |
| Canary |
Route small % to new version, gradually increase |
Very Low |
Instant |
| Feature Flags |
Deploy code dark, enable via flag |
Very Low |
Instant |
Rollback Procedures
- Automated: health check fails -> automatic rollback
- Manual:
kubectl rollout undo deployment/app
- Database: forward-only migrations with backward compatibility
- Config: revert via secret manager version
Database Migration Safety
| Rule |
Rationale |
| Migrations must be backward compatible |
Old code + new schema must work |
| Never rename/drop columns in same deploy |
Two-phase change required |
| Two-phase: add column -> deploy -> remove old |
Zero-downtime schema evolution |
| Always test rollback of each migration |
Ensure reversibility |
Anti-Patterns / Common Mistakes
| Anti-Pattern |
Why It Is Wrong |
What to Do Instead |
| Manual production deployments |
No audit trail, error-prone |
Automate via CI/CD |
| Shared or hardcoded secrets |
Security breach risk |
Use secrets manager |
| No rollback plan before deploying |
Stuck if deploy fails |
Document rollback before every deploy |
latest tag for production images |
Non-reproducible |
Pin specific version tags |
| Running containers as root |
Security vulnerability |
Use non-root user in Dockerfile |
| Alert fatigue from non-actionable alerts |
Real issues get missed |
Alert on symptoms, tune thresholds |
| Skipping staging environment |
Bugs found in production |
Always deploy to staging first |
| Snowflake servers with manual config |
Cannot reproduce, cannot scale |
Infrastructure as code |
| Monitoring without alerting |
Nobody notices problems |
Wire alerts to monitoring |
Key Principles
- Infrastructure as code — no manual changes to production
- Immutable infrastructure — replace, do not patch
- Cattle, not pets — servers are disposable
- Shift left security — scan early in pipeline
- Least privilege — minimal permissions everywhere
- Automate everything that runs more than twice
- Test the disaster recovery plan regularly
Documentation Lookup (Context7)
Use mcp__context7__resolve-library-id then mcp__context7__query-docs for up-to-date docs. Returned docs override memorized knowledge.
docker — for Dockerfile syntax, compose configuration, or multi-stage builds
kubernetes — for resource manifests, kubectl commands, or Helm charts
terraform — for provider configuration, resource blocks, or state management
Integration Points
| Skill |
Integration |
deployment |
Provides higher-level deploy pipeline orchestration |
security-review |
Security scan stage in CI pipeline |
planning |
Infrastructure changes are planned like features |
verification-before-completion |
Post-deploy verification gate |
finishing-a-development-branch |
Merge triggers deployment pipeline |
mcp-builder |
MCP servers need containerization and deployment |
Skill Type
FLEXIBLE — Adapt tooling and patterns to the project's cloud provider, team size, and operational maturity. The principles (IaC, immutability, observability) are constant; the specific tools are interchangeable.
1---
2name: senior-devops
3description: >
4 Use when the user needs CI/CD pipelines, Docker configuration, Kubernetes deployment,
5 infrastructure-as-code, monitoring, or zero-downtime deployment strategies. Triggers: user says
6 "devops", "docker", "kubernetes", "CI/CD", "infrastructure", "monitoring", "deploy to production",
7 "container", "terraform", "observability".
8---
9
10# Senior DevOps Engineer
11
12## Overview
13
14Design, build, and maintain production infrastructure and deployment pipelines. This skill covers Docker containerization, Kubernetes orchestration, CI/CD with GitHub Actions, infrastructure-as-code with Terraform/Pulumi, monitoring with Prometheus/Grafana, alerting strategies, zero-downtime deployments, and rollback procedures.
15
16## Phase 1: Infrastructure Design
17
181. Define deployment topology (single server, cluster, multi-region)
192. Choose containerization strategy (Docker, Buildpacks)
203. Select orchestration platform (Kubernetes, ECS, Cloud Run)
214. Plan networking (load balancers, DNS, TLS)
225. Design secret management approach
23
24**STOP — Present infrastructure design to user for approval before implementation.**
25
26### Infrastructure Decision Table
27
28| Scale | Topology | Orchestration | Recommended |
29|---|---|---|---|
30| Hobby / MVP | Single server | Docker Compose | Railway, Fly.io |
31| Startup (< 100k users) | Small cluster | ECS, Cloud Run | AWS ECS, GCP Cloud Run |
32| Growth (100k - 1M users) | Multi-AZ cluster | Kubernetes | EKS, GKE |
33| Enterprise (1M+ users) | Multi-region | Kubernetes + service mesh | EKS/GKE + Istio |
34| Compliance-heavy | Dedicated/private cloud | Kubernetes | Self-managed K8s |
35
36## Phase 2: Pipeline Implementation
37
381. Build CI pipeline (lint, test, build, security scan)
392. Build CD pipeline (deploy to staging, production)
403. Configure environment-specific settings
414. Set up artifact registry (container images, packages)
425. Implement deployment strategy (blue-green, canary, rolling)
43
44**STOP — Validate pipeline config syntax and present for review.**
45
46## Phase 3: Observability
47
481. Deploy monitoring stack (Prometheus, Grafana)
492. Configure alerting rules and escalation
503. Set up log aggregation
514. Implement distributed tracing
525. Create runbooks for common incidents
53
54**STOP — Verify monitoring covers all critical services before declaring complete.**
55
56## Dockerfile Best Practices
57
58```dockerfile
59# 1. Use specific version tags (not :latest)
60FROM node:20-alpine AS base
61
62# 2. Set working directory
63WORKDIR /app
64
65# 3. Install dependencies in separate layer (cache optimization)
66FROM base AS deps
67COPY package.json pnpm-lock.yaml ./
68RUN corepack enable && pnpm install --frozen-lockfile --prod
69
70FROM base AS build-deps
71COPY package.json pnpm-lock.yaml ./
72RUN corepack enable && pnpm install --frozen-lockfile
73
74# 4. Build in separate stage
75FROM build-deps AS builder
76COPY . .
77RUN pnpm build
78
79# 5. Production image — minimal size
80FROM base AS runner
81ENV NODE_ENV=production
82
83# 6. Don't run as root
84RUN addgroup --system --gid 1001 app && \
85 adduser --system --uid 1001 app
86USER app
87
88# 7. Copy only what's needed
89COPY --from=deps /app/node_modules ./node_modules
90COPY --from=builder /app/dist ./dist
91
92# 8. Health check
93HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
94 CMD wget -qO- http://localhost:3000/health || exit 1
95
96# 9. Expose port and set entrypoint
97EXPOSE 3000
98CMD ["node", "dist/server.js"]
99```
100
101### Key Dockerfile Rules
102
103| Rule | Why |
104|---|---|
105| Multi-stage builds | Minimize image size |
106| `.dockerignore` file | Exclude node_modules, .git, tests |
107| Non-root user | Security hardening |
108| Specific base image versions | Reproducible builds |
109| Layer ordering (deps before src) | Cache efficiency |
110| HEALTHCHECK instruction | Container health monitoring |
111| No secrets in build args/layers | Prevent credential leaks |
112
113## Docker Compose Patterns
114
115```yaml
116services:
117 app:
118 build:
119 context: .
120 dockerfile: Dockerfile
121 target: runner
122 ports:
123 - "3000:3000"
124 environment:
125 - DATABASE_URL=postgresql://postgres:postgres@db:5432/app
126 - REDIS_URL=redis://cache:6379
127 depends_on:
128 db:
129 condition: service_healthy
130 cache:
131 condition: service_started
132 healthcheck:
133 test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
134 interval: 10s
135 timeout: 5s
136 retries: 3
137
138 db:
139 image: postgres:16-alpine
140 volumes:
141 - postgres_data:/var/lib/postgresql/data
142 environment:
143 POSTGRES_DB: app
144 POSTGRES_USER: postgres
145 POSTGRES_PASSWORD: postgres
146 healthcheck:
147 test: ["CMD-SHELL", "pg_isready -U postgres"]
148 interval: 5s
149 timeout: 3s
150 retries: 5
151
152 cache:
153 image: redis:7-alpine
154 volumes:
155 - redis_data:/data
156
157volumes:
158 postgres_data:
159 redis_data:
160```
161
162## GitHub Actions Workflow
163
164```yaml
165name: CI/CD
166on:
167 push:
168 branches: [main]
169 pull_request:
170 branches: [main]
171
172concurrency:
173 group: ${{ github.workflow }}-${{ github.ref }}
174 cancel-in-progress: true
175
176jobs:
177 lint-and-test:
178 runs-on: ubuntu-latest
179 steps:
180 - uses: actions/checkout@v4
181 - uses: pnpm/action-setup@v3
182 - uses: actions/setup-node@v4
183 with:
184 node-version: 20
185 cache: pnpm
186 - run: pnpm install --frozen-lockfile
187 - run: pnpm lint
188 - run: pnpm typecheck
189 - run: pnpm test -- --coverage
190
191 security-scan:
192 runs-on: ubuntu-latest
193 steps:
194 - uses: actions/checkout@v4
195 - run: npx audit-ci --moderate
196 - uses: aquasecurity/trivy-action@master
197 with:
198 scan-type: fs
199 severity: HIGH,CRITICAL
200
201 build-and-push:
202 needs: [lint-and-test, security-scan]
203 if: github.ref == 'refs/heads/main'
204 runs-on: ubuntu-latest
205 steps:
206 - uses: actions/checkout@v4
207 - uses: docker/setup-buildx-action@v3
208 - uses: docker/login-action@v3
209 with:
210 registry: ghcr.io
211 username: ${{ github.actor }}
212 password: ${{ secrets.GITHUB_TOKEN }}
213 - uses: docker/build-push-action@v5
214 with:
215 push: true
216 tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
217 cache-from: type=gha
218 cache-to: type=gha,mode=max
219
220 deploy:
221 needs: build-and-push
222 runs-on: ubuntu-latest
223 environment: production
224 steps:
225 - name: Deploy to production
226 run: echo "Deploying ${{ github.sha }}"
227```
228
229## Terraform / Pulumi Patterns
230
231### Terraform Structure
232
233```
234modules/
235 vpc/
236 main.tf, variables.tf, outputs.tf
237 ecs/
238 main.tf, variables.tf, outputs.tf
239environments/
240 staging/
241 main.tf, terraform.tfvars
242 production/
243 main.tf, terraform.tfvars
244```
245
246### Key IaC Rules
247
248| Rule | Why |
249|---|---|
250| Remote state backend (S3 + DynamoDB) | Shared state, locking |
251| State locking | Prevent concurrent modifications |
252| Environment-specific variable files | Separation of concerns |
253| Module versioning | Reproducible shared infra |
254| `terraform plan` in CI | Catch issues before apply |
255| Drift detection on schedule | Detect manual changes |
256| Tag all resources | Ownership, cost allocation |
257
258## Monitoring (Prometheus + Grafana)
259
260### USE Method (Resources)
261
262| Resource | Utilization | Saturation | Errors |
263|---|---|---|---|
264| CPU | cpu_usage_percent | cpu_throttled | — |
265| Memory | memory_usage_bytes | oom_kills | — |
266| Disk | disk_usage_percent | io_wait | disk_errors |
267| Network | bytes_total | queue_length | errors_total |
268
269### RED Method (Services)
270
271- **Rate**: requests per second
272- **Errors**: error rate per second
273- **Duration**: latency distribution (p50, p95, p99)
274
275### Alerting Rules
276
277```yaml
278groups:
279 - name: app-alerts
280 rules:
281 - alert: HighErrorRate
282 expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
283 for: 5m
284 labels:
285 severity: critical
286 - alert: HighLatency
287 expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
288 for: 5m
289 labels:
290 severity: warning
291```
292
293### Alerting Best Practices
294
295| Practice | Why |
296|---|---|
297| Alert on symptoms, not causes | Reduces noise, focuses on impact |
298| Every alert has a runbook link | Enables fast response |
299| Tiered severity | critical=page, warning=ticket, info=log |
300| Aggregate before alerting | Avoid flapping |
301| Review and prune quarterly | Prevent alert fatigue |
302
303## Zero-Downtime Deployment Strategies
304
305| Strategy | How It Works | Risk | Rollback Speed |
306|---|---|---|---|
307| Rolling | Replace instances one at a time | Low | Medium |
308| Blue-Green | Switch traffic between two environments | Low | Instant |
309| Canary | Route small % to new version, gradually increase | Very Low | Instant |
310| Feature Flags | Deploy code dark, enable via flag | Very Low | Instant |
311
312### Rollback Procedures
313
3141. **Automated**: health check fails -> automatic rollback
3152. **Manual**: `kubectl rollout undo deployment/app`
3163. **Database**: forward-only migrations with backward compatibility
3174. **Config**: revert via secret manager version
318
319### Database Migration Safety
320
321| Rule | Rationale |
322|---|---|
323| Migrations must be backward compatible | Old code + new schema must work |
324| Never rename/drop columns in same deploy | Two-phase change required |
325| Two-phase: add column -> deploy -> remove old | Zero-downtime schema evolution |
326| Always test rollback of each migration | Ensure reversibility |
327
328## Anti-Patterns / Common Mistakes
329
330| Anti-Pattern | Why It Is Wrong | What to Do Instead |
331|---|---|---|
332| Manual production deployments | No audit trail, error-prone | Automate via CI/CD |
333| Shared or hardcoded secrets | Security breach risk | Use secrets manager |
334| No rollback plan before deploying | Stuck if deploy fails | Document rollback before every deploy |
335| `latest` tag for production images | Non-reproducible | Pin specific version tags |
336| Running containers as root | Security vulnerability | Use non-root user in Dockerfile |
337| Alert fatigue from non-actionable alerts | Real issues get missed | Alert on symptoms, tune thresholds |
338| Skipping staging environment | Bugs found in production | Always deploy to staging first |
339| Snowflake servers with manual config | Cannot reproduce, cannot scale | Infrastructure as code |
340| Monitoring without alerting | Nobody notices problems | Wire alerts to monitoring |
341
342## Key Principles
343
344- Infrastructure as code — no manual changes to production
345- Immutable infrastructure — replace, do not patch
346- Cattle, not pets — servers are disposable
347- Shift left security — scan early in pipeline
348- Least privilege — minimal permissions everywhere
349- Automate everything that runs more than twice
350- Test the disaster recovery plan regularly
351
352## Documentation Lookup (Context7)
353
354Use `mcp__context7__resolve-library-id` then `mcp__context7__query-docs` for up-to-date docs. Returned docs override memorized knowledge.
355- `docker` — for Dockerfile syntax, compose configuration, or multi-stage builds
356- `kubernetes` — for resource manifests, kubectl commands, or Helm charts
357- `terraform` — for provider configuration, resource blocks, or state management
358
359---
360
361## Integration Points
362
363| Skill | Integration |
364|---|---|
365| `deployment` | Provides higher-level deploy pipeline orchestration |
366| `security-review` | Security scan stage in CI pipeline |
367| `planning` | Infrastructure changes are planned like features |
368| `verification-before-completion` | Post-deploy verification gate |
369| `finishing-a-development-branch` | Merge triggers deployment pipeline |
370| `mcp-builder` | MCP servers need containerization and deployment |
371
372## Skill Type
373
374**FLEXIBLE** — Adapt tooling and patterns to the project's cloud provider, team size, and operational maturity. The principles (IaC, immutability, observability) are constant; the specific tools are interchangeable.