Written by the

Linux: Git, Containers and Automation for DevOps

Bridge system administration and software engineering. Master command-line Git workflows, Docker containerization, Ansible configuration management, cloud-init provisioning, kernel namespaces and cgroups, and Python automation.

14.1 Git on the Command Line

Git is the industry-standard distributed version control system. Every configuration file, infrastructure playbook, and application codebase on modern Linux servers is tracked through Git repositories.

14.1.1 Core Repository Workflow

Standard operations transition code between the working directory, the staging index, and the permanent Git history:

CommandTarget StageOperational Action
git init / git clone <url>Repository InitInitializes a new empty repository or clones an existing remote repository
git add <file> (or git add .)Staging IndexStages modified file changes into the index ready for commit packaging
git commit -m "message"Local HistoryRecords a snapshot of staged changes with an author signature and hash
git push origin <branch>Remote SyncUploads local branch commits to the remote tracking branch
git pullRemote SyncFetches remote changes and immediately merges them into the active branch

14.1.2 Branching, Merging, and Conflict Resolution

Branch Management

  • Branch Creation: git checkout -b feature/deploy:Creates and switches to a dedicated feature branch, isolating ongoing work from main.
  • Branch Inspection: git branch -v -a:Lists all local and remote tracking branches alongside latest commit hashes.
  • Branch Merging: git merge feature/deploy:Integrates changes from feature branch into active branch (fast-forward or three-way commit).
  • Conflict Resolution:Edit conflict markers (<<<<<<<, =======, >>>>>>>), stage resolved files with git add, and commit.

14.1.3 Authenticating with GitHub and GitLab over SSH

Authenticate Git operations using modern Ed25519 SSH keypairs rather than storing plaintext credentials in script files:

Git SSH key setup

Create a key, print it, test the connection, and switch the remote.

# Generate dedicated Ed25519 keypair for Git operations
ssh-keygen -t ed25519 -C "devops@example.com" -f ~/.ssh/id_ed25519_git

# Print public key to copy into GitHub/GitLab account settings
cat ~/.ssh/id_ed25519_git.pub

# Test authenticated SSH connectivity to remote provider
ssh -T git@github.com

# Configure repository remote URL to use SSH
git remote set-url origin git@github.com:organization/infra-repo.git

14.2 Docker on Linux

Docker packages applications and their complete userspace dependencies into lightweight, portable container images that run consistently across development laptops, testing clusters, and cloud production environments.

14.2.1 Installation and Container Lifecycle

Install the official Docker Engine packages and grant local user rights by adding your account to the docker group:

Docker Host Setup

  • Repository Installation:Install docker-ce, docker-ce-cli, containerd.io, and docker-compose-plugin from the official Docker repository.
  • User Group Delegation:Add current user to docker group: sudo usermod -aG docker $USER to communicate with the Docker Unix domain socket (/var/run/docker.sock) without sudo.
  • Daemon Validation:Verify installation with docker version and run the test container: docker run hello-world.

Run and inspect a container

Start nginx with a port and volume, then check it.

# Run container in background with port mapping and volume mount
docker run -d \
  --name webapp \
  -p 8080:80 \
  -v app_data:/usr/share/nginx/html \
  --restart unless-stopped \
  nginx:alpine

# Review running containers, resource usage, and streaming logs
docker ps
docker stats --no-stream
docker logs -f webapp

14.2.2 Images, Containers, Volumes, and Networks

Core Docker Primitives

  • Image vs Container:An image is an immutable read-only template with layers; a container is a running instance with an ephemeral read-write layer.
  • Named Volumes (docker volume):Persists data independently of the container lifecycle in /var/lib/docker/volumes/.
  • Bridge Networks (docker network):Provides DNS service discovery and IP isolation between sibling containers on the same host.

14.2.3 Dockerfile and Multi-Container Docker Compose

Define reproducible application runtime images with Dockerfile and orchestrate multi-container stacks using compose.yaml:

Docker Compose stack

Write compose.yaml, then validate and start it.

# Write compose.yaml
cat > compose.yaml <<'YAML'
services:
  web:
    build: .
    ports:
      - "80:8000"
    environment:
      - DB_HOST=db
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
YAML

# Validate and start the stack
docker compose config
docker compose up -d

14.3 Configuration Management with Ansible

Ansible is an agentless automation engine that configures servers over standard OpenSSH without installing background agents on target nodes. It enforces idempotency: tasks only make changes if the target node is not already in the declared state.

14.3.1 Inventory and Playbook Architecture

Structure infrastructure definitions using declarative YAML playbooks:

Ansible inventory and playbook

Write both files, then run the playbook.

# Write the inventory
cat > hosts.ini <<'INI'
[webservers]
web01.internal ansible_host=10.0.1.10
web02.internal ansible_host=10.0.1.11
INI

# Write the playbook
cat > site.yml <<'YAML'
---
- name: Configure Production Web Servers
  hosts: webservers
  become: true
  tasks:
    - name: Ensure Nginx package is installed
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: Ensure deployment user exists
      ansible.builtin.user:
        name: deployer
        shell: /bin/bash
        groups: sudo
        append: true

    - name: Ensure Nginx service is running and enabled at boot
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true
YAML

