Docker: "works on my machine"

Docker: "works on my machine"

Containers are one of the biggest drivers of how we serve applications today.


What is Docker?

Docker is an open source suite of PaaS (Platform as a Service) solutions for serving applications by building, deploying and managing containers.

What is a container?

According to the official Docker website

A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.

Let’s dive into this definition. They are standard software units, because their execution is isolated from the operating system, this allows it to work without conflicts from other programs, which makes it more stable and reproducible.

Container vs Virtual machine

After the previous definition, you might be thinking: “Isn’t that what a virtual machine does?”. Well, a virtual machine indeed creates isolation from the main operating system, but it does this by virtualizing other operating systems, consuming much more resources compared to containers, since they function as processes of the operating system.

Docker
App 1
nodejs
Container Engine
Operating System
Kernel
Hardware
App 2
python

How does a container work?

The container works by combining namespaces, which is a feature that allows isolation between groups of processes at a logical level, with cgroups, which is a feature that defines the consumption limits and sharing of resources by processes.

Namespaces

  • PID - Process isolation
  • NET - Isolation of network interfaces
  • IPC - Isolation of communication between processes and shared memory
  • MNT - File System Isolation / Mount Point
  • UTS - Kernel isolation (simulates another host)

Cgroups

  • blkio - Implements inbound and outbound blocking
  • acct - Group tasks using cgroups and declare the CPU usage of these groups
  • sets - Provides a mechanism for allocating CPUs and memory to a set of tasks
  • devices - Implements a cgroup to enforce restrictions on device files
  • freezer - Manages the running state of a task, pausing and running according to the system administrator’s will
  • hugetlb - Controller that allows you to adjust the usage of larger virtual memory pages, per control group
  • memory - Controller that isolates the behavior of memory, of a group of tasks, from the rest of the system
  • net_cls - Provides an interface to mark network packages with a class identifier
  • net_prio - Provides an interface that allows an administrator to dynamically configure the priority of network traffic
  • resource_counter - It should facilitate the management of resources by controllers, providing common tools for accounting

Container vs Image

Container is an image with a temporary read and write layer. This allows the same image to be reused, changing only the layer and reading and writing, which makes the container process even lighter.

Container
Read and Write Layer
Imagem

Persistence types

Bind mounts

Managed by the file system

Terminal window
docker run -it -v /volume-dk:/app ubuntu
Terminal window
docker run -it --mount type=bind,source=/home/viniciusflv/Documents/codes/app-exemplo/volume-dk,target=/app ubuntu

Volumes

Managed by docker

Terminal window
docker volume create [name]
Terminal window
docker run -it -v meu-volume:/app ubuntu
Terminal window
docker run -it --mount source=meu-volume,target=/app ubuntu

tmpfs

It is not written in the read and write layer

Terminal window
docker run -it --tmpfs=/app ubuntu
Terminal window
docker run -it --mount type=tmpfs,destination=/app ubuntu

Network communication

List networks

Terminal window
docker network ls

Bridge

Create a network channel

Create networks

Terminal window
docker network create --driver bridge [netname]

Network names

Terminal window
docker run -it --name [name] --network [netname] [image] [cmd]

None

Remove the network interface

Host

Removes network isolation from container and system

Installing docker on linux

Updating programs

Terminal window
sudo apt update

Installing dependencies

Terminal window
sudo apt install \
ca-certificates \
curl \
gnupg \
lsb-release

Downloading

Terminal window
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Adding the signing key

Terminal window
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Installing Docker CE

Terminal window
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Giving CLI execution permission to user

Terminal window
sudo usermod -aG docker $USER

Running a container

To run a container we can go to Docker Hub, which is a repository of published open source images, and search for a container. I’ll start by choosing the official Ubuntu image.

Terminal window
docker run ubuntu

Whenever you run a a container the following steps are going to happen:

no
yes
Has local image?
Run the container
Download image
Hash validation

As it was the first run you will notice that the following logs will appear at your terminal:

Terminal window
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
e96e057aae67: Already exists
Digest: sha256:4b1d0c4a2d2aaf63b37111f34eb9fa89fa1bf53dd6e4ca954d47caebca4005c2
Status: Downloaded newer image for ubuntu:latest

You may also notice that nothing happens, even if you run the command again. That’s because docker’s default behavior is to stop execution of the container if there are no processes running.

We can run a container command by declaring it in front of the image id:

Terminal window
docker run ubuntu echo Olá mundo

Listing running images and containers

Now that we’ve downloaded our first image, we can list them with the command:

Terminal window
docker images

To list running containers let’s first run bash in interactive mode:

Terminal window
docker run -it ubuntu bash

And in another terminal run the command:

Terminal window
docker ps

Deleting images and containers

Delete a container

Terminal window
docker container rm -f [container]

Delete all containers

Terminal window
docker container rm -f $(docker container list -q)

Delete an image

Terminal window
docker image rm -f [image]

Building an image

To build an image it is necessary to create a Dockerfile. In this file will be declared a series of instructions that will configure the image.

FROM

Every Dockerfile must be preceded by the FROM statement followed by the id of the parent image. It serves as basis for us to build our custom image layer.

FROM ubuntu

RUN

We can run commands inside the image through the RUN instruction. The result of these commands will be assigned to the image sequentially.

RUN echo Hello World

LABEL

Add metadata to an image.

LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"

CMD

The main purpose of the CMD instruction is to provide default arguments for the execution of an ENTRYPOINT.

CMD ["cd", "./app"]

EXPOSE

Exposes an application execution port.

EXPOSE 3000

ENV

Declares an environment variable.

ENV PORT=3000

ARG

Defines variables that users can pass in build-time with the docker build command via the --build-arg <varname>=<value> flag.

ENV PORT=3000

ADD

Copies remote or compressed files and adds to the image’s file system.

ADD hom* /mydir/

COPY

Copy local files and add to image file system.

COPY hom* /mydir/

VOLUME

Creates a disk mount point, with a specific name, and marks it as externally mounted to other volumes or containers.

VOLUME ["/data"]

USER

Instruction that creates a username (or UID), and optionally the user’s group (or GID), to be used as the default for the rest of the current stage.

USER node

WORKDIR

Instruction that declares the working directory for the RUN, CMD, ENTRYPOINT, COPY and ADD statements.

WORKDIR /path/to/workdir

ENTRYPOINT

Defines the executable container entrypoint command.

ENTRYPOINT ["npm", "run", "dev"]

ONBUILD

Instructions to be executed when the image is used as base for another build.

ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

STOPSIGNAL

Change docker’s default stop signal.

STOPSIGNAL signal

HEALTHCHECK

Instruction that tells docker how to test if the container is still functional.

HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1

SHELL

Instruction allows you to change the default shell used to run commands.

SHELL ["powershell", "-command"]

Uploading an image in docker hub?

  1. Create your Docker Hub account
npm login
  1. Use the command below to login
Terminal window
docker login -u [username]
  1. Create an image, with the name concatenating the username and the image name separated by ”/” [username]/[imagename]
Terminal window
docker build username/imagename:1.0.0
  1. Run the publish command
Terminal window
docker push username/imagename:1.0.0