User Tools

Site Tools


it-artikel:linux:how-to-install-and-configure-docker-on-ubuntu-server-20.04-and-similar

How to install and configure Docker on UBUNTU Server 20.04 (and similar)

One can find “manuals” and “how to”s for this topic everywhere, but there is always something important missing and thus you'll have to do further search and puzzle everything together. I'm not saying that my manual here is ever complete, but at least from an administrators standpoint it hopefully covers more than the average docker page on the interwebs to prevent Docker from going haywire and pulling down your host. Since we dont want it to fill up our ROOT filesystem, right?

These are my goals for this manual:

  • configure the Docker directory, where it puts its images, volumes, etc.
  • configure / limit Dockers log files (prevent haywire)
  • how to provide additional IP (external) addresses to containers, so one could run additional network services like DNS, HTTPS etc which ports may be already IN USE by services on your docker host (port collision, ports in use).
  • Modify an iptables based hostfirewall to allow Docker container access to the local network (lan) and internet

Installation and configuration:

Beside the Docker runtime itself im also going to install docker-compose , the manuals and additional “Dockerfile” syntax highlighting for vim.

  1. Enter as user ROOT to remove any old docker installation that may be around:
    aptitude install -y vim-syntax-docker
    aptitude remove -y docker.io docker.io-doc docker-compose 
    
    # add Docker.com's GPG key to APT:
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    
    # add Docker.com's APT repo to APT
    add-apt-repository \
       "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
       $(lsb_release -cs) \
       stable"
    
    # install docker-ce (community edition)
    apt-get update
    apt-get install \
        docker-ce \
        docker-ce-cli 
        
  2. Check if the Systemd Service is enabled, else enable the service, to it starts on boot time:
    systemctl status docker
    
    # prevent starting docker on boot
    systemctl disable docker
    
    # stop docker for now
    systemctl stop docker
    
  3. DO NOT START DOCKER YET! We need to configure the Docker daemon first to achieve…
    1. Change storage directory:
      1. By default Docker will put everything (Containers, Images, Volumes etc) under /var/lib/docker/, which is most likely part of your ROOT filesystem. We most likely don't want that to happen. One way how to point Docker in the right direction is to use symbolic links, another way is to add a configuration File ( /etc/docker/daemon.json ) for the Docker daemon, where we can define the default location (directory)
    2. Limiting the logging behavior of the deamon:
      1. By default the Docker daemon is unlimited in its logging capbilities. Thus its able to fill up gigabytes within seconds if something goes haywire. Better limit this to a more manageable size.
    3. Preventing Docker from messing around with IP routing (ip forwarding) and iptables (firewalld / ipf ) rules:
      1. By default Docker tries to dynamicly add and remove iptables rules/chains to the IP packet filter (hostfirewall), including a rule for enabling NAT (ip masquerading) on the packets leaving the docker0 interface etc. All this is nice on a simple stand-alone installation of Docker but is most likely to break your hostfirewall setup on your Docker host system, if in place. Thats why i prefer to disable all this and have it manually configured if required.
  4. To configure the Docker daemon we need a configuration file now. As with UBUNTU 20.04 and the official Docker installation method there is none by default. So we prepare the storage and create a config file:
    # trash everyhing at former (default) docker location and within /etc/
    rm -rv /var/lib/docker /etc/docker
    
    # prepare new destination dir/drive
    mkdir -vp /yourDataDrive/docker/
    
    # create configuration file for Docker daemon:
    cat << 'EOF' > /etc/docker/daemon.json
    {
      "ip-forward": false,
      "ip-masq": false,
      "iptables": false,
      "data-root": "/yourDataDrive/docker/",
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "10m",
        "max-file": "3"
      }  
    }
    EOF
  5. Start the Docker service:
    systemctl start docker
  6. Check if Docker is running:
    systemctl status docker
    
    docker version
    
    # pull and run a temporarily 
    # container from the default 
    # docker registry on the 
    # interwebs
    #
    docker run --rm hello-world
    
    # expect some hello world output
    
    # clean up the hello-world remains:
    #
    docker image rm hello-world
    
  7. At this point we are pretty much ready to spin up any Docker container we want… … that is until we want to run new network services as a container on our Docker host where we might already have similar services running. Like a http/httpd webserver on Port 80 or 443, or a local DNS server on port 53. Docker wont let us spin up containers that collide with these tcp/udp ports already in use. Now what ?

