Reference · Daily SDE

Cheatsheets — Linux, Docker, Kubernetes & the Daily Toolbelt

Field guide for what an SDE types every day. Each section is a quick-scan table plus the gotchas that bite in production. Code blocks copy on click.

1 · Linux — Files & Permissions

Filesystem moves, listing, and the chmod bits that confuse everyone.

Navigation & listing

CommandPurpose
ls -lahLong, human-sized, all (incl. dotfiles).
ls -lt | headNewest files first.
tree -L 2 -aTwo levels deep, all files.
cd -Jump back to previous dir.
pushd /x / popdDir stack — explore then return.
readlink -f fileResolve symlink to absolute path.

File ops

CommandPurpose
cp -a src dstArchive: preserve perms, links, timestamps.
rsync -avhP src/ dst/Resumable, progress, trailing slash matters.
mv -i a bInteractive — prompt before overwrite.
ln -s target linkSymbolic link.
stat fileInode, perms, atime/mtime/ctime.
du -sh * / du -hd1Per-entry size of cwd.
df -hDisk free per mount.
ncdu /Interactive disk usage explorer.

Permissions & ownership

# numeric: r=4 w=2 x=1   user|group|other
chmod 755 script.sh        # rwxr-xr-x
chmod 600 ~/.ssh/id_rsa    # rw------- (private keys MUST be 600)
chmod -R u+rwX,go-w dir    # capital X = exec only on dirs / already-exec files
chown -R user:group dir
umask 022                  # default mask: new files = 644, dirs = 755
sudo chmod g+s shareddir   # setgid on dir = new files inherit group

Find & locate

find . -type f -name "*.log" -mtime -1            # modified in last 24h
find . -type f -size +100M                         # bigger than 100MB
find . -name node_modules -type d -prune -exec rm -rf {} +
find . -name "*.tmp" -delete
fd 'pattern'                                       # rust find, faster
locate filename                                    # uses prebuilt db (mlocate)

2 · Text Processing — grep · sed · awk

Filter, transform, count. Pipe everything.

grep / ripgrep

grep -rni 'TODO' src/                 # recursive, line nums, ignore-case
grep -E '(error|fatal)' app.log       # extended regex
grep -v '^#' conf                     # invert: skip comments
grep -A3 -B1 'panic' log              # 3 after, 1 before
grep -c 'Exception' app.log           # count matches
rg -t py 'def main' .                 # ripgrep, only .py files
rg -l 'pattern'                       # files with matches only

sed — stream edit

sed -n '5,10p' file               # print lines 5-10
sed -i 's/foo/bar/g' file         # in-place replace (BSD/macOS: sed -i '' ...)
sed -i.bak 's/old/new/g' file     # safer: keep .bak
sed '/^$/d' file                  # delete blank lines
sed 's/[[:space:]]*$//' file      # trim trailing whitespace

awk — column tool

awk '{print $1, $NF}' file              # first + last field
awk -F: '$3 >= 1000 {print $1}' /etc/passwd   # custom delim
awk '{sum+=$1} END {print sum}' nums    # sum column
ps aux | awk '$3 > 50.0'                # rows where CPU > 50%
awk 'NR==1 || /ERROR/' log              # header + matches

cut · sort · uniq · tr · wc

cut -d, -f1,3 file.csv            # CSV columns 1 & 3
sort -k2 -n file                  # numeric sort by col 2
sort | uniq -c | sort -rn         # frequency table (top hitters)
tr 'A-Z' 'a-z' < file             # lowercase
wc -l file                        # line count
paste a b                         # side-by-side merge
xargs -n1 -P4 -I{} curl {}        # parallel: 4 jobs

3 · Processes & System

Who's running what, and who's eating the box.

List & signal

CommandPurpose
ps auxEvery process, BSD format (CPU, MEM, START).
ps -ef --forestTree view — see parent/child.
pgrep -af nodePIDs whose cmdline matches.
pkill -9 -f myappKill by full cmdline pattern.
kill -TERM <pid>15 = polite shutdown. Default.
kill -KILL <pid>9 = uncatchable. Last resort.
kill -HUP <pid>1 = reload config (nginx, sshd).
nohup cmd &Detach from terminal; survives logout.
disown -h %1Detach existing job from shell.

Live monitors

