Setting up a Windows machine to run Make is a challenge. The tools were just not developed for the Windows environment and many ports have been abandoned. So, what is a Windows developer to do when they want to contribute to projects that requires those tools? One option is to use Docker. In this post I will explain how I built an image to allow a developer to contribute to Dapr which relies on Make and other Linux tools on a Windows machine.
You will need Docker for Desktop installed with Kubernetes enabled. As of this writing I was using version 20.10.5. To follow along you will need Visual Studio Code with the Docker extension and the Remote-Containers extension.
The first step was to create a Dockerfile that contained all the code and tools required for development. Because Dapr is written in Go I decided to start with the official Golang image as my base.
After taking an inventory of all the tools I use when developing components for Dapr I decided to install kubectl, Helm, Docker Client, Dapr CLI, Delve, and golangci-lint.
# Install kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
RUN install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Install Helm
RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
RUN chmod 700 get_helm.sh
# Install Docker
RUN curl -fsSL https://get.docker.com/ | sh
# Install Dapr CLI
RUN wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash
# Install Delve for Debugging
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# Install golangci-lint
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /go/bin v1.38.0
After adding those commands to my image, I started adding the required repositories. To develop a Dapr component you need two. The core dapr repo and the components-contrib repo. The location of those repos is very important and must be under the /go/src/github.com/ folder. I create the required folders and clone the code into those folders.
Because the development on Dapr is constant the code will need to be updated before you begin your development. However, having them cloned already just requires a pull which will require less time. In the /go/src/github.com/dapr/ folder is a pull script that can be run to pull the latest code of both repositories.
With my Dockerfile complete I built and pushed my image to Docker Hub.
The next challenge was how do I connect the container to my Docker Desktop running on Windows? For the answer to this I turned to Twitter and Jeff Hollan was the first to provide a solution.
docker run -v /var/run/docker.sock:/var/run/docker.sock image:tag
Armed with that I could now run ‘docker ps’ from inside my container to list the containers running on my host. Then it dawned on me that I also need to make sure kubectl could reach Docker Desktop. I needed to get my /.kube/config file into my container. I figured why not try to map that in as well. So I added the following volume mapping to my run command.
With that in place I could now run kubectl commands from inside my container.
When you put this all together the following command gets you a complete environment ready to develop Dapr components.
docker run -dt -v /var/run/docker.sock:/var/run/docker.sock -v ~/.kube/:/root/.kube/ darquewarrior/dapr-dev
Once the container is running you can use Visual Studio Code to attach to the container.
Once connected to the container open the /go/src/github.com/dapr/ folder. There you will find the pull script, a readme file and two repos dapr and components-contrib.
While developing your component do not delete the container. You can stop it and restart it and your changes will be saved. If you delete the container before pushing your changes to GitHub all you changes will be lost.
An alternative is to mount your source from your host machine. Clone the required repositories next to each other in a common folder. Then mount that folder into the container.
docker run -dt -v /var/run/docker.sock:/var/run/docker.sock -v ~/.kube:/root/.kube -v ~/go/src/github.com/dapr:/go/src/github.com/dapr darquewarrior/dapr-dev
Note that doing this will update the permissions of all the files and mark them as changed in your repository.
If you would like to see the final Dockerfile you can view it on GitHub.
Hopefully, this image will make developing components for Dapr easier for the community and the number of components will continue to grow.