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