top                  # classic
htop                 # color, scroll, tree (F5)
btop                 # modern eye-candy
iotop                # disk IO per process
iftop                # network bandwidth per host
glances              # aggregate dashboard
free -h              # RAM/swap snapshot
uptime               # load avg over 1/5/15 min
vmstat 1             # one sample/sec: cpu, io, swap
iostat -xz 1         # per-device IO stats

What's open / what's listening

ss -tulnp                       # TCP/UDP, listening, with PID (modern)
netstat -tulnp                  # legacy alias
lsof -i :8080                   # who has port 8080
lsof -p <pid>                   # files+sockets opened by pid
lsof +D /var/log                # who has files under /var/log open
fuser -v /mnt/data              # processes using a path

systemd

systemctl status nginx
systemctl start|stop|restart|reload nginx
systemctl enable --now nginx           # start now + on boot
systemctl list-units --failed
journalctl -u nginx -f                  # follow service logs
journalctl --since "10 min ago"
journalctl -p err -b                    # errors since last boot

4 · Networking — diagnose in 30s

Layer probes

CommandLayer / Purpose
ip a / ip rL3: addrs and routing table.
ping -c 4 hostL3: reachable? RTT?
traceroute host / mtr hostL3: path. mtr = continuous.
dig +short example.comDNS: A record only.
dig @8.8.8.8 MX example.comDNS: query specific server.
host -a example.comDNS: every record type.
nslookup example.comDNS: legacy but on every box.
nc -zv host 443L4: port reachable from here?
curl -I https://x.comL7: headers only.
tcpdump -i any -n port 443Packet capture on the wire.

Common debug flow

# 1. DNS resolves?
dig +short api.svc.local
# 2. Route exists?
ip route get 10.0.0.5
# 3. TCP port open from here?
nc -zv api.svc.local 443
# 4. TLS handshake works?
openssl s_client -connect api.svc.local:443 -servername api.svc.local
# 5. App layer responds?
curl -v https://api.svc.local/health

5 · Bash Scripting Essentials

The strict-mode preamble, parameter expansion, and the loops you actually use.

Strict-mode preamble

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

# -e  exit on error
# -u  fail on unset variables
# -o pipefail  fail if any pipe stage fails
# IFS  safer word-splitting (no spaces)

Variables & parameter expansion

name="alice"
echo "${name^^}"           # ALICE  (uppercase)
echo "${name,,}"           # alice  (lowercase)
echo "${name:-anon}"       # default if unset/empty
echo "${name:+set}"        # 'set' only if name has value
file="/var/log/app.log"
echo "${file##*/}"         # app.log    (basename)
echo "${file%/*}"          # /var/log   (dirname)
echo "${file%.log}.bak"    # swap extension
arr=(a b c); echo "${#arr[@]}"   # 3

Conditionals & loops

if [[ -f "$f" ]]; then echo "exists"; fi
[[ -d "$d" ]] && echo "dir"
[[ "$x" =~ ^[0-9]+$ ]] && echo "numeric"
[[ -z "$s" ]]   # empty
[[ -n "$s" ]]   # non-empty

for f in *.log; do gzip "$f"; done
for i in {1..5}; do echo $i; done
while read -r line; do echo "$line"; done < file
case "$1" in start) ... ;; stop) ... ;; *) ... ;; esac

Functions, traps, args

cleanup() { rm -f /tmp/lock; }
trap cleanup EXIT INT TERM

main() {
  local input="${1:?usage: main <input>}"
  echo "processing $input"
}
main "$@"

6 · SSH, scp, rsync

Keys & config

ssh-keygen -t ed25519 -C "you@host"           # modern, fast, small
ssh-copy-id user@host                          # push pubkey
ssh-add ~/.ssh/id_ed25519                      # load into agent

# ~/.ssh/config
Host bastion
  HostName 1.2.3.4
  User ubuntu
  IdentityFile ~/.ssh/prod_ed25519
Host prod-*
  ProxyJump bastion
  User ubuntu

Common usage

ssh -A user@host                  # forward agent (carefully)
ssh -L 8080:localhost:80 host     # local fwd: localhost:8080 → host:80
ssh -R 9000:localhost:9000 host   # reverse fwd: expose your service to host
ssh -D 1080 host                  # SOCKS proxy on :1080
ssh host 'tail -f /var/log/syslog'