How to provide more IP addresses (external/LAN) to Docker containers, to avoid port collisions with local services on the Docker host:

There are times and scenarios where you might run out of free ports or get port collisions between services running on your Docker host and your Docker containers. “Well… just remap your container ports to something free on your Docker host! Whats the problem?” you might say. The Problem lays with the kind of service you may want to run. There are services and apps who REQUIRE the use of specific ports and protocols and are unwilling or just troublesome to fiddle around with it.

In my case the DNS port 53 tcp+udp on my docker host was occupied by a productive DNS server. But i wanted to run “some 3rd party app” in a container which brings (and requires) its own DNS server on port 53. My goal was to run BOTH on the SAME HOST with the SAME PORT. So i simply needed another IP address i can bind the container to.

In these rare cases you might want to add more IP addresses to your Docker host, so you can separate things a bit better and bind container and services to “unused” IP addresses and ports.

This is how i did it…

  1. Configure multiple IP addresses to your Docker hosts main (LAN) interface:
    1. :!: Watch the indentation! Its important with yaml files!
    2. In this example we are configuring 3 IPv4+IPv6 addresses to a bridge interface br0 instead to the physical network interface. Because we can. :
      cat << EOF > /etc/netplan/55-manual-net-config.yaml
      network:
        version: 2
        ethernets:
          enp1s0:
            dhcp4: false
            dhcp6: false
        bridges:
          br0:
            addresses:
            - 192.168.0.1/24
            - 192.168.0.2/24
            - 192.168.0.3/24
            - fd00:dead:beef:affe::1/64
            - fd00:dead:beef:affe::2/64
            - fd00:dead:beef:affe::3/64
            dhcp4: false
            dhcp6: false
            interfaces:
            - enp1s0
            nameservers:
              addresses:
              - 192.168.0.1
              - ::1
              search:
              - lan
      EOF
  2. Apply/activate our change:
    netplan apply
  3. Check network interface and their assigned IP addresses:
    ip addr show
  4. To run a Docker container using a specific alternative IP address and port you can do something like this now:
    docker run -ti --name nameYourContainer -p 192.168.0.2:80:80     -p 192.168.0.2:443:443    yourImage:tag 
    

Allowing Docker container to access local network and internet destinations while running an iptables based hostfirewall script on the Docker host:

Without any kind of host firewall or network firewall in place, Docker is by default allowed to access anything on your local network (and the internet) as well as services running within containers can be accessed from your local network. That might be ok for you.

However…

If you run your Docker daemon on a host with some sort of host firewall (iptables, firewalld or similar), multiple network interfaces, routing plus IP masquerading/NAT etc, Docker messes up your firewall rules and it gets complicated real quick and your Docker container might fail to access the internet or services within the container cannot be reached from your LAN. Now what ?

Well… since this highly depends on the type of firewall/script/scenario you have, my example may or may not work for you. It may be even dangerous to do it like this. But it seems to work so far for me in my experimental network environment and it did not blew up in my face just yet.

In my case my Docker host was denying, rejecting and reporting any traffic or connection attempts on any network interfaces that is unexpected. Therefore i had to allow incoming traffic on the docker0: virtual network interface (bridge), as well as allowing forwarding/routing of any traffic coming from that interface to everywhere else (local net and internet).

The iptables commands shown are just examples and are totally ripped out of context. Its just to demo the crucial part which made it fly again for me. Depending on your firewall script the possitions of the commands are crucial of course.

...
iptables -I INPUT n -i docker0 -j ACCEPT -m comment --comment "ACCEPT anything on docker0"
...
iptables -I FORWARD n -i docker0 -j ACCEPT -m comment --comment "FORWARD anything from docker0 to anywhere"
...
iptables -I FORWARD n -i $INTERNET-IF -o docker0 -m state --state RELATED,ESTABLISHED -j ACCEPT -m comment --comment "enable incoming dynamic reverse nat for docker0
...

it-artikel/linux/how-to-install-and-configure-docker-on-ubuntu-server-20.04-and-similar.txt · Last modified: 2021-04-01 19:43 by axel.werner.1973@gmail.com