DEV Notes

Docker notes

Here are some notes and tips collected for docker during last years.

It is better to check most recent docs on docker installation on the official site as they changed several times during the last years and now they are inclined to promote Docker Desktop for every platform.

Ubuntu

Add current user to docker group (the group should be created during the installation process)

sudo usermod -aG docker $USER

Check user groups

groups $USER

Restart Docker

sudo service docker restart

Login into Docker’s group

newgrp docker

Mac OS

The --net=host option doesn’t work on macOS

There are special host names inside containers:

docker.for.mac.host.internal
docker.for.mac.localhost

This can be used, for example, to communicate between DB and backend containers as localhost isn’t available on macOS inside containers.

Docker commands

Test Docker

docker run --rm hello-world

Start a service

docker run --name SOME_NAME --env-file=ENV_FILE --net=host -dp 127.0.0.1:OUTER_PORT:INNER_PORT CONTEINER

--net=host is required if one container should reach another via localhost:port.
If -p is used without a local address like 127.0.0.0 it will be bound to 0.0.0.0 which could be a security issue.
Any network service inside a docker container must be served on 0.0.0.0 to be available outside the container.

Example: start Swagger

docker run --name swagger-editor -dp 0.0.0.0:8080:8080 swaggerapi/swagger-editor
docker ps -a --format "{{.Names}}"
doocker ps -a -q

Clean none containers

docker rmi -f $(docker images -f "dangling=true" -q)

It is possible to set LABEL inside a Dockerfile and filter by it

docker image prune --filter label=SOME_LABEL

NOTE: Consider to use docker build --rm this should remove intermediate containers

Copy files from/into a docker container

docker cp SOME_CONTEINER:/path/to/file LOCAL_FILE_NAME
docker cp LOCAL_FILE_NAME SOME_CONTEINER:/path/to/file

List volumes and clean them

docker volume ls
docker volume prune

Clean Docker images

docker rmi $(docker images | grep '^<none>' | awk '{print $3}')

Run something untrusted in Docker

docker run --rm -it -v $(PWD)/untrustedprogram:/untrustedprogram:ro ubuntu:latest

Set Docker limits for build

docker build --cpu-period=100000 --cpu-quota=50000 --memory=1024m -t $PROJECT:$VERSION -f Dockerfile .

Fix a terminal inside a container

Sometimes something could be mis-configured inside a container and things like nano can’t work. This should be executed inside the container.

export TERM=xterm

Databases oneliners

NOTE: No volumes so they all are ephemeral

PostgresSQL

docker run --name postgres -e POSTGRES_PASSWORD=password -dp 5432:5432 postgres:alpine
docker run --name postgres -e POSTGRES_PASSWORD=password -dp 127.0.0.1:5432:5432 postgres:alpine
docker exec -it postgres psql -U postgres
docker logs -f postgres

MySQL\MariaDB

docker run --name mariadb -e MYSQL_ROOT_PASSWORD=password -dp 127.0.0.1:3306:3306 mariadb
docker exec -it mariadb mysql -p
docker logs -f mariadb

Redis

docker run --name redis -dp 127.0.0.1:6379:6379 redis:alpine
docker exec -it redis redis-cli
docker logs -f redis

MongoDB

NOTE: Security isn’t enabled by default

docker run --name mongodb -dp 127.0.0.1:27017:27017 mongo
docker exec -it mongodb mongo
docker exec -it mongodb mongo admin
docker logs -f mongodb

Multi-Stage Build container example

FROM golang as compiler 
RUN CGO_ENABLED=0 go get -a -ldflags '-s' \
    github.com/adriaandejonge/helloworld FROM scratch
 
COPY --from=compiler /go/bin/helloworld . 
EXPOSE 8080
CMD ["./helloworld"]

Docker rootless and read-only container example

FROM alpine:3.15.0
# docker build -t alpine .
# docker run -it --name alpine -d alpine
# docker run -it --name alpine -d --read-only alpine
# docker exec -it alpine sh
# docker exec -it -u root alpine sh

RUN addgroup -S alpine
RUN adduser -G alpine -S alpine
USER alpine

CMD sleep infinity

Docker .gitignore

When utilizing a custom Dockerfile name, the associated .dockerignore file should be named to match the custom Dockerfile name, followed by .dockerignore. For example, if the custom Dockerfile is named Dockerfile.dev, the corresponding ignore file should be named Dockerfile.dev.dockerignore.

When initiating a Docker build with a custom Dockerfile using the -f flag (like, docker build -f Dockerfile.dev .), Docker will first search for an ignore file with the specific naming convention Dockerfile.dev.dockerignore. If this specific file is not found, Docker will then fall back to using a standard .dockerignore file if one exists in the build context. This allows for tailored exclusion rules for different build environments or purposes while maintaining a clear association between the Dockerfile and its ignore rules.

Multistage Dockerfile

FROM python:3.12 AS builder
RUN pip install -r requirements.txt
COPY . /app

FROM python:3.12 AS tests
COPY --from=builder /app /app
CMD ["pytest", "-vv"]

FROM python:3.12 AS service
COPY --from=builder /app /app
CMD ["python", "app.py"]

This way it is possible to build separate images from different stages by using the --target flag:

# Build only the 'service' stage (default, also `--target service` can be used)
docker build -t my-service .

# Build only the 'tests' stage as a separate image
docker build -t my-tests --target tests .

# Build only the 'builder' stage as a separate image
docker build -t my-builder --target builder .

NOTE: docker-compose also supports this by using target: attribute.