scp file user@host:/path/
rsync -avhP --delete src/ user@host:/dst/    # mirror, with progress

7 · Docker — Containers & Images

90% of your daily commands. Memorize these.

Containers

CommandPurpose
docker psRunning. Add -a for stopped.
docker run --rm -it img bashInteractive, auto-cleanup on exit.
docker run -d --name api -p 8080:80 imgDetached, named, port mapped.
docker exec -it api bashShell into running container.
docker logs -f --tail 100 apiFollow last 100 lines.
docker stop api && docker rm apiStop & remove.
docker inspect apiFull JSON: env, mounts, IP, state.
docker statsLive CPU/mem per container.
docker cp api:/etc/app.conf .Copy out (or in).
docker top apiProcesses inside container.

Images

docker images
docker pull alpine:3.23
docker build -t myapp:1.0 .
docker build --target builder -t myapp:dev .   # multi-stage target
docker tag myapp:1.0 registry/me/myapp:1.0
docker push registry/me/myapp:1.0
docker rmi myapp:old
docker image prune -a                          # remove unused images
docker history myapp:1.0                       # layer breakdown
docker save myapp:1.0 | gzip > myapp.tgz       # offline transfer
gunzip -c myapp.tgz | docker load

Volumes & networks

docker volume create pgdata
docker run -v pgdata:/var/lib/postgresql/data postgres
docker run -v "$PWD":/app -w /app node:24 npm test    # bind mount
docker volume ls
docker volume prune

docker network create app-net
docker run --network app-net --name db postgres
docker run --network app-net --name api myapp     # api can resolve "db"
docker network inspect app-net

Cleanup — reclaim disk

docker system df                  # what's using space
docker system prune -a --volumes  # nuke unused images, networks, volumes
docker container prune
docker builder prune              # build cache

8 · Dockerfile Patterns

Multi-stage Node example

# syntax=docker/dockerfile:1.7

# ---- build stage ----
FROM node:24-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .
RUN npm run build

# ---- runtime stage ----
FROM node:24-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://127.0.0.1:3000/health || exit 1
CMD ["node", "dist/server.js"]

Layer-cache rules

.dockerignore

