# Running Docker in Docker on GKE Autopilot with gVisor Docker in Docker is an interesting workload to run on GKE in Autopilot mode, as for Autopilot you’re limited to userland programs, and Docker in Docker likes to run as root. This is a bit of a legacy from the days when docker was actually running on the host (now it’s containerd), so it “made sense” to just punch out of the container into the host’s docker environment to execute there, since, why not. Of course, this presents some security and supportability issues, as now that process is root. Fortunately there is a way to run Docker in Docker completely in userland, in a way compatible with GKE Autopilot. Here’s my test. The solution is gVisor which allows you to provide Docker in Docker an execution environment that looks like it has full access, without actually giving it full access. Best of both worlds. The gVisor project has [documented how to use Docker in Docker on GKE Autopilot](https://gvisor.dev/docs/tutorials/docker-in-gke-sandbox/), so I gave that a spin. ## Updating the cluster to support docker-in-docker with gVisor Before I could get it to work, I needed to make two changes to my Autopilot cluster: 1. Enable `NET_ADMIN` (which is disabled by default, as it grants elevated security permissions) 2. Update the cluster to 1.32 (which enables containers using gVisor to request `SYS_ADMIN` permissions) You can easily update a cluster to enable NET_ADMIN as follows. This param can also be added during creation. ```php CLUSTER_NAME=autopilot-cluster-1 LOCATION=us-central1 gcloud container clusters update $CLUSTER_NAME --workload-policies=allow-net-admin --location $LOCATION ``` I then updated my cluster in the UI to the latest version of 1.32. ## Building the builder container Now to run the example. First we need to build our docker builder container. gVisor ships with a [basic example](https://github.com/google/gvisor/tree/master/images/basic/docker) that configures docker with the right network setup. First, clone the gVisor project: ```php git clone https://github.com/google/gvisor.git cd gvisor ``` Build and push the sample. Create your own Artifact Registry Docker repo, and copy the path to set REPO with your own path. ```php REPO=us-west1-docker.pkg.dev/gke-autopilot-test/dind-test IMAGE=$REPO/docker-in-gvisor:latest docker build -t $IMAGE images/basic/docker docker push $IMAGE echo "$IMAGE pushed". ``` I put a copy in `docker.io/wdenniss/docker-in-gvisor:latest` so you don’t have to build it yourself. ## Running docker-in-docker on Autopilot Now we deploy our new container as a Pod. Replace the container image with your own if you built it in the previous step. ```javascript apiVersion: v1 kind: Pod metadata: name: docker-in-gvisor spec: runtimeClassName: gvisor dnsPolicy: "None" dnsConfig: nameservers: - "8.8.8.8" - "8.8.4.4" containers: - name: docker-in-gvisor image: docker.io/wdenniss/docker-in-gvisor:latest securityContext: capabilities: add: [AUDIT_WRITE,CHOWN,DAC_OVERRIDE,FOWNER,FSETID,KILL,MKNOD,NET_BIND_SERVICE,NET_RAW,SETFCAP,SETGID,SETPCAP,SETUID,SYS_CHROOT,SYS_PTRACE,NET_ADMIN,SYS_ADMIN] volumeMounts: - name: docker mountPath: /var/lib/docker volumes: - name: docker emptyDir: {} ``` [docker-in-gvisor.yaml](https://github.com/WilliamDenniss/autopilot-examples/blob/master/docker-in-gvisor/docker-in-gvisor.yaml) Note: it’s important to specify the nameservers here, as Docker in Docker gets configured with these nameservers. By default, GKE uses internal nameservers which Docker in Docker can’t resolve. By setting external nameservers here, we ensure Docker in Docker can resolve names. NOTE: for production, you probably don’t want to override the Pod’s nameservers, and instead configure the builder container to have whatever DNS configuration you like. I took the easy route here to get the gVisor demo docker container working without modification. ```javascript kubectl create -f https://raw.githubusercontent.com/WilliamDenniss/autopilot-examples/refs/heads/master/docker-in-gvisor/docker-in-gvisor.yaml ``` ``` kubectl exec -it docker-in-gvisor -- bash ``` Copying the commands from [gVisor’s example](https://gvisor.dev/docs/tutorials/docker-in-gke-sandbox/) to create a Dockerfile and build it, we get (you can just copy/paste this block directly): ```php mkdir whalesay && cd whalesay cat > Dockerfile <