Skip to content

Git Workflows Guide

Workflows and best practices for using k3d-local in development teams.

Overview

This guide covers common Git workflows when developing with k3d-local in a local environment. Topics include:

  • Version control for your Kubernetes manifests
  • Local configuration management
  • Branching strategies for multi-environment setups
  • CI/CD integration with k3d-local
  • Team collaboration patterns

Organizing Your Code

my-project/
├── README.md
├── .gitignore
├── .github/
│   └── workflows/
│       ├── test.yml
│       └── deploy.yml
├── k8s/
│   ├── base/
│   │   ├── namespace.yaml
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── ingress.yaml
│   ├── overlays/
│   │   ├── development/
│   │   │   ├── kustomization.yaml
│   │   │   └── ingress-patch.yaml
│   │   ├── staging/
│   │   │   ├── kustomization.yaml
│   │   │   └── replicas-patch.yaml
│   │   └── production/
│   │       └── kustomization.yaml
│   └── helm/
│       ├── Chart.yaml
│       ├── values.yaml
│       ├── values-dev.yaml
│       └── templates/
├── src/
│   └── application code
└── Makefile

.gitignore for Kubernetes Projects

# Local development
*.local
.env
.env.local
kubeconfig

# Generated files
dist/
build/
*.tar.gz

# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Kubernetes
.kube/
kubeconfig-*

# k3d
k3d-*.yaml
k3d-*.log

# Helm
charts/**/Chart.lock

Version Control Best Practices

1. Commit Kubernetes Manifests

DO: Store manifests in version control

# Good - commit manifests
git add k8s/deployment.yaml
git add k8s/service.yaml
git commit -m "feat: add kubernetes deployment"

DON'T: Exclude manifests from version control

# Bad - never do this
*.yaml >> .gitignore  # Don't!

2. Use Meaningful Commit Messages

Follow conventional commits:

feat: add postgresql database deployment
fix: correct ingress routing rules
docs: update helm deployment guide
refactor: simplify deployment structure
test: add k8s manifest validation
chore: update dependencies

Example commit:

git commit -m "feat: add prometheus monitoring

- Deploy prometheus via helm
- Configure scrape intervals
- Add grafana datasource
- Closes #123"

3. Separate Concerns

Create separate commits for different concerns:

# Separate commits for clarity
git add k8s/database/
git commit -m "feat: add postgresql database"

git add k8s/api/
git commit -m "feat: add api deployment"

git add k8s/frontend/
git commit -m "feat: add frontend deployment"

Branching Strategies

main (production)
  ↑
  └─→ release/1.0.0
      ↑
      └─→ develop (staging/integration)
          ↑
          ├─→ feature/add-database
          ├─→ feature/update-api
          └─→ bugfix/fix-ingress-routing

Workflow:

# Create feature branch from develop
git checkout develop
git pull origin develop
git checkout -b feature/add-database

# Work locally with k3d-local
make setup  # Creates local k3d cluster
kubectl apply -f k8s/database/

# Test your changes
kubectl get pods
kubectl logs deploy/postgres

# Commit and push
git add k8s/
git commit -m "feat: add postgresql deployment"
git push origin feature/add-database

# Create pull request
# ... review and merge to develop

# Later: Create release
git checkout develop
git checkout -b release/1.0.0
# ... bump versions, test

# Merge to main
git checkout main
git merge release/1.0.0
git tag v1.0.0
git push origin main --tags

# Merge back to develop
git checkout develop
git merge main

GitHub Flow (Simpler, for Smaller Teams)

main (production)
  ↑
  └─→ feature/add-database
  └─→ bugfix/fix-routing
  └─→ docs/update-guide

Workflow:

# Create feature branch from main
git checkout main
git pull origin main
git checkout -b feature/add-database

# Test locally
make setup
kubectl apply -f k8s/database/

# Commit and push
git push origin feature/add-database

# Create pull request and merge
# Then deploy from main to production

Local Development Workflow

Setting Up for Development

# Clone repository
git clone https://github.com/organization/project.git
cd project

# Create local k3d cluster
k3d-local create --with-traefik --with-apps

# Point kubectl to cluster
kubectl config use-context k3d-k3d-local

# Install dependencies
make install

# Deploy base infrastructure
kubectl create namespace development
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install postgres bitnami/postgresql -n development

Daily Development Cycle

# 1. Start a new feature
git checkout -b feature/new-feature

# 2. Make code changes
# ... edit files, create new components ...

# 3. Deploy to local k3d
kubectl apply -f k8s/

# 4. Test locally
kubectl get pods -n development
kubectl port-forward svc/myapp 3000:3000
curl http://localhost:3000

# 5. Iterate until working
# ... make more changes, deploy again ...

# 6. Commit changes
git add .
git commit -m "feat: add new feature"

# 7. Push and create PR
git push origin feature/new-feature
# Create pull request on GitHub/GitLab

Testing Before Commit

# 1. Verify manifests
kubectl apply -f k8s/ --dry-run=client

# 2. Lint YAML
yamllint k8s/