.git
node_modules
**/*.log
.env*
dist
coverage
.DS_Store

9 · docker compose

Minimal stack

# compose.yaml
services:
  api:
    build: .
    ports: ["8080:8080"]
    environment:
      DATABASE_URL: postgres://app:app@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:18-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    volumes: [pgdata:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  pgdata:

Daily commands

docker compose up -d                 # start in background
docker compose up --build api        # rebuild then up
docker compose logs -f api db
docker compose ps
docker compose exec api sh
docker compose run --rm api npm test # one-off, then remove
docker compose stop                  # stop, keep state
docker compose down                  # stop + remove containers/networks
docker compose down -v               # ALSO remove named volumes (data loss!)
docker compose config                # render effective merged config

10 · Kubernetes — kubectl

Context & namespaces

kubectl config get-contexts
kubectl config use-context prod
kubectl config set-context --current --namespace=app-prod
kubens app-prod                        # if you have kubectx/kubens
kubectl cluster-info

Inspect

CommandPurpose
kubectl get pods -A -o wideAll ns, with node + IP.
kubectl get pods -l app=apiLabel selector.
kubectl describe pod <p>Events, status, mounts.
kubectl logs -f <p> -c sidecarStream container logs.
kubectl logs <p> --previousLogs from prior crash.
kubectl exec -it <p> -- shShell in pod.
kubectl top podCPU/mem (needs metrics-server).
kubectl get events --sort-by=.lastTimestampLatest cluster events.

Apply / rollout / debug

kubectl apply -f k8s/                # apply directory
kubectl diff -f deploy.yaml          # what would change
kubectl rollout status deploy/api
kubectl rollout history deploy/api
kubectl rollout undo deploy/api      # back one revision
kubectl scale deploy/api --replicas=5
kubectl set image deploy/api api=myapp:1.4

kubectl port-forward svc/api 8080:80
kubectl cp pod:/var/log/app.log .
kubectl debug -it pod/api --image=busybox --target=api  # ephemeral container

Pod manifest skeleton

apiVersion: apps/v1
kind: Deployment
metadata: { name: api, labels: { app: api } }
spec:
  replicas: 3
  selector: { matchLabels: { app: api } }
  template:
    metadata: { labels: { app: api } }
    spec:
      containers:
      - name: api
        image: myapp:1.0
        ports: [{ containerPort: 8080 }]
        resources:
          requests: { cpu: 100m, memory: 128Mi }
          limits:   { cpu: 500m, memory: 512Mi }
        readinessProbe:
          httpGet: { path: /ready, port: 8080 }
          periodSeconds: 5
        livenessProbe:
          httpGet: { path: /health, port: 8080 }
          initialDelaySeconds: 30

11 · Git — Daily & Rescue

Daily flow

git status -sb                       # short + branch info
git switch -c feat/x                 # create+switch (modern)
git add -p                           # stage hunks interactively
git commit -m "feat: x"
git commit --amend --no-edit         # tweak last commit
git push -u origin feat/x

git pull --rebase                    # avoid merge bubbles
git fetch --all --prune              # clean tracking branches
git log --oneline --graph --decorate --all
git diff main...feat/x               # changes on feature since branch point

Stash / restore / clean

git stash push -m "wip" -u           # include untracked
git stash list
git stash pop                        # apply + drop
git restore file                     # discard worktree changes
git restore --staged file            # unstage
git clean -fd                        # remove untracked (DESTRUCTIVE)

Rewrite history (local only!)

git rebase -i HEAD~5                 # squash/reorder/edit
git rebase --onto main old-base feat # transplant range
git cherry-pick <sha>
git revert <sha>                     # safe: new commit that undoes
git rebase --onto main old-base feat — transplant a commit range

Recovery

git reflog                           # every HEAD movement (90 days)
git reset --hard HEAD@{2}            # jump back to a reflog entry
git fsck --lost-found                # dangling commits
git bisect start && git bisect bad && git bisect good v1.0
# git auto-checks out midpoints; mark good/bad until culprit found

12 · curl · jq · HTTPie

curl

curl -fsSL https://x.com/install.sh | bash
#  -f fail-on-error  -s silent  -S show-err  -L follow-redirects

curl -i https://api.x.com/v1/me                              # show headers + body
curl -H 'Authorization: Bearer $T' https://api.x.com/me
curl -X POST -H 'Content-Type: application/json' \
     -d '{"name":"alice"}' https://api.x.com/users
curl -F 'file=@./image.png' https://api.x.com/upload         # multipart
curl -o out.bin -C - https://x.com/big.bin                   # resume download
curl -w '%{http_code} %{time_total}\n' -o /dev/null -s URL   # timing only

jq — JSON surgery

curl -s api.x/users | jq '.'                       # pretty
jq '.users[] | .name'                              # extract
jq '.users[] | select(.active) | .id'              # filter
jq -r '.users[].email'                             # raw (no quotes)
jq '{name, email}'                                 # pick fields
jq '.users | length'
jq 'group_by(.role) | map({role: .[0].role, n: length})'
jq -s 'add' a.json b.json                          # slurp + merge arrays

HTTPie (friendlier)

http GET api.x.com/me Authorization:"Bearer $T"
http POST api.x.com/users name=alice age:=30      # := for non-string
http --download big.bin URL

13 · Vim & tmux — Survive Remote Boxes

Vim — bare minimum

KeysAction
i / a / oInsert before / after / new line below.
Esc or Ctrl-[Back to normal mode.
:w / :q / :wq / :q!Write / quit / write+quit / discard.
dd / yy / pDelete line / yank line / paste.
u / Ctrl-rUndo / redo.
/foo · n · NSearch forward · next · prev.
:%s/foo/bar/gcReplace all, confirm each.
gg / G / :42Top / bottom / line 42.
v · V · Ctrl-vVisual char · line · block.
ciw / ci" / ci(Change inside word / quotes / paren.

tmux — sessions that survive disconnect

tmux new -s work          # start named session
tmux ls
tmux attach -t work
# inside: prefix is Ctrl-b
#   c    new window      n / p  next / prev window
#   "    split horiz     %      split vert
#   o    next pane       arrows move between panes
#   d    detach          x      kill pane
#   [    scroll mode (q to exit)

14 · Performance & Debug

The USE checklist

Trace what a process is doing

strace -p <pid> -f -e trace=network,read,write   # syscalls
strace -c -p <pid>                                # summary table on Ctrl-C
ltrace -p <pid>                                   # library calls
perf top -p <pid>                                 # live hot functions
perf record -g -p <pid> -- sleep 30 && perf report
sudo cat /proc/<pid>/status                       # state, threads, RSS
sudo ls -l /proc/<pid>/fd                         # open file descriptors

Memory & OOM

free -h
cat /proc/meminfo | head
dmesg -T | grep -i 'killed process'      # OOM kill events
smem -k -p                                # PSS-aware per-process memory

Quick "what's slow?" recipe

uptime              # load trend
vmstat 1 5          # cpu / io / swap
iostat -xz 1 5      # disk pressure
ss -s               # socket totals
dmesg -T | tail     # kernel complaints
journalctl -p err -b | tail

15 · Package Managers — Cross-Distro

Actionapt (Debian/Ubuntu)dnf (RHEL/Fedora)pacman (Arch)brew (macOS)
refresh indexapt updatednf check-updatepacman -Syubrew update
installapt install pkgdnf install pkgpacman -S pkgbrew install pkg
removeapt remove pkgdnf remove pkgpacman -R pkgbrew uninstall pkg
upgrade allapt full-upgradednf upgradepacman -Syubrew upgrade
searchapt search foodnf search foopacman -Ss foobrew search foo
infoapt show pkgdnf info pkgpacman -Si pkgbrew info pkg
which file ownsdpkg -S /pathrpm -qf /pathpacman -Qo /pathbrew list pkg
list installedapt list --installeddnf list --installedpacman -Qbrew list

Language-level

# Python
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pipx install black                     # global CLI tools, isolated
uv pip install -r requirements.txt     # fast modern alt

# Node
npm ci                                 # reproducible from lockfile
npm run dev
pnpm install                           # fast, content-addressed
nvm use 24                             # version switch

# Go / Rust
go install github.com/x/y@latest
cargo install ripgrep

16 · SQL & Query Patterns

Joins, window functions, and the query shapes interviews drill.

Joins & Grouping

CommandPurpose
INNER JOIN b ON a.id = b.a_idRows matching in both tables
LEFT JOIN b ON a.id = b.a_idAll left rows, NULLs where no match
FULL OUTER JOIN b ON …All rows from both sides
CROSS JOIN bCartesian product of both tables
LEFT JOIN b ON … WHERE b.id IS NULLAnti-join: left rows with no match
SELECT dept, COUNT(*) … GROUP BY deptAggregate rows per group
GROUP BY dept HAVING COUNT(*) > 5Filter groups after aggregation
GROUP BY GROUPING SETS ((a),(b),())Multiple aggregation levels in one pass
COALESCE(col, 0)First non-NULL value / default

Window Functions

CommandPurpose
ROW_NUMBER() OVER (ORDER BY ts)Unique sequential rank, no ties
RANK() OVER (ORDER BY score DESC)Rank with gaps on ties
DENSE_RANK() OVER (…)Rank without gaps on ties
LAG(val, 1) OVER (ORDER BY ts)Previous row's value
LEAD(val, 1) OVER (ORDER BY ts)Next row's value
SUM(amt) OVER (ORDER BY ts)Running total (cumulative)
SUM(amt) OVER (PARTITION BY user ORDER BY ts)Running total reset per partition
AVG(x) OVER (ORDER BY ts ROWS 6 PRECEDING)7-row moving average
NTILE(4) OVER (ORDER BY score)Split rows into quartile buckets
FIRST_VALUE(x) OVER (PARTITION BY g ORDER BY ts)First value per group

Top-N Per Group & Dedup

-- Latest row per user (dedup / top-1 per group)
WITH ranked AS (
  SELECT *,
         ROW_NUMBER() OVER (PARTITION BY user_id
                            ORDER BY created_at DESC) AS rn
  FROM events
)
SELECT * FROM ranked WHERE rn = 1;

-- Same thing with QUALIFY (Snowflake / BigQuery / DuckDB)
SELECT *
FROM events
QUALIFY ROW_NUMBER() OVER (PARTITION BY user_id
                          ORDER BY created_at DESC) = 1;

CTEs, Recursion & Gaps-and-Islands

CommandPurpose
WITH cte AS (SELECT …) SELECT * FROM cteNamed subquery for readability
WITH RECURSIVE t AS (…) SELECT …Hierarchies, graph walks, sequences
EXPLAIN ANALYZE SELECT …Show plan with real row/timing stats
CREATE INDEX idx ON t (col)B-tree index to speed lookups/joins
SELECT … FROM t /*+ INDEX(t idx) */Optimizer hint (Oracle/MySQL) to force index
-- Recursive: employee org chart
WITH RECURSIVE org AS (
  SELECT id, name, manager_id, 1 AS depth
  FROM emp WHERE manager_id IS NULL
  UNION ALL
  SELECT e.id, e.name, e.manager_id, o.depth + 1
  FROM emp e JOIN org o ON e.manager_id = o.id
)
SELECT * FROM org ORDER BY depth;

