Running Gitea Actions Without Docker on Kubernetes

Use containerd directly with kaniko for building images and avoid DIND complexities.

JR

2 minute read

Use containerd directly with kaniko for building images and avoid DIND complexities.

Diagnosis

Running Gitea Actions on Kubernetes without Docker typically fails due to:

  • Missing containerd integration in runners
  • Image building reliance on Docker daemon
  • Container execution expecting Docker-specific features

Repair Workflow

1. Install Kaniko for Image Building

# Deploy kaniko as a sidecar or standalone tool  
kubectl apply -f https://raw.githubusercontent.com/chainguard-forks/kaniko/master/kaniko-sa.yaml  

2. Configure Kubernetes Runner to Use Containerd

Update runner config.toml:

[[runners]]  
  name = "k8s-containerd"  
  url = "https://gitea.example.com"  
  token = "your-token"  
  executor = "kubernetes"  
  [runners.docker]  
    # Disable Docker  
    enabled = false  
  [runners.kubernetes]  
    image = "gitea/kaniko:latest"  
    containerd_socket = "/var/run/containerd/containerd.sock"  

3. Build Images with Kaniko

Example Gitea workflow step:

- name: Build container image  
  uses: docker://build  
  with:  
    context: .  
    push: true  
    tags: my-registry/my-image:latest  

4. Execute Containers Without Docker

Use nerdctl or containerd directly for runtime:

nerdctl run --rm -it my-registry/my-image:latest  

Policy Example

Restrict container execution to specific images and enforce read-only root filesystems:

apiVersion: v1  
kind: Pod  
metadata:  
  labels:  
    app: gitea-actions  
spec:  
  securityContext:  
    runAsNonRoot: true  
  containers:  
  - name: build  
    image: gitea/kaniko:latest  
    imagePullPolicy: IfNotPresent  
    securityContext:  
      readOnlyRootFilesystem: true  

Tooling

  • kaniko: Image building without Docker daemon (Chainguard fork recommended)
  • containerd: Native Kubernetes container runtime
  • nerdctl: CLI for testing container execution outside Gitea

Tradeoffs

  • kaniko: Slower than Docker due to tarball-based builds, lacks live debugging
  • containerd: Requires manual configuration for image pushing/pulling
  • No Docker: Breaks workflows relying on Docker-specific features (e.g., BuildKit)

Troubleshooting

Common Failures

  1. Containerd socket permission denied

    • Fix: Add runner service account to containerd group:
      usermod -aG containerd gitea-runner  
      
  2. Image pull errors for private registries

    • Fix: Configure containerd to use registry credentials via config.toml:
      [auths]  
        https://my-registry.com = {  
          username = "user"  
          password = "pass"  
        }  
      
  3. Kaniko failing with “no build context”

    • Fix: Ensure source code is mounted correctly in the runner pod:
      kubectl exec -it <pod-name> -- ls /workspace  
      

Prevention

  • Use init containers to validate containerd connectivity before job execution
  • Enforce image signing with Cosign for built artifacts
  • Monitor runner node disk usage (kaniko builds can bloat node storage)

Avoid DIND (Docker-in-Docker) entirely—it’s fragile, insecure, and incompatible with modern Kubernetes security defaults. Kaniko + containerd provides a cleaner, more maintainable pipeline.

Source thread: Gitea Actions runner on Kubernetes/containerd — how should I handle job containers without Docker?

comments powered by Disqus