Docker and Containers and Minikube! Oh My!
We ended last week with a web server that can stream our sample video to the web browser. This week we focus on Chapter 3: Publishing Your First Microservice from Bootstrapping Microservices, but with one major tweak in Section 3.
Before we get there, we need to know a tiny bit about Docker.
Section 1: A Brief Introduction to Docker
Developers frequently dealt with inconsistent development and production environments, with team members often having difficulty replicating production errors on their own machines. This was a huge drain on productivity.
Docker finally enabled a write-once, deploy anywhere workflow that enables consistent deployment of images to any machine imaginable. Containers can be created consistently from these images and run under almost any imaginable environment.
Docker images are created with Dockerfiles, a set of instructions for creating an image.
Here's a simple example:
FROM golang:1.23
ADD . /src
WORKDIR /src
ENV CGO_ENABLED=0
RUN go build -o main .
ENTRYPOINT ["/main"]
Everything prior to the ENTRYPOINT line is stored in a separate layer of the image.
Now let's move on to the next step: Docker.
Section 2: Enough theory! Let's practice Docker! (source)
Our Dockerfile will be slightly more complicated than those in the book, but only so we can minimize the size of our final Docker image.
# builder is our temporary image.
FROM golang:1.23 AS builder
# ADD allows us to place every file in the
# current directory to the /src directory of
# the golang image.
ADD . /src
# WORKDIR is the directory where our RUN and CMD
# instructions execute in.
WORKDIR /src
# Disabling CGO_ENABLED creates a larger executable,
# but strengthens our security by eliminating all
# other Linux executables.
ENV CGO_ENABLED=0
# RUN executes the given command in WORKDIR.
# Here, we build the video-streaming binary.
RUN go build -o main .
# SCRATCH is an empty image: size 0 bytes. It's extremely
# useful for improving your security.
FROM scratch
# WORKDIR says make the root directory our working directory.
WORKDIR /
# COPY allows us to copy files from either our host
# computer or, with the --from option, an earlier build stage,
# to our final image. We'll first copy the executable main,
# from the builder stage, then we'll copy the /src/videos directory.
COPY --from=builder /src/main /
COPY --from=builder /src/videos /videos
# ENTRYPOINT specifies the command that runs when this
# container starts,
ENTRYPOINT ["/main"]
With our Dockerfile defined, let's now switch to the chapter-03 directory and build our first image:
$ docker build -t video-streaming .And finally, we can instantiate a container from our image with:
$ docker run -p 3000:3000 -e PORT=3000 video-streamingWe can even run a second instance of the container bound to another local port if we so choose:
$ docker run -p 3001:3000 -e PORT=3000 video-streamingWe don't need to at this point, but this can be helpful when comparing the functionality of separate versions of the same microservice. (aka, regression tests. More on that in future weeks.)
Section 3: Publishing our microservice
This is where we deviate slightly from the book. This series will use minikube as its Kubernetes platform instead of Azure, eliminating any risk of getting "accidentally" charged while learning Kubernetes.
We won't be interacting with Kubernetes for three more weeks, but we'll demonstrate loading our images into the minikube container registry here since the book does.
For Linux and Macs:
$ minikube start
$ eval $(minikube docker-env)
$ docker build -t video-streaming .
$ minikube stopFor Powershell:
PS> minikube start
PS> minikube -p minikube docker-env --shell powershell | Invoke-Expression
PS> docker build -t video-streaming .
PS> minikube stop…and finally, for the Windows command prompt:
C:\tmp> minikube start
C:\tmp> @FOR /f "tokens=*" %i IN ('minikube -p minikube docker-env --shell cmd') DO @%i
C:\tmp> docker build -t video-streaming .
C:\tmp> minikube stop
Using minikube as our container registry is sufficient for now, as we'll primarily be using docker compose during development.
Next week: docker compose, MongoDB, S3, MinIO, and the video-storage microservice. Get excited!