-- Gaps-and-islands: collapse consecutive login days into ranges
SELECT user_id, MIN(day) AS start_day, MAX(day) AS end_day
FROM (
  SELECT user_id, day,
         day - (ROW_NUMBER() OVER (PARTITION BY user_id
                                   ORDER BY day))::int AS grp
  FROM logins
) s
GROUP BY user_id, grp
ORDER BY user_id, start_day;

17 · Cloud CLI & IaC

AWS/GCP CLI, IAM, and Terraform one-liners.

AWS CLI

CommandPurpose
aws configure ssoSet up SSO-based credentials profile
aws sts get-caller-identityShow current account, user, and ARN
aws s3 ls s3://bucket/prefix/List objects under a prefix
aws s3 sync ./dist s3://bucket --deleteMirror local dir to bucket, prune extras
aws s3 cp file s3://bucket/ --sse aws:kmsUpload with KMS encryption
aws ec2 describe-instances --filters Name=instance-state-name,Values=runningList running instances
aws ec2 start-instances --instance-ids i-0abcBoot a stopped instance
aws logs tail /aws/lambda/fn --followStream CloudWatch logs live
aws logs start-query --log-group-name … --query-string '…'Run a Logs Insights query
aws iam list-attached-role-policies --role-name rShow managed policies on a role
aws ssm start-session --target i-0abcShell into an instance without SSH