# Execute playbook against inventory
ansible-playbook -i hosts.ini site.yml

14.4 Linux in the Cloud

Deploying virtual machines across AWS EC2, Azure VMs, or Google Cloud Compute Engine relies on standardized cloud initialization mechanisms and cloud-native security controls.

14.4.1 Bootstrapping with cloud-init

Supply #cloud-config user-data during VM creation to automate initial server setup without manual intervention:

cloud-init configuration

Write the user data, then validate it.

# Write the cloud-init user data
cat > user-data.yaml <<'CLOUD'
#cloud-config
package_upgrade: true
packages:
  - curl
  - git
  - ufw

users:
  - name: devops
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1l... admin@laptop

runcmd:
  - ufw default deny incoming
  - ufw allow 22/tcp
  - ufw --force enable
CLOUD

# Validate the schema
cloud-init schema --config-file user-data.yaml

14.4.2 Securing Cloud Virtual Machines

Architecture LayerCloud Hardening PrincipleRisk Prevented
Subnet PlacementPlace databases in private subnets with NAT-only outbound routingPrevents direct internet scans from probing internal database ports
Security GroupsRestrict port 22 access to specific office VPN or bastion host IP addressesStops brute-force dictionary attacks against SSH
Metadata ProtectionEnforce AWS IMDSv2 (token-based instance metadata access)Prevents SSRF vulnerabilities from harvesting IAM role credentials
Storage EncryptionEnable KMS encryption on all root EBS and persistent volume disksProtects physical data at rest against unauthorized snapshot access

14.5 CI/CD and Kubernetes Overview

Understanding container execution requires looking beneath Docker abstractions at Linux kernel primitives.

14.5.1 Container Internals: Namespaces and cgroups

Containers are standard Linux processes isolated by two distinct kernel subsystems:

Kernel SubsystemIsolation BoundaryContainer Behavior
PID NamespaceProcess NumberingContainer sees itself as PID 1; cannot see or signal host processes
NET NamespaceNetwork StackContainer possesses dedicated virtual interface (veth), routing table, and port bindings
MNT NamespaceFilesystem MountsIsolates directory mount points; container cannot see host paths outside volume mounts
Control Groups (cgroups)Resource ThrottlingEnforces hard CPU, memory, and disk I/O quota ceilings per container

14.5.2 Kubernetes at a Glance

Kubernetes Core Components

  • Pod:The smallest deployable unit; contains one or more tightly coupled containers sharing IPC and network namespaces.
  • Deployment:Declares desired replica counts and manages automated rolling updates and rollbacks without downtime.
  • Service:Provides a stable virtual cluster IP and round-robin load balances traffic across ephemeral Pods.
  • Kubelet:Agent running on every Linux worker node communicating with container runtimes (containerd/CRI-O).

14.6 Python for Linux Admins

When bash scripts exceed 100 lines or require parsing complex nested JSON, XML, or interacting with REST APIs, Python provides standard libraries for clean system automation.

14.6.1 Virtual Environments and Administrative Scripting

Modern distributions enforce PEP 668, preventing direct pip install outside virtual environments to protect system libraries. Use venv and the standard subprocess module:

Disk space check in Python

Write the script, run it, and read the exit status.

# Write the disk check script
cat > disk_check.py <<'PY'
#!/usr/bin/env python3
import subprocess
import json
import sys

def check_disk_space(threshold_percent=80):
    """Inspect disk usage and return warning if threshold is breached."""
    cmd = ["df", "--output=pcent,target", "/"]
    result = subprocess.run(cmd, capture_output=True, text=True, check=True)
    
    # Parse second line (usage percentage)
    lines = result.stdout.strip().splitlines()
    usage_str = lines[1].split()[0].replace("%", "")
    usage = int(usage_str)
    
    if usage >= threshold_percent:
        print(f"[ALERT] Root filesystem at {usage}% capacity!")
        return 1
    
    print(f"[OK] Root filesystem nominal at {usage}%.")
    return 0

if __name__ == "__main__":
    sys.exit(check_disk_space())
PY

# Run it and show the exit code
python3 disk_check.py; echo "Exit status: $?"

14.7 Interactive Lab: Git Repositories and CLI Automation

Practice initializing a Git repository, creating commits, and running Python administrative scripts with the commands below. Press Load in Terminal to open them in the Linux terminal:

Git Repositories and CLI Automation

Load these in the terminal, then press Enter to run them.

$ git --version
$ python3 --version
$ mkdir -p /tmp/demo-repo && cd /tmp/demo-repo
$ git init
$ git status

Knowledge Check: Module 14 DevOps, Containers and Automation

1. Which Git command creates and immediately switches to a new branch?

2. Which Linux kernel technology provides process and network isolation for Docker containers?

3. Which Linux kernel technology enforces resource quotas such as CPU and memory limits on containers?

4. What communication protocol does Ansible use by default to manage remote Linux target nodes?

5. Which multi-distribution tool initializes cloud instances using user-data scripts during first boot?

6. Which built-in Python module executes shell commands and captures their output in administrative scripts?