• Martin Thoma
  • Home
  • Categories
  • Tags
  • Archives
  • Support me

Docker

Contents

  • Glossary
  • Context
    • Containers vs Virtual Machines
    • Alternatives
  • Using Docker
    • Dockerfile
    • Using a Dockerfile
    • Commands
    • Volumes
    • docker-compose.yml
    • Cleanup
  • See also

Docker is a tool which allows developers to make deployment of their software easier.

Imagine you have a web service. Then you usually not only have your own software, but you built it with other libraries. You run it on a web server. The server needs some configuration, exposes some ports, reads and writes data. Being a good developer, you identified different components which can be built (and scaled) independently (aka microservices). They have a way to talk with each other and they need to run in order to make the service work. As you are the developer, you know what you need. But you might not be the one who deploys the software. Hence you have to write documentation about it.

And you can create a (Docker) container.

Glossary

Image
An image is an immutable file which contains the application code, the operating system, the required software. They are created with docker build. Images can be stored in a registry such as hub.docker.com. An image is defined using a Dockerfile. Typically, an image is built on another image.
You can list images on your machine with docker images.
Container
A virtual operating system. It is an instance of an image. A container is created with docker run. A methaphor used by paislee is that an image is a class and a container is an object. They encapsulate the environment in which the application runs.
docker ps -a lists all containers - running and stopped.
Docker Compose
A tool for defining and running multi-container applications.
Docker Swarm
A tool to deploy containers in a cluster. Similar to Kubernetes.
Kubernetes
A tool to deploy containers in a cluster. Similar to Docker Swarm.

Context

Containers vs Virtual Machines

  • Resource sharing / isolation: Docker containers share resources. A docker container is similar to a host process, hence the memory / CPU scheduling will be handled by the host for Docker. Docker is less isolated than a VM. Docker containers use less disk space and less memory.
  • Startup time: A VM takes minutes to start, Docker takes seconds to start
  • Kernel: Docker containers share the same kernel (the host kernel) whereas each virtual machine has its own kernel.

Alternatives

Although Docker seems to be by far the most common container tool, there are alternatives:

  • Rocket
  • LXD
  • Flockport

And there are VMs:

  • VirtualBox
  • VMware Workstation

Using Docker

First, install Docker.

Dockerfile

A Dockerfile defines an image. It is a simple text file which could look as follows:

FROM ubuntu:latest
LABEL maintainer="[email protected]"

# Settings for the local user
ENV APP_USER docker
ENV APP_USER_UID 9999
ENV APP_USER_GROUP docker
ENV APP_USER_GROUP_GID 4711

# Install and update software
RUN apt-get update -y
RUN apt-get install -y python-pip python-dev build-essential
RUN apt-get upgrade -y

# Copy projects code
COPY . /opt/app
WORKDIR /opt/app
RUN pip install -r requirements.txt --no-cache-dir

# Create user
RUN groupadd --gid ${APP_USER_GROUP_GID} ${APP_USER_GROUP}
RUN useradd --uid ${APP_USER_UID} --create-home -g ${APP_USER_GROUP} ${APP_USER}
RUN chown -R $APP_USER:$APP_USER_GROUP /opt/app

# Start app
USER docker
RUN mkdir -p /opt/app/uploads
ENTRYPOINT ["python"]
CMD ["app.py"]

Let's go through it:

  • FROM defines on which base image we built our image. We add another layer to that one.
  • LABEL: Add metadata in a key=value based fashion to the image.
  • RUN <command>: Execute this.
  • COPY <src> <dest>: Copy files from src on the host to dest in the container.
  • WORKDIR /abs/path/to/workdir: Work directory for and RUN, CMD, ENTRYPOINT instruction that follows
  • ENTRYPOINT ["executable", "param1", "param2"]: Run this when the Docker container is started.
  • CMD ["executable","param1","param2"]: The command is to run via the entrypoint.

