New Docker Goodies: Init and Watch
Tags: docker, devops, development, tutorial
Published: 2023-05-02 11:19:44

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](https://github.com/robert-nemet/docker-experiments).

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:

[![asciicast](https://asciinema.org/a/581956.svg)](https://asciinema.org/a/581956)

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:

```bash
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:

```yaml
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:

[![asciicast](https://asciinema.org/a/glvEsLPFcuSOHVU7Htjiad1vn.svg)](https://asciinema.org/a/glvEsLPFcuSOHVU7Htjiad1vn)

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](https://github.com/compose-spec/compose-spec/pull/253).

## Other noticeable stuff

With [4.19.0 release](https://docs.docker.com/desktop/release-notes/), the Docker engine and CLI are updated to [Moby 23.0](https://github.com/moby/moby/releases/tag/v23.0.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

* [Docker init](https://docs.docker.com/engine/reference/commandline/init/)
* [Docker watch](https://docs.docker.com/compose/file-watch/)