GCP & Azure CLI

CommandPurpose
gcloud auth loginAuthenticate the gcloud CLI
gcloud config set project my-projSet the active project
gcloud compute instances listList Compute Engine VMs
gsutil ls gs://bucketList objects in a GCS bucket
gcloud projects get-iam-policy my-projDump project IAM bindings
gcloud logging read 'severity>=ERROR' --limit 20Query Cloud Logging entries
az loginAuthenticate the Azure CLI
az vm list -o tableList Azure VMs as a table

IAM Policy Quick Reference

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "ReadOneBucket",
    "Effect": "Allow",
    "Action": ["s3:GetObject", "s3:ListBucket"],
    "Resource": [
      "arn:aws:s3:::my-bucket",
      "arn:aws:s3:::my-bucket/*"
    ],
    "Condition": {
      "StringEquals": { "aws:PrincipalTag/team": "data" }
    }
  }]
}

Terraform Workflow

CommandPurpose
terraform initDownload providers, configure backend
terraform fmt -recursiveCanonically format all .tf files
terraform validateCheck config for syntax/type errors
terraform plan -out tf.planPreview changes, save to a plan file
terraform apply tf.planApply a saved plan exactly
terraform apply -target=aws_s3_bucket.bApply a single resource
terraform destroy -auto-approveTear down all managed resources
terraform state listList resources tracked in state
terraform state mv a.old a.newRename/move a resource in state
terraform import aws_s3_bucket.b my-bucketBring existing infra under management
terraform output -jsonEmit outputs as machine-readable JSON
terraform workspace new stagingCreate an isolated state workspace

Ansible Ad-Hoc

CommandPurpose
ansible all -m ping -i inventory.iniConnectivity check across hosts
ansible web -m apt -a "name=nginx state=latest" -bInstall a package with become/sudo
ansible-playbook site.yml --check --diffDry-run a playbook, show changes
ansible-vault encrypt secrets.ymlEncrypt a secrets file at rest

18 · CI/CD Pipelines

GitHub Actions and GitLab CI syntax you forget under pressure.