You might see ENV DEBIAN_FRONTEND noninteractive in a couple of Dockerfiles, but there is a reason against it.

See also: What is pip's --no-cache-dir good for?.

Using a Dockerfile

Build the image:

# docker build -t a_tag_you_like .

Run the image in a container:

# docker run a_tag_you_like

Commands

Docker needs to be run in super-user mode. I indicate that with #. You can run sudo su in order to run all subsequent commands as a superuser.

List all images:

# docker image ls

List all running containers:

# docker container ls

Go into an interactive (-i) bash in a pseudo-tty (-t) in a container with ID 4f7d3f0763ad:

# docker exec -it 4f7d3f0763ad bash

Volumes

If you copy the code directly into the image, you need to rebuild the image every time you make a change to the code. In order to prevent this, you can use volumes. There are two types of volumes:

  1. Persist and share data between containers
  2. Share folders between host and containers

List volumes:

# docker volume ls

Remove volumes:

# docker volume rm <volume name>

docker-compose.yml

The docker-compose.yml is a YAML file which defines multi-container applications. It looks like this:

version: '3'  # Version number of the docker-compose file format
services:
  web:
    build: .
    command: app.py
    ports:
     - "8082:5000"
    volumes:
     - .:/opt/app  # enables hot code reloading
     - uploads:/opt/app/uploads  # for data persistance (<volume name>:<abs path in container>)
    links:
     - db
    hostname: myappserver
    environment:
    - MYSQL_ROOT_PASSWORD=p@ssw0rd123
    - MYSQL_DATABASE=flask_db
    - MYSQL_HOST=db
    - MYSQL_PORT=3306
    depends_on:
    - db
  db:
    image: mysql
    ports:
    - "3307:3306"
    environment:
    - MYSQL_ROOT_PASSWORD=p@ssw0rd123
    - MYSQL_DATABASE=flask_db
    - MYSQL_HOST=mysqlserver
    volumes:
      - ./flask_db.sql:/docker-entrypoint-initdb.d/flask_db.sql
volumes:
    uploads:
        driver: local

Start it with docker-compose up.

The host name of each service is the name of the service itself.

You can find the data persistance volume with:

# docker volumes ls
DRIVER              VOLUME NAME
local               db6caef4eae28832f35af0951e95ae77d6c29189a793300f5aa9523cd25af362
local               flaskmysqldockerized_uploads

And you can find the path on the host with

# docker volume inspect flaskmysqldockerized_uploads
[
    {
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "flaskmysqldockerized",
            "com.docker.compose.volume": "uploads"
        },
        "Mountpoint": "/var/lib/docker/volumes/flaskmysqldockerized_uploads/_data",
        "Name": "flaskmysqldockerized_uploads",
        "Options": {},
        "Scope": "local"
    }
]

Cleanup

Kill all running containers:

# docker kill $(docker ps -q)

Delete all stopped containers

# docker rm $(docker ps -a -q)

Delete all images

# docker rmi $(docker images -q)

Remove unused data

# docker system prune

See also

  • Docker.com
    • Dockerfile reference
    • Compose file version 3 reference
  • StackOverflow (docker tag)
    • Docker image vs container
    • How is Docker different from a normal virtual machine?
    • What is the difference between CMD and ENTRYPOINT in a Dockerfile?
  • Docker Clustering Tools Compared: Kubernetes vs Docker Swarm
  • github.com/MartinThoma/flask_mysql_dockerized: A minimal example how to use a database and a webserver with docker-compose.
  • Itamar Turner-Trauring: The best Docker base image for your Python application, August 2019.

Published

Jul 22, 2017
by Martin Thoma

Category

Code

Tags

  • Deployment 1
  • Docker 3

Contact

  • Martin Thoma - A blog about Code, the Web and Cyberculture
  • E-mail subscription
  • RSS-Feed
  • Privacy/Datenschutzerklärung
  • Impressum
  • Powered by Pelican. Theme: Elegant by Talha Mansoor