Recently Docker brought some new stuff that I found very useful for developers. They are still in the experimental phase but are already very useful. Try them and give your feedback to the Docker team. The code I’m using for this is available here.

Let’s start…

Init

Writing a Dockerfile when starting with a new application is tedious. Why? Because we are repeating most of the stuff over and over again. So, in the end, we reach to copy/paste solution. Of course, copy/paste needs to be modified to fit an application’s needs. I do not say that copy/paste is terrible, but with it, we miss new stuff that Docker brings to us. Even seasoned developers miss stuff. If we do not do it every day, we forget. Because of that, the Docker team brought us a new command called init. The init is not new but is still in beta. This time with more improvements.

It is a straightforward command that will create a Dockerfile for us. It asks a few questions, and based on our answers, it will create a Dockerfile. Let us see how it works:

It is effortless to use. Initially, when the Docker team introduced it, only Go was supported. With the latest release(docker desktop 4.19.0 and docker engine v23.0.5) docker init supports NodeJS and Python, too. I’m sure that they will add more languages in the future.

If you inspect the Dockerfile, you will see that it tries to be simple but also includes all the best practices when writing a Dockerfile. It will try to use cache and multi-stage builds. You can go with generated Dockerfile as is. I prefer to modify it a bit. I suggest you compare my Dockerfile version with generated one. I like Google’s distroless images. In my example, I’m also serving static files, so I need to add them to Dockerfile.

Watch

If you look at the compose.yaml file, you will see nothing exciting. Nothing new or fancy. But there is something new.

When you are working with docker compose and want to run your changes, you need to rebuild the image. So, every time you do something like this:

docker compose -f <compose file> up --detach --build <service name>

But what if you do not need to do it anymore? What if docker compose can do it for you? Well, it can. And it can do things to rebuild your app only when needed or to update static files. In my example, I have a Go server that serves one static file. When I change the code, I need to rebuild the image. But when I change static files, I want to be updated. See:

services:
  server:
    build:
      context: .
      target: final
    ports:
      - 8080:8080
    x-develop:
      watch:
      - path: ./go.mod
        action: rebuild
      - path: ./main.go
        action: rebuild
      - path: ./static/
        action: sync
        target: /app/static/

The section under x-develop with the name watch does all the magic. That is an experimental feature. It has two actions that can be used: rebuild and sync. The rebuild will rebuild the image, and the sync will sync files from the host to the container.

In the example above, I instruct docker compose to watch for the changes in the go.mod and main.go files and rebuild the image when they change. While if there are any changes in a directory with the name static(notice the trailing slash), sync them to the container. The target specifies where to sync files in the container. In my case, I want to sync them to the /app/static/ directory.

As this feature is experimental, it will not work if you just run docker compose up -d. First, run docker compose up -d, and run docker compose alpha watch when all containers are up and running. That will start watching for changes. If you want to stop watching, press Ctrl+C. Let’s see this in action:

Initially, I built and ran a container with docker compose up -d. Then I run docker compose alpha watch, and instruct docker compose to watch for changes. When I modify index.html or main.css, they are synced with the container. When I modify main.go or go.mod the image is rebuilt, and the container is restarted. Try it out yourself.

If you find this helpful feature, please leave your feedback and suggestions here.

Other noticeable stuff

With 4.19.0 release, the Docker engine and CLI are updated to Moby 23.0. That brings a lot of new stuff. One of the things that can be confusing on start is that docker build is now an alias for docker buildx build. The reason is that Buildx and BuildKit are default builders on Linux and OSX. You will notice differences when building images. You’ll see switching blue and white lines in the short demos above. White lines are tasks in progress, while blue ones are completed tasks. As well you’ll see that Buildx is trying to run tasks in parallel.

Enjoy!

References