GitHub Actions Workflow

name: ci
on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        node: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: npm
      - name: Cache build
        uses: actions/cache@v4
        with:
          path: ~/.cache
          key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
      - run: npm ci
      - run: npm test
      - name: Deploy
        if: github.ref == 'refs/heads/main'
        env:
          TOKEN: ${{ secrets.DEPLOY_TOKEN }}
        run: ./deploy.sh

GitHub Actions Reference

CommandPurpose
on: schedule: [{cron: '0 6 * * *'}]Trigger on a cron schedule
needs: [test]Run job only after another succeeds
if: ${{ failure() }}Run step only when a prior step failed
permissions: { contents: read }Scope down the GITHUB_TOKEN
uses: actions/upload-artifact@v4Persist build output between jobs
${{ vars.API_URL }}Reference a non-secret repo variable
outputs: { id: ${{ steps.s.outputs.id }} }Pass values to downstream jobs
gh run watchFollow a running workflow from the CLI

GitLab CI

stages: [build, test, deploy]

variables:
  IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build:
  stage: build
  image: docker:27
  services: [docker:27-dind]
  script:
    - docker build -t "$IMAGE" .
    - docker push "$IMAGE"

test:
  stage: test
  image: node:20
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths: [node_modules/]
  script:
    - npm ci
    - npm test
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

deploy:prod:
  stage: deploy
  script: ./deploy.sh
  environment:
    name: production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual

Common Pipeline Patterns

CommandPurpose
rules: - when: manualRequire a click to run a job (gated deploy)
needs: [build]Out-of-stage DAG dependency (GitLab)
artifacts: { paths: [dist/], expire_in: 1h }Pass build output downstream
retry: 2Auto-retry a flaky job
extends: .base-jobReuse a hidden template job

19 · Observability Stack

Prometheus, Grafana, and the ELK/log commands.

PromQL

CommandPurpose
up1 if a target is scrapeable, 0 if down
rate(http_requests_total[5m])Per-second request rate over 5m
sum by (code) (rate(requests_total[5m]))Request rate grouped by status code
increase(errors_total[1h])Total counter increase over an hour
histogram_quantile(0.95, sum by (le) (rate(latency_bucket[5m])))p95 latency from a histogram
avg_over_time(cpu_usage[10m])Average of a gauge over a window
predict_linear(disk_free[6h], 4*3600)Forecast a gauge 4h ahead
node_memory_Active_bytes / node_memory_MemTotal_bytesMemory-used ratio per node
# Error ratio > 5% of traffic, per service
(
  sum by (service) (rate(http_requests_total{code=~"5.."}[5m]))
  /
  sum by (service) (rate(http_requests_total[5m]))
) > 0.05

# p99 request latency by route
histogram_quantile(
  0.99,
  sum by (le, route) (rate(http_request_duration_seconds_bucket[5m]))
)

Grafana & Alerting

CommandPurpose
grafana-cli plugins install grafana-piechart-panelInstall a panel plugin
grafana-cli admin reset-admin-password NEWReset the admin password
curl -s localhost:9090/-/reload -XPOSTHot-reload Prometheus config
promtool check rules alerts.ymlValidate alerting rule syntax
amtool alert queryList active Alertmanager alerts

Logs: ELK, Loki & kubectl

CommandPurpose
{app="api"} |= "error" | jsonLogQL: filter Loki logs and parse JSON
rate({app="api"} |= "500" [5m])LogQL: error-line rate from logs
GET /idx/_search?q=level:ERRORElasticsearch query for error logs
logcli query '{job="nginx"}' --limit=100Query Loki from the CLI
curl localhost:9200/_cat/indices?vList Elasticsearch indices and sizes
kubectl logs -f deploy/api --tail=100Stream a deployment's logs
kubectl logs pod --previousLogs from the last crashed container
kubectl top pod -A --sort-by=memoryLive pod CPU/memory usage
kubectl top nodePer-node resource utilization

OpenTelemetry

CommandPurpose
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317Point SDK at the OTLP collector
OTEL_SERVICE_NAME=checkout-apiTag all telemetry with a service name
OTEL_TRACES_SAMPLER=parentbased_traceidratioConfigure head-based trace sampling
otelcol --config config.yamlRun the OpenTelemetry Collector