devops-roadmap
stage 04 / 16
Beginner6 lessons · ~6 min read · 4–6 weeks to practise

Programming & scripting

Automation is just code you write for machines to run

Bash for glue, Python for real automation, the data formats every tool speaks, regex for text, APIs to drive everything — and a taste of Go, the language of the cloud-native stack.

0/6 read
On this page · 6 lessons
04.01

Bash scripting

Safe scripts with `set -euo pipefail`, quoting, exit codes, and knowing when to stop using Bash.

Bash is the glue of DevOps: bootstrapping servers, wiring CI steps, and automating the boring stuff. You don't need to be a Bash wizard, but you must write scripts you can trust.

Start every serious script with a safety header:

#!/usr/bin/env bash
set -euo pipefail   # exit on error, unset vars, and failed pipes

That one line prevents a huge class of silent failures. From there the building blocks are variables (name="prod"), conditionals (if [[ -f "$file" ]]; then …), loops (for f in *.log; do …; done), and functions.

Two habits separate pros from beginners: quote your variables ("$var", always — spaces and empty values will bite you) and check exit codes instead of assuming success. Run every script through ShellCheck, which catches these bugs automatically.

backup() {
  local src="$1" dest="$2"
  tar -czf "$dest/backup-$(date +%F).tgz" "$src" && echo "backed up $src"
}
04.02

Python for automation

Enough Python to call APIs, parse JSON, and glue systems together — plus venvs and pinned dependencies.

When a task outgrows Bash — calling APIs, parsing JSON, real error handling — Python is the DevOps default. It's readable, ships everywhere, and has a library for every cloud and tool.

You only need a practical slice to be effective: variables and types, lists/dicts, for loops, functions, try/except for errors, and reading/writing files. The killer feature is the ecosystem:

  • requests to call REST APIs.
  • json / PyYAML to parse config and API responses.
  • Cloud SDKs like boto3 (AWS) to automate infrastructure.
import requests
r = requests.get("https://api.github.com/repos/kubernetes/kubernetes")
r.raise_for_status()
print(r.json()["stargazers_count"], "stars")

Two professional habits: always use a virtual environment (python -m venv .venv) so projects don't pollute each other, and pin dependencies in requirements.txt for reproducible runs.

04.03

YAML, JSON & jq

Every manifest and pipeline is YAML; every API speaks JSON. Master indentation and jq.

Configuration in DevOps is data, and that data is almost always YAML or JSON. Kubernetes manifests, CI pipelines, Docker Compose, Ansible — all YAML. API responses and Terraform state — JSON.

YAML is designed for humans: indentation defines structure (spaces only, never tabs), key: value for maps, and - for list items.

service:
  name: web
  replicas: 3
  ports:
    - 80
    - 443

The number-one YAML mistake is indentation — a single wrong space breaks the whole file. Validate with yamllint before shipping.

JSON is the machine-friendly cousin: stricter, no comments, great for APIs. Learn jq to slice JSON from the command line — it's indispensable:

curl -s api/data | jq '.items[] | .name'

Go is worth a taste later, not now: Docker, Kubernetes, and Terraform are all written in it, so reading Go helps you understand your tools and contribute to them.

04.04

Regular expressions

The dozen symbols that let you extract anything from any log, alert rule or CI filter.

Regular expressions are the pattern language for text — and DevOps is drowning in text: logs, configs, alert rules, CI filters, monitoring queries. A little regex goes an extremely long way.

The building blocks:

  • . any character · \d digit · \w word char · \s whitespace
  • * zero or more · + one or more · ? optional · {2,4} a range
  • ^ start of line · $ end of line
  • [abc] any of these · [^abc] none of these
  • (…) a capture group — the part you want to extract
  • | alternation (or)
# find IPs in a log
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log | sort | uniq -c | sort -rn

# find failed logins
grep -E 'Failed password.*from ([0-9.]+)' /var/log/auth.log

Regex shows up far beyond grep: log-parsing rules, Prometheus label matchers, Git ignore/branch filters, CI path triggers, and validation rules everywhere.

The professional's warning: regex is greedy by default (.* grabs as much as possible — use .*? to be lazy), and an over-clever regex is unmaintainable. Test them interactively (regex101.com) rather than guessing in production.

04.05

REST APIs, auth & webhooks

Methods, status codes, bearer tokens, rate limits, pagination and webhooks — how you drive every tool in the stack.

Almost everything you automate is driven through an API. Terraform, kubectl, cloud CLIs, and your monitoring dashboards are all just clients making HTTP calls. Understanding APIs turns you from a tool user into a tool builder.

REST is the dominant style: resources at URLs, manipulated with HTTP methods.

  • GET /users — list · GET /users/42 — fetch one
  • POST /users — create · PUT/PATCH /users/42 — update · DELETE /users/42 — remove

Responses carry a status code (200, 201, 404, 500) and usually a JSON body. Requests carry headers, including authentication.

Authentication is where beginners stumble. The common patterns: an API key header, a Bearer token (Authorization: Bearer <token>), or OAuth2 where you exchange credentials for a short-lived token. Tokens expire — good automation handles refresh and never hard-codes secrets.

curl -s -H "Authorization: Bearer $TOKEN" \
     https://api.example.com/v1/deployments | jq '.items[].status'

Also expect rate limits (back off and retry, don't hammer), pagination (results come in pages — follow next), and webhooks, the inverse pattern where the service calls you when an event happens (this is how CI triggers on a Git push).

04.06

A taste of Go

Docker, Kubernetes and Terraform are all written in Go. Read it to understand your tools; write it for fast single binaries.

Docker, Kubernetes, Terraform, Prometheus — the entire cloud-native stack is written in Go. You don't need to be a Go developer, but reading it lets you understand your tools, debug them, and eventually contribute.

Go was designed for exactly this world: it compiles to a single static binary with no runtime to install (which is why Go programs ship so beautifully in tiny containers), it's fast, and concurrency is built in.

package main

import "fmt"

func main() {
    services := []string{"api", "web", "worker"}
    for _, s := range services {
        fmt.Printf("deploying %s\n", s)
    }
}

The Go-isms to recognise: explicit error handling (functions return a value and an error; if err != nil { … } is everywhere), goroutines (go doWork() runs concurrently — lightweight threads) and channels for passing data between them. There are no exceptions and no classes; it's deliberately small and boring, which is a virtue at scale.

Where it pays off for you: writing a fast CLI tool, a custom Prometheus exporter, or a Kubernetes operator.

read more — go deeper ↗
practise — build these
  • $Write a Bash script that backs up a directory, rotates old backups, and exits non-zero on failure. Pass ShellCheck cleanly.
  • $Write a Python tool that calls a REST API with a token, handles pagination and rate limits, and writes a report.