DB-유

Installing Docker CE on Ubuntu 18.04

· linux, docker, ubuntu

Ubuntu's docker.io package lags several releases behind, and its packaging doesn't match what Docker's own documentation assumes. I got tired of "works in the docs, not on my box", so on anything I plan to keep I use Docker CE from Docker's apt repository (18.09 right now). After that, upgrades are just apt upgrade.

Below: Docker CE and docker-compose on Ubuntu 18.04 (64-bit, sudo user, outbound HTTPS to download.docker.com), non-root access, and a few daemon defaults before the first container runs.

Remove old versions

If the machine ever had the distribution packages, remove them first so the two do not conflict:

sudo apt remove -y docker docker-engine docker.io containerd runc

It is fine if none of them are installed; apt just says so. Images and containers under /var/lib/docker are left in place.

Add Docker's apt repository

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88

The fingerprint output should end in 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88. Then add the stable channel for your architecture and release:

sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

lsb_release -cs expands to bionic on 18.04.

Install Docker CE

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io

The service is enabled and started by the package. Check:

sudo systemctl status docker
sudo docker version

The client and server should both report 18.09.x. If you need to stay on a specific version, list what is available and pin it:

apt-cache madison docker-ce
sudo apt install -y docker-ce=5:18.09.2~3-0~ubuntu-bionic docker-ce-cli=5:18.09.2~3-0~ubuntu-bionic containerd.io
sudo apt-mark hold docker-ce docker-ce-cli

Running docker without sudo

The package creates a docker group. Members can talk to the daemon socket, which is root on the host for all practical purposes, so I only add accounts I'd also trust with sudo.

sudo usermod -aG docker $USER

Log out and back in for the group to take effect, then docker ps should work without sudo.

Daemon defaults

I put these in /etc/docker/daemon.json on every host before running anything: log rotation, because the default json-file driver grows without limit (a chatty container filled a disk on me once), and the overlay2 storage driver, already the default on 18.04 but nice to see written down.

sudo nano /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}
sudo systemctl restart docker
docker info | grep -E 'Storage Driver|Logging Driver'

docker-compose

docker-compose is a separate program shipped as a single binary. Ubuntu's packaged version is older than what current Compose files expect, so I fetch the release from GitHub:

sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" \
  -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose version

Smoke test

docker run --rm hello-world

You want Hello from Docker!. Then something with a port, to check that publishing and DNS inside the container work:

docker run -d --name web-test -p 8080:80 nginx:1.15-alpine
curl -I http://localhost:8080
docker rm -f web-test

If it misbehaves

  • Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock. Your user is not in the docker group yet, or you have not logged out since being added. id -nG shows the effective groups of the current session.
  • E: The repository 'https://download.docker.com/linux/ubuntu bionic Release' does not have a Release file. Usually a typo in the add-apt-repository line, or arch=amd64 on an ARM machine. Check /etc/apt/sources.list.d/ for the generated entry.
  • Containers cannot resolve DNS. The daemon copies the host's /etc/resolv.conf into containers, and on 18.04 that points at 127.0.0.53 (systemd-resolved), which Docker detects and replaces with Google's servers. If your network blocks those, set "dns": ["10.0.0.2"] in daemon.json.
  • ufw rules are bypassed by published ports. Docker manages its own iptables chains. Publish only to localhost (-p 127.0.0.1:8080:80) when a service should not be reachable from outside, and put a reverse proxy in front.

I keep daemon.json in configuration management now, so no host starts without log rotation.