Docker basics

Setting up Portainer (Docker web frontend and container manager)

Create persistent volume in local root docker install

docker volume create portainer_data

The following command will :

  • Pull "portainer/portainer-ce:latest" image in local root docker
  • Container publishes ports 9443 and 8000 ; docker host forward them
  • Always restart with docker
  • -v to map volumes host_volume:container_volume
$ sudo docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

Portainer is now up and running at https://localhost:9443

Tips

Listing images is as simple as running the following :

$ sudo docker images

Images are stored in local root docker install, default is /var/lib/docker/overlay2

Docker is conservative by default ; one has to "prune" unused stuff using the prune option

$ docker image prune
$ docker network prune
$ docker volume prune

Or, to delete all unused resources :

$ docker system prune

To list containers and their status :

$ sudo docker ps

A Dockerfile is used to build custom images
One can use it with compose.yml and the $ docker-compose command

To build the multi container app configured in ./compose.yml

$ docker-compose build

Finally, to run specified <service_name> in a new container using options specified in ./compose.yml

$ docker-compose run --rm --service-ports <service_name>

--rm removes the container on exit
--service-ports uses ports defined in the service configuration in the compose file

Sample Dockerfile

FROM ruby:latest #--> pulls ruby latest image from dockerhub

WORKDIR /home/app #--> image working directory can be anything

ENV PORT 3000 #--> sets up env var "PORT" inside the container to be "3000"

EXPOSE $PORT #--> expose container's "PORT" env var to the docker host

RUN gem install rails bundler #--> run arbitrary commands to set up env as wished
RUN gem install rails
RUN apt-get update -qq && apt-get install -y nodejs

ENTRYPOINT [ "/bin/bash" ] #--> command that gets executed when using docker run <this_image_container>

Sample compose.yml

services:
  rails_dev: #--> sets up a service called "rails_dev"
    build: . #--> when running docker-compose build use "." as the filepath where to look for the Dockerfile
    container_name: rails_container #--> the container name
    ports:
      - "3000:3000" #--> exposing ports host:container, default ip is 0.0.0.0, can use "127.0.0.1:3000:3000"
    volumes:
      - ./:/home/app #--> map volumes host:container

💡 Note
A Dockerfile is used to describe and build an image.
A docker compose file is used to describe and build a container and its associated services.

Registry

Docker pulls images from what's called a registry (dockerhub @docker.io by default)

# shortcut for "docker pull docker.io/library/<image_name>"
$ docker pull <image_name>

# one can run its own registry using the official image called registry
$ docker run -d -p 5000:5000 --restart always --name registry registry:2

# tags local <image_name> with the tag "myfirstimage" in registry @localhost:5000
$ docker image tag <image_name> localhost:5000/myfirstimage

# push image with tag "myfirstimage" to registry @localhost:5000
$ docker push localhost:5000/myfirstimage

✅ Why is it cool?
One can integrate its own registry in a CI/CD workflow

commit -> git hooks or something (quality check) -> build process is triggered in CI system (automated tests) -> build succeed? -> push new image to registry and notify -> auto deploy on a staging env or simply notify other systems of the new image being available

This streamlines build process, reduces codebase discrepancy between devs and make maintenance easier for multiple versions of the same application.
Also, allows image distribution in an isolated network which is a nice privacy bonus to avoid leak of critical corporate information / leak of product intelligence.

Changing docker root directory

Running out of disk space on my /, I had to move my docker root directory in order to be able to create new volumes.

One can achieve this doing the following :

  1. Checking the current default docker directory
$ sudo docker info
  1. Stopping the docker daemon, its service AND its socket (sockets are used for triggering units, reloading confs etc.)
$ sudo systemctl stop docker.service
$ sudo systemctl stop docker.socket
$ sudo systemctl status docker
$ sudo systemctl status docker.socket
  1. Make a backup of the current docker configuration
$ sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.old
  1. Edit the data-root option
$ sudo vi /etc/docker/daemon.json
{
  "data-root": "/new/path/to/docker-root/"
}
  1. Move old content
    The previous files contained in the docker root won't magically appear in the new one though.
    One has to manually copy or rsync old content in the new directory.
$ sudo rsync -aP /var/lib/docker/ "/path/to/your/new/docker-root"

or

$ sudo cp -rp /var/lib/docker/* "/path/to/your/new/docker-root/"

or using symbolic links

$ ls -al docker-root/
$ ln -s /var/lib/docker/* /path/to/your/new/docker-root/
  1. Restart the docker daemon
$ systemctl restart docker
  1. Check that the newly defined path has been updated
$ docker info