Skip to content

Commit 03b5a9d

Browse files
committed
Added new labs
1 parent 984afec commit 03b5a9d

File tree

294 files changed

+32187
-2516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

294 files changed

+32187
-2516
lines changed

.claude/settings.local.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(cd /Users/nirg/repositories/KubernetesLabs/Labs/16-Affinity-Taint-Tolleration && python3 << 'EOF'\nwith open\\('README.md', 'r'\\) as f:\n content = f.read\\(\\)\n \nfence_count = content.count\\('```'\\)\nprint\\(f\"Total code fences: {fence_count}\"\\)\nprint\\(f\"Is even \\(properly paired\\): {fence_count % 2 == 0}\"\\)\n\n# Check last 80 lines for issues\nlines = content.split\\('\\\\n'\\)\nlast_80_lines = lines[-80:]\nfence_in_last_80 = ''.join\\(last_80_lines\\).count\\('```'\\)\nprint\\(f\"\\\\nCode fences in last 80 lines: {fence_in_last_80}\"\\)\nEOF)",
5+
"Bash(cd /Users/nirg/repositories/KubernetesLabs/Labs/16-Affinity-Taint-Tolleration && python3 << 'EOF'\nimport re\n\nwith open\\('README.md', 'r'\\) as f:\n lines = f.readlines\\(\\)\n\n# Get total lines\ntotal_lines = len\\(lines\\)\n# Get last 80 lines \\(from total-80 to total\\)\nstart_idx = max\\(0, total_lines - 80\\)\nlast_80 = lines[start_idx:]\nlast_80_content = ''.join\\(last_80\\)\n\nprint\\(f\"File has {total_lines} total lines\"\\)\nprint\\(f\"Checking lines {start_idx+1} to {total_lines}\"\\)\nprint\\(\"\\\\n=== Checking code fence balance in last 80 lines ===\"\\)\n\n# Count code fences in last 80\nfence_count = last_80_content.count\\('```'\\)\nprint\\(f\"Code fences in last 80 lines: {fence_count}\"\\)\nprint\\(f\"Properly paired: {fence_count % 2 == 0}\"\\)\n\n# Check for unclosed code blocks\nin_code = False\nline_num = start_idx + 1\nfor i, line in enumerate\\(last_80, start=start_idx+1\\):\n if line.startswith\\('```'\\):\n in_code = not in_code\n print\\(f\" Line {i}: Fence toggle \\(in_code={in_code}\\): {line.strip\\(\\)}\"\\)\n\nprint\\(f\"\\\\n=== Checking links ===\"\\)\n# Find all markdown links\nlinks = re.findall\\(r'\\\\[\\([^\\\\]]+\\)\\\\]\\\\\\(\\([^\\\\\\)]+\\)\\\\\\)', last_80_content\\)\nfor text, url in links:\n line_no = None\n for i, line in enumerate\\(last_80, start=start_idx+1\\):\n if text in line:\n line_no = i\n break\n print\\(f\" Line ~{line_no}: [{text}]\\({url}\\)\"\\)\n \n # Check relative links\n if url.startswith\\('../'\\):\n print\\(f\" -> Relative link, needs verification\"\\)\n elif url.startswith\\('http'\\):\n print\\(f\" -> External URL\"\\)\n\nEOF)",
6+
"Bash(cd /Users/nirg/repositories/KubernetesLabs/Labs/16-Affinity-Taint-Tolleration && python3 << 'EOF'\nimport re\n\nwith open\\('README.md', 'r'\\) as f:\n content = f.read\\(\\)\n lines = content.split\\('\\\\n'\\)\n\n# Get last 80 lines\nlast_80_lines = lines[-80:]\n\nprint\\(\"=== COMPREHENSIVE MARKDOWN ANALYSIS \\(Last 80 Lines\\) ===\\\\n\"\\)\n\n# 1. Check for unclosed bold\nbold_markers = 0\nfor line in last_80_lines:\n bold_count = line.count\\('**'\\)\n if bold_count % 2 != 0:\n print\\(f\"⚠ Odd number of ** in line: {line}\"\\)\n bold_markers += bold_count\n\nprint\\(f\"✓ Bold markers properly paired \\(total: {bold_markers}\\)\"\\)\n\n# 2. Check for unclosed inline code\ninline_code = 0\nfor line in last_80_lines:\n backtick_count = line.count\\('`'\\)\n # Account for code fences \\(```\\)\n code_fence_count = line.count\\('```'\\)\n single_backticks = backtick_count - \\(code_fence_count * 3\\)\n \n if single_backticks % 2 != 0 and '```' not in line:\n print\\(f\"⚠ Odd number of backticks in line: {line}\"\\)\n inline_code += single_backticks\n\nprint\\(f\"✓ Inline code markers balanced\"\\)\n\n# 3. Check heading levels\nfor i, line in enumerate\\(last_80_lines, start=len\\(lines\\)-80\\):\n if line.startswith\\('##'\\):\n print\\(f\"Line {i}: Heading: {line}\"\\)\n\n# 4. Check for markdown structure consistency\nprint\\(\"\\\\n=== Structure Check ===\"\\)\nprint\\(\"Last 80 lines structure:\"\\)\nsection_count = 0\nfor i, line in enumerate\\(last_80_lines, start=len\\(lines\\)-80\\):\n if line.startswith\\('##'\\):\n section_count += 1\n print\\(f\" Line {i}: Section: {line}\"\\)\n\n# 5. Check list consistency in Troubleshooting\nprint\\(\"\\\\n=== Troubleshooting Section Structure ===\"\\)\nin_troubleshooting = False\nlist_item_count = 0\nfor i, line in enumerate\\(last_80_lines, start=len\\(lines\\)-80\\):\n if '## Troubleshooting' in line:\n in_troubleshooting = True\n print\\(f\"Line {i}: Found Troubleshooting section\"\\)\n elif in_troubleshooting and line.startswith\\('## '\\):\n in_troubleshooting = False\n print\\(f\"Line {i}: End of Troubleshooting, found next section: {line}\"\\)\n break\n elif in_troubleshooting and line.startswith\\('- **'\\):\n list_item_count += 1\n print\\(f\" Line {i}: Troubleshooting item #{list_item_count}: {line[:50]}\"\\)\n\nprint\\(f\"\\\\nTotal troubleshooting items: {list_item_count}\"\\)\n\nEOF)"
7+
]
8+
}
9+
}

.devcontainer/Dockerfile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
FROM mcr.microsoft.com/devcontainers/base:ubuntu
2+
3+
# Install common tools
4+
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
5+
&& apt-get install -y --no-install-recommends \
6+
zsh \
7+
jq \
8+
curl \
9+
wget \
10+
bash-completion \
11+
&& apt-get clean \
12+
&& rm -rf /var/lib/apt/lists/*
13+
14+
# Install Kind
15+
ARG KIND_VERSION="v0.27.0"
16+
RUN curl -Lo /usr/local/bin/kind "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64" \
17+
&& chmod +x /usr/local/bin/kind
18+
19+
# Install k9s
20+
RUN curl -sS https://webi.sh/k9s | sh 2>/dev/null; \
21+
mv ~/.local/bin/k9s /usr/local/bin/k9s 2>/dev/null || true
22+
23+
# Install kubewall
24+
ARG KUBEWALL_VERSION="v0.0.16"
25+
RUN curl -Lo /tmp/kubewall.tar.gz \
26+
"https://github.com/kubewall/kubewall/releases/download/${KUBEWALL_VERSION}/kubewall_Linux_x86_64.tar.gz" \
27+
&& tar -xzf /tmp/kubewall.tar.gz -C /usr/local/bin kubewall \
28+
&& chmod +x /usr/local/bin/kubewall \
29+
&& rm /tmp/kubewall.tar.gz
30+
31+
# Install kubectx + kubens
32+
RUN curl -Lo /usr/local/bin/kubectx https://github.com/ahmetb/kubectx/releases/latest/download/kubectx \
33+
&& curl -Lo /usr/local/bin/kubens https://github.com/ahmetb/kubectx/releases/latest/download/kubens \
34+
&& chmod +x /usr/local/bin/kubectx /usr/local/bin/kubens
35+
36+

.devcontainer/devcontainer.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "KubernetesLabs",
3+
"build": {
4+
"dockerfile": "Dockerfile"
5+
},
6+
"features": {
7+
"ghcr.io/devcontainers/features/docker-in-docker:2": {
8+
"dockerDashComposeVersion": "v2"
9+
},
10+
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {
11+
"kubectl": "latest",
12+
"helm": "latest",
13+
"minikube": "none"
14+
},
15+
"ghcr.io/devcontainers/features/github-cli:1": {}
16+
},
17+
"postCreateCommand": "bash .devcontainer/post-create.sh",
18+
"customizations": {
19+
"vscode": {
20+
"extensions": [
21+
"ms-kubernetes-tools.vscode-kubernetes-tools",
22+
"redhat.vscode-yaml",
23+
"ms-azuretools.vscode-docker",
24+
"tim-koehler.helm-intellisense"
25+
],
26+
"settings": {
27+
"terminal.integrated.defaultProfile.linux": "zsh"
28+
}
29+
}
30+
},
31+
"hostRequirements": {
32+
"cpus": 2,
33+
"memory": "4gb",
34+
"storage": "32gb"
35+
},
36+
"remoteUser": "vscode",
37+
"forwardPorts": [
38+
8443
39+
],
40+
"portsAttributes": {
41+
"8443": {
42+
"label": "Kubewall Dashboard",
43+
"onAutoForward": "notify"
44+
}
45+
}
46+
}

.devcontainer/kind-config.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
kind: Cluster
2+
apiVersion: kind.x-k8s.io/v1alpha4
3+
nodes:
4+
- role: control-plane
5+
kubeadmConfigPatches:
6+
- |
7+
kind: InitConfiguration
8+
nodeRegistration:
9+
kubeletExtraArgs:
10+
node-labels: "ingress-ready=true"
11+
extraPortMappings:
12+
# HTTP
13+
- containerPort: 80
14+
hostPort: 80
15+
protocol: TCP
16+
# HTTPS
17+
- containerPort: 443
18+
hostPort: 443
19+
protocol: TCP
20+
# NodePort range
21+
- containerPort: 30000
22+
hostPort: 30000
23+
protocol: TCP
24+
- containerPort: 30001
25+
hostPort: 30001
26+
protocol: TCP
27+
- containerPort: 30002
28+
hostPort: 30002
29+
protocol: TCP

.devcontainer/post-create.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
# Wait for Docker-in-Docker to be ready
4+
echo "==> Waiting for Docker daemon..."
5+
for i in $(seq 1 30); do
6+
if docker info &>/dev/null; then
7+
break
8+
fi
9+
echo " Waiting for Docker... ($i/30)"
10+
sleep 2
11+
done
12+
13+
if ! docker info &>/dev/null; then
14+
echo "ERROR: Docker daemon not available. Kind cluster will not be created."
15+
echo " You can retry manually: bash .devcontainer/post-create.sh"
16+
exit 0
17+
fi
18+
19+
echo "==> Creating Kind cluster..."
20+
if kind get clusters 2>/dev/null | grep -q "^labs$"; then
21+
echo " Kind cluster 'labs' already exists, skipping."
22+
else
23+
kind create cluster \
24+
--name labs \
25+
--config .devcontainer/kind-config.yaml \
26+
--wait 120s || {
27+
echo "WARNING: Kind cluster creation failed. You can retry manually."
28+
exit 0
29+
}
30+
fi
31+
32+
echo "==> Setting kubectl context..."
33+
kubectl cluster-info --context kind-labs || true
34+
35+
echo ""
36+
echo "============================================"
37+
echo " KubernetesLabs devcontainer is ready!"
38+
echo " - Kind cluster 'labs' is running"
39+
echo " - kubectl, helm, k9s are available"
40+
echo " - Run: kubewall (dashboard on port 8443)"
41+
echo "============================================"

.github/workflows/build-devlab.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# -----------------------------------------------------------------------------
2+
# GitHub Actions Workflow: Build & Push devlab Image to GHCR
3+
#
4+
# This workflow builds the standalone devlab Docker image and pushes it to
5+
# GitHub Container Registry as a multi-arch image (amd64 + arm64).
6+
#
7+
# Main Steps:
8+
# 1. Checkout the repository.
9+
# 2. Set up QEMU for cross-platform builds.
10+
# 3. Set up Docker Buildx.
11+
# 4. Login to GitHub Container Registry.
12+
# 5. Extract image metadata (tags, labels).
13+
# 6. Build and push the multi-arch image.
14+
#
15+
# The image is published to ghcr.io/<owner>/klabs-devlab with `latest` and
16+
# `sha-<short>` tags so users can pull a ready-to-use environment.
17+
# -----------------------------------------------------------------------------
18+
19+
name: Build devlab Image
20+
21+
# Event triggers for the workflow
22+
on:
23+
push:
24+
branches:
25+
- main
26+
- master
27+
paths:
28+
- "scripts/Dockerfile.devlab"
29+
- "scripts/entrypoint-devlab.sh"
30+
workflow_dispatch:
31+
32+
# Workflow permissions
33+
permissions:
34+
contents: read
35+
packages: write
36+
37+
# Concurrency settings
38+
concurrency:
39+
cancel-in-progress: true
40+
group: "devlab-build"
41+
42+
# The build job
43+
jobs:
44+
build-and-push:
45+
runs-on: ubuntu-latest
46+
steps:
47+
- name: Checkout repository
48+
uses: actions/checkout@v4
49+
50+
- name: Set up QEMU
51+
uses: docker/setup-qemu-action@v3
52+
53+
- name: Set up Docker Buildx
54+
uses: docker/setup-buildx-action@v3
55+
56+
- name: Login to GitHub Container Registry
57+
uses: docker/login-action@v3
58+
with:
59+
registry: ghcr.io
60+
username: ${{ github.actor }}
61+
password: ${{ secrets.GITHUB_TOKEN }}
62+
63+
- name: Extract metadata (tags, labels)
64+
id: meta
65+
uses: docker/metadata-action@v5
66+
with:
67+
images: ghcr.io/${{ github.repository_owner }}/klabs-devlab
68+
tags: |
69+
type=raw,value=latest
70+
type=sha,prefix=sha-,format=short
71+
72+
- name: Build and push
73+
uses: docker/build-push-action@v6
74+
with:
75+
context: scripts/
76+
file: scripts/Dockerfile.devlab
77+
platforms: linux/amd64,linux/arm64
78+
push: true
79+
tags: ${{ steps.meta.outputs.tags }}
80+
labels: ${{ steps.meta.outputs.labels }}
81+
cache-from: type=gha
82+
cache-to: type=gha,mode=max

CLAUDE.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
KubernetesLabs is a hands-on Kubernetes learning repository with 33+ numbered labs and 7 task collections. Content is published as an MkDocs Material site at https://nirgeier.github.io/KubernetesLabs/.
8+
9+
## Build & Serve Commands
10+
11+
```bash
12+
# Install dependencies
13+
pip install -r mkdocs/requirements.txt
14+
15+
# Local development server (http://localhost:8000)
16+
mkdocs serve --config-file mkdocs.yml
17+
18+
# Build static site (output: mkdocs-site/)
19+
mkdocs build --config-file mkdocs.yml
20+
21+
# Deploy to GitHub Pages (done automatically by CI on push to main/master)
22+
mkdocs gh-deploy --force --clean --config-file mkdocs.yml --no-history
23+
```
24+
25+
## Architecture
26+
27+
### MkDocs Configuration
28+
29+
The single `mkdocs.yml` at root is a merged file containing all config sections. The modular source files live in `mkdocs/`:
30+
31+
- `01-mkdocs-site.yml` - Site metadata (name, URL, author)
32+
- `02-mkdocs-theme.yml` - Material theme settings
33+
- `03-mkdocs-extra.yml` - Social links, extra CSS/JS
34+
- `04-mkdocs-plugins.yml` - Plugins (git-committers, search, minify, print-site, include-markdown)
35+
- `05-mkdocs-extensions.yml` - Markdown extensions (pymdownx, mermaid, admonitions, tabs)
36+
- `06-mkdocs-nav.yml` - Navigation structure
37+
38+
**Important:** `docs_dir` is set to `Labs` - all content lives under `Labs/`.
39+
40+
### Lab Structure
41+
42+
Each lab follows this pattern:
43+
```
44+
Labs/XX-TopicName/
45+
├── README.md # Main lab content (this is the MkDocs page)
46+
├── manifests/ # Kubernetes YAML files
47+
├── scripts/ # Shell automation scripts
48+
└── [Dockerfile, etc.]
49+
```
50+
51+
Tasks live in `Labs/Tasks/Kubernetes-*-Tasks/README.md`.
52+
53+
### Navigation
54+
55+
When adding a new lab, update the nav in both:
56+
- `mkdocs.yml` (the merged config)
57+
- `mkdocs/06-mkdocs-nav.yml` (the source file)
58+
59+
## Lab README Conventions
60+
61+
- Start with optional YAML frontmatter
62+
- Include sections: description, "What will we learn?", "Official Documentation & References" (table format), "Prerequisites", then numbered content sections (01, 01.01, etc.)
63+
- Use `=== "macOS"` / `=== "Linux"` tab syntax for platform-specific instructions
64+
- Use admonitions (`!!! note`, `!!! warning`, `!!! tip`) for callouts
65+
- Use mermaid fenced blocks for architecture diagrams
66+
- Code blocks use language hints: `bash`, `yaml`, `go`, `dockerfile`
67+
68+
## CI/CD
69+
70+
GitHub Actions (`.github/workflows/deploy-mkdocs.yml`) deploys on push to `main` or `master`. Requires Python 3.11, full git history (`fetch-depth: 0`), and `mkdocs/requirements.txt`.
71+
72+
## Commit Message Convention
73+
74+
Follow the pattern: `labXX: <description>` (e.g., `lab32: Add EFK stack`).

0 commit comments

Comments
 (0)