# 3. Validate configurations
kubeval k8s/*.yaml

# 4. Run full test suite
make test

# 5. Only then commit
git commit -m "feat: add feature (tested)"

Working with Helm Charts

Helm Chart Git Setup

# Initialize a new Helm chart
helm create my-app

# Version control
git init my-app
git add .
git commit -m "initial: helm chart scaffold"

# Update values for different environments
# values-dev.yaml
# values-staging.yaml
# values-prod.yaml

git add values*.yaml
git commit -m "chore: add environment-specific values"

# Deploy and test locally
helm install my-app ./my-app -f values-dev.yaml

Sharing Helm Charts

Publish to Helm Repository:

# Package chart
helm package my-app

# Upload to repository
# (depends on your Helm repo hosting)

# Tag in git
git tag helm-chart-v1.0.0
git push origin helm-chart-v1.0.0

Multi-Environment Configuration

Using Kustomize for Overlays

# Base configuration
cat > k8s/base/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- namespace.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
EOF

# Development overlay
cat > k8s/overlays/development/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
- ../../base

patchesStrategicMerge:
- deployment-patch.yaml

namePrefix: dev-
EOF

# Deploy using overlay
kubectl apply -k k8s/overlays/development

# Version control
git add k8s/
git commit -m "feat: add kustomize overlays for multi-environment"

Branch per Environment

# Development branch
git checkout develop
kubectl apply -k k8s/overlays/development

# Staging branch
git checkout staging
kubectl apply -k k8s/overlays/staging

# Main/Production branch
git checkout main
kubectl apply -k k8s/overlays/production

Continuous Integration Locally

Run CI/CD Locally

Validate changes before pushing:

# Create Makefile targets for validation
cat > Makefile << 'EOF'
.PHONY: lint test validate deploy

lint:
    yamllint k8s/
    helm lint ./my-app

test:
    kubeval k8s/base/*.yaml
    kubectl apply -f k8s/ --dry-run=client

validate:
    @echo "Running tests..."
    $(MAKE) lint
    $(MAKE) test

deploy:
    kubectl apply -f k8s/overlays/development
    kubectl rollout status deployment -n development

clean:
    kubectl delete -f k8s/overlays/development
EOF

# Run validation before commit
make validate

# Only commit if validation passes
git commit -m "feat: add new feature (validated)"

GitHub Actions Integration

Test with k3d-local in CI:

# .github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Create k3d cluster
        run: |
          curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
          k3d cluster create test-cluster

      - name: Apply manifests
        run: kubectl apply -f k8s/

      - name: Verify deployment
        run: |
          kubectl wait --for=condition=available --timeout=300s deployment -l app=myapp

      - name: Run tests
        run: |
          kubectl port-forward svc/myapp 3000:3000 &
          sleep 5
          curl http://localhost:3000

Collaboration Patterns

Code Review Process

# Developer: Create feature branch and PR
git checkout -b feature/new-feature
# ... make commits ...
git push origin feature/new-feature

# On GitHub: Create Pull Request

# Reviewer: Test locally
git fetch origin feature/new-feature
git checkout origin/feature/new-feature
k3d-local delete  # Clean previous cluster
k3d-local create --with-traefik --with-apps

# Deploy and test
kubectl apply -f k8s/

# If issues, request changes
# If approved, merge

Pair Programming with k3d-local

# Share screen and use same k3d cluster
# Both developers connect to same cluster:

# Dev 1
kubectl config get-contexts
kubectl config use-context k3d-k3d-local

# Dev 2
kubectl config get-contexts
kubectl config use-context k3d-k3d-local

# Create shared namespace and deploy
kubectl create namespace pair-session
kubectl apply -f k8s/ -n pair-session

# Track changes in git
git commit -m "feat: add feature (paired with @dev2)"

Configuration Management

Store Secrets Safely

DON'T:

# Never commit secrets!
git add secrets.yaml  # Don't!

DO:

# Use sealed-secrets or external-secrets operator
kubectl create secret generic myapp-secrets \
  --from-literal=password=secret \
  -n development

# Or use sealed-secrets CLI
# kubeseal -f secret.yaml -w sealed-secret.yaml
git add sealed-secret.yaml  # OK - encrypted

# Reference in manifests
env:
- name: PASSWORD
  valueFrom:
    secretKeyRef:
      name: myapp-secrets
      key: password

.env Files for Local Development

# .env.local (not committed)
K3D_SERVERS=1
K3D_AGENTS=2
K3D_MEMORY=4g
DATABASE_PASSWORD=localdev
API_KEY=test-key-only

# Create gitignored files
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo "kubeconfig" >> .gitignore

git add .gitignore
git commit -m "chore: add .gitignore for local secrets"

# Use in shell
source .env.local
k3d-local create --with-traefik

Troubleshooting Git + k3d-local

Sync Cluster State with Git

# Apply latest from git
git pull origin main
kubectl apply -f k8s/

# Check for drift
kubectl diff -f k8s/

# Revert to git state
git checkout k8s/
kubectl apply -f k8s/

Revert Changes

# Undo local k8s changes
kubectl rollout undo deployment/myapp -n development

# Revert git commits
git revert HEAD~1
git push origin develop

# Clean local development
k3d-local delete
k3d-local create --with-traefik --with-apps

Best Practices Summary

DO: - Commit all Kubernetes manifests to git - Use branching strategies (Git Flow or GitHub Flow) - Test locally before pushing - Write clear commit messages - Use overlays for multi-environment configs - Validate manifests in CI/CD - Encrypt secrets before committing - Tag releases in git

DON'T: - Commit .env files or secrets - Use kubectl apply without version control - Push directly to main branch - Skip validation before commit - Hardcode configuration in manifests - Forget to update documentation - Leave merged branches undeleted - Ignore code review feedback

Common Git Commands for k3d-local

# Feature branch workflow
git checkout -b feature/my-feature
kubectl apply -f k8s/
# ... test and iterate ...
git add .
git commit -m "feat: add feature"
git push origin feature/my-feature

# Sync with latest develop
git fetch origin develop
git rebase origin/develop

# Update local cluster with latest
git pull origin develop
kubectl apply -f k8s/
kubectl rollout restart deployment/myapp

# Cherry-pick a commit
git cherry-pick <commit-hash>

# View changes before commit
git diff k8s/
git add k8s/
git diff --cached k8s/

Resources

Next Steps