Customizing Docker

The Docker systemd unit can be customized by overriding the unit that ships with the default Flatcar Container Linux settings or through a drop-in unit. Common use-cases for doing this are covered below.

If you want to use containerd with Kubernetes, please refer to this dedicated guide .

Use a custom containerd configuration

The default configuration file at /usr/share/containerd/config.toml is read-only. To customize it, copy the file to /etc/containerd/config.toml and make your modifications there.

Create a /etc/systemd/system/containerd.service.d/10-use-custom-config.conf unit drop-in file to select the new configuration:

[Service]
ExecStart=
ExecStart=/usr/bin/containerd

On a running system, apply the changes by executing systemctl daemon-reload && systemctl restart containerd.

Enable the remote API on a new socket

Create a file called /etc/systemd/system/docker-tcp.socket to make Docker available on a TCP socket on port 2375.

[Unit]
Description=Docker Socket for the API

[Socket]
ListenStream=2375
BindIPv6Only=both
Service=docker.service

[Install]
WantedBy=sockets.target

Then enable this new socket:

systemctl enable docker-tcp.socket
systemctl stop docker
systemctl start docker-tcp.socket
systemctl start docker

Test that it’s working:

docker -H tcp://127.0.0.1:2375 ps

Butane Config

To enable the remote API across all Flatcar Container Linux machines in a cluster, you can use a Butane Config . By providing the new socket file, Docker’s socket activation support will automatically bind to it:

variant: flatcar
version: 1.0.0
systemd:
  units:
    - name: docker-tcp.socket
      enabled: true
      contents: |
        [Unit]
        Description=Docker Socket for the API

        [Socket]
        ListenStream=2375
        BindIPv6Only=both
        Service=docker.service

        [Install]
        WantedBy=sockets.target

To keep access to the port local, replace the ListenStream configuration above with:

        [Socket]
        ListenStream=127.0.0.1:2375

Enable the remote API with TLS authentication

Docker TLS configuration consists of three parts: creating TLS keys, configuring a new systemd socket unit, and adding a systemd drop-in configuration.

TLS keys creation

Follow the instructions to create self-signed certificates and private keys. Then copy the following files into the /etc/docker directory on your Flatcar Container Linux machine and set the correct permissions:

scp ~/cfssl/{server.pem,server-key.pem,ca.pem} flatcar.example.com:
ssh [email protected]
sudo mv {server.pem,server-key.pem,ca.pem} /etc/docker/
sudo chown root:root /etc/docker/{server-key.pem,server.pem,ca.pem}
sudo chmod 0600 /etc/docker/server-key.pem

On your local host, copy the certificates into ~/.docker:

mkdir ~/.docker
chmod 700 ~/.docker
cd ~/.docker
cp -p ~/cfssl/ca.pem ca.pem
cp -p ~/cfssl/client.pem cert.pem
cp -p ~/cfssl/client-key.pem key.pem

Enable the secure remote API on a new socket

Create a file called /etc/systemd/system/docker-tls-tcp.socket to make Docker available on a secured TCP socket on port 2376.

[Unit]
Description=Docker Secured Socket for the API

[Socket]
ListenStream=2376
BindIPv6Only=both
Service=docker.service

[Install]
WantedBy=sockets.target

Then enable this new socket:

systemctl enable docker-tls-tcp.socket
systemctl stop docker
systemctl start docker-tls-tcp.socket

Drop-in configuration

Create /etc/systemd/system/docker.service.d/10-tls-verify.conf drop-in for systemd Docker service:

[Service]
Environment="DOCKER_OPTS=--tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server.pem --tlskey=/etc/docker/server-key.pem"

Reload systemd config files and restart docker service:

sudo systemctl daemon-reload
sudo systemctl restart docker.service

You can now access the Docker API through a TLS-secured connection:

docker --tlsverify -H tcp://server:2376 images
# or
docker --tlsverify -H tcp://server.example.com:2376 images

If you’ve experienced problems connecting to the remote Docker API using TLS, you can debug it with curl:

curl -v --cacert ~/.docker/ca.pem --cert ~/.docker/cert.pem --key ~/.docker/key.pem https://server:2376

Or on your Flatcar Container Linux host:

journalctl -f -u docker.service

In addition, you can export environment variables and use the Docker client without additional options:

export DOCKER_HOST=tcp://server.example.com:2376 DOCKER_TLS_VERIFY=1
docker images

Butane Config (TLS)

A Butane Config for Docker TLS authentication will look like:

variant: flatcar
version: 1.0.0
storage:
  files:
    - path: /etc/docker/ca.pem
      mode: 0644
      contents:
        inline: |
          -----BEGIN CERTIFICATE-----
          MIIFNDCCAx6gAwIBAgIBATALBgkqhkiG9w0BAQswLTEMMAoGA1UEBhMDVVNBMRAw
          DgYDVQQKEwdldGNkLWNhMQswCQYDVQQLEwJDQTAeFw0xNTA5MDIxMDExMDhaFw0y
          NTA5MDIxMDExMThaMC0xDDAKBgNVBAYTA1VTQTEQMA4GA1UEChMHZXRjZC1jYTEL
          ... ... ...
    - path: /etc/docker/server.pem
      mode: 0644
      contents:
        inline: |
          -----BEGIN CERTIFICATE-----
          MIIFajCCA1SgAwIBAgIBBTALBgkqhkiG9w0BAQswLTEMMAoGA1UEBhMDVVNBMRAw
          DgYDVQQKEwdldGNkLWNhMQswCQYDVQQLEwJDQTAeFw0xNTA5MDIxMDM3MDFaFw0y
          NTA5MDIxMDM3MDNaMEQxDDAKBgNVBAYTA1VTQTEQMA4GA1UEChMHZXRjZC1jYTEQ
          ... ... ...
    - path: /etc/docker/server-key.pem
      mode: 0644
      contents:
        inline: |
          -----BEGIN RSA PRIVATE KEY-----
          MIIJKAIBAAKCAgEA23Q4yELhNEywScrHl6+MUtbonCu59LIjpxDMAGxAHvWhWpEY
          P5vfas8KgxxNyR+U8VpIjEXvwnhwCx/CSCJc3/VtU9v011Ir0WtTrNDocb90fIr3
          YeRWq744UJpBeDHPV9opf8xFE7F74zWeTVMwtiMPKcQDzZ7XoNyJMxg1wmiMbdCj
          ... ... ...
systemd:
  units:
    - name: docker-tls-tcp.socket
      enabled: true
      contents: |
        [Unit]
        Description=Docker Secured Socket for the API

        [Socket]
        ListenStream=2376
        BindIPv6Only=both
        Service=docker.service

        [Install]
        WantedBy=sockets.target
    - name: docker.service
      dropins:
        - name: flags.conf
          contents: |
            [Service]
            Environment="DOCKER_OPTS=--tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server.pem --tlskey=/etc/docker/server-key.pem"

Use attached storage for Docker images

Docker containers can be very large and debugging a build process makes it easy to accumulate hundreds of containers. It’s advantageous to use attached storage to expand your capacity for container images. Check out the guide to mounting storage to your Flatcar Container Linux machine for an example of how to bind mount storage into /var/lib/docker.

Enabling the Docker debug flag

Set the --debug (-D) flag in the DOCKER_OPTS environment variable by using a drop-in file. For example, the following could be written to /etc/systemd/system/docker.service.d/10-debug.conf:

[Service]
Environment=DOCKER_OPTS=--debug

Now tell systemd about the new configuration and restart Docker:

systemctl daemon-reload
systemctl restart docker

To test the debug output, run a Docker command and then read the systemd journal, which should contain the debug logs:

docker ps
journalctl -u docker

Butane Config (flags)

If you need to modify a flag across many machines, you can add the flag with a Butane Config:

variant: flatcar
version: 1.0.0
systemd:
  units:
    - name: docker.service
      dropins:
        - name: flags.conf
          contents: |
            [Service]
            Environment="DOCKER_OPTS=--debug"

Use an HTTP proxy

If you’re operating in a locked down networking environment, you can specify an HTTP proxy for Docker to use via an environment variable. First, create a directory for drop-in configuration for Docker:

mkdir /etc/systemd/system/docker.service.d

Now, create a file called /etc/systemd/system/docker.service.d/http-proxy.conf that adds the environment variable:

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"

To apply the change, reload the unit and restart Docker:

systemctl daemon-reload
systemctl restart docker

Proxy environment variables can also be set system-wide .

Butane Config (proxy)

The easiest way to use this proxy on all of your machines is via a Butane Config:

variant: flatcar
version: 1.0.0
systemd:
  units:
    - name: docker.service
      enabled: true
      dropins:
        - name: 20-http-proxy.conf
          contents: |
            [Service]
            Environment="HTTP_PROXY=http://proxy.example.com:8080"

Increase ulimits

If you need to increase certain ulimits that are too low for your application by default, like memlock, you will need to modify the Docker service to increase the limit. First, create a directory for drop-in configuration for Docker:

mkdir /etc/systemd/system/docker.service.d

Now, create a file called /etc/systemd/system/docker.service.d/increase-ulimit.conf that sets the increased limit:

[Service]
LimitMEMLOCK=infinity

To apply the change, reload the unit and restart Docker:

systemctl daemon-reload
systemctl restart docker

Butane Config (ulimits)

The easiest way to use these new ulimits on all of your machines is via a Butane Config:

variant: flatcar
version: 1.0.0
systemd:
  units:
    - name: docker.service
      enabled: true
      dropins:
        - name: 30-increase-ulimit.conf
          contents: |
            [Service]
            LimitMEMLOCK=infinity

Using a dockercfg file for authentication

A JSON file .dockercfg can be created in your home directory to store authentication credentials for a public or private Docker registry.