Basics
Examples using public docker images
You can get the list of public docker images here: https://hub.docker.com/search
Very simple example running a specific python console from a docker image:
docker run -it --rm python:3.13-bookworm python
Note
-it
is used to map a port from the host machine to a port inside the Docker container.
-rm
is used to automatically remove the container when it exits.
Below is a simple example using basics docker features to start a postgresql database server. A pgadmin docker image is also used to connect to the database.
Creating/Running the database server:
docker run -d \
--name postgres-container-name \
-p 5432:5432 \
-e POSTGRES_USER=mycustomuser \
-e POSTGRES_PASSWORD=mysecretpassword \
-e POSTGRES_DB=mycustomdatabase \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v /custom/mount:/var/lib/postgresql/data \
postgres
Note
-p
is used to map a port from the host machine to a port inside the Docker container.Here, it allows us to access the database from HOST using the URL
localhost:5432
.-e
is used to set environment variables inside a Docker container.Here, we use it to setup database configuration such as user, password, database name and the path where to store the database data.
-v
is used to mount a volume or a bind mount between the host machine and the Docker container.Here, we use it to keep the database data (persistent data) even when the container is stopped or deleted.
Note
Docker will pull the image automatically if it doesn’t exist locally.
Note
Container run by default in bridge
network mode. You can run it in host
by using the --network host
argument.
If you have psql
installed on your HOST machine, you can use the following command to access the database:
psql -h localhost -U mycustomuser -d mycustomdatabase
Runing a pgadmin
docker image to access the database:
docker run \
--network host \
-e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' \
-e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' \
-d dpage/pgadmin4
You can now access pgadmin in your browser using the URL: http://localhost:80
, enter the fake email/password and add a new server using host localhost
and port 5432
and the database credentials set when running the postgres container.
Note
We started pgadmin
in host
network mode in order to access the database using localhost
, if you prefer to start it in bridge
mode, you’ll need to map port 80
when running the docker pgadmin container, you’ll also need to enter the postgres
container IP adress instead of localhost
(see the command below to get the IP adress of a running docker container)
Dockerfile: Build your custom image
Let’s consider a python project with the following structure:
.
├── Dockerfile
└── print_and_save_message.py
With print_and_save_message.py
content being:
import argparse
import os
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Print Something")
parser.add_argument("message", type=str, help="Message to print")
parser.add_argument("--output", type=str, default=".", help="Path where to save the message")
args = parser.parse_args()
print(f"MESSAGE: {args.message}")
print(f"EXTRA_MESSAGE: {os.environ.get('EXTRA_MESSAGE')}")
print(f"PATH: {args.output}")
with open(os.path.join(args.output, "message.txt"), "w") as f:
f.write(args.message)
Below is the Dockerfile
that demonstrates the functionality of key features, including:
The use of basic key instructions:
ARG
,FROM
,RUN
,ENV
,COPY
,WORKDIR
,CMD
,ENTRYPOINT
Multi stage builds
Executing command as a non-root user
ARG PYTHON_IMG="python:3.13-bookworm"
ARG USER_UID=2000
ARG USER_GID=2000
# BUILD STAGE
FROM ${PYTHON_IMG} AS builder
RUN mkdir /project
COPY print_and_save_message.py /project/print_and_save_message.py
# RUN STAGE
FROM ${PYTHON_IMG}
ARG USER_UID
ARG USER_GID
COPY --from=builder /project /project
RUN groupadd -g ${USER_GID} newuser
RUN useradd newuser -u ${USER_UID} -g ${USER_GID} -m -s /bin/bash
USER newuser
ENV EXTRA_MESSAGE="Welcome"
WORKDIR /project
ENTRYPOINT ["python", "print_and_save_message.py"]
CMD ["Hello World!"]
There are multiple important aspects to understand in this Dockerfile
:
ARG
is available at build time only, and the default value can be overwrite by the--build-arg VAR=value
When using
ARG
globally (before anyFROM
instruction) in multiple stages as in our case, we need to “renew” the ARG at each stage.We create a user with the possibility to set explicitly the user UID and GID during the build command. Doing so, if the UID/GID match the UID/GID of the HOST user and if we bind a volume inside the container, files generated by the script in the container will be created as if it was created by the HOST.
You can use the following command to build the image:
docker build --build-arg PYTHON_IMG="python:3.12-bookworm" --build-arg USER_UID=$(id -u) --build-arg USER_GID=$(id -g) -t test-img .
And run the image using:
mkdir container_output
docker run -it --rm -v ./container_output:/home/newuser test-img "Bye World" "--output" "/home/newuser"
# Alternative using --mount option
docker run -it --rm --mount type=bind,source=./container_output,target=/home/newuser test-img "Bye World" "--output" "/home/newuser"
Note
If you want the container to have only read access to the HOST volume, you can use arguments -v ./container_output:/home/newuser:ro
or --mount type=bind,source=./container_output,target=/home/newuser,readonly
.
Differences between ENTRYPOINT and CMD
The difference between ENTRYPOINT
and CMD
:
CMD
: Specifies the default command and arguments to execute when running a container. It can be overridden by specifying a command in the docker run command. It Can be specified in three forms:Shell form: CMD command param1 param2
Exec form: CMD [“executable”, “param1”, “param2”]
As default parameters to ENTRYPOINT: CMD [“param1”, “param2”]
ENTRYPOINT
: Defines the executable that will always be run in the container. It is designed to not be overridden unless explicitly overridden with--entrypoint
in the docker run command.Typically specified in exec form: ENTRYPOINT [“executable”, “param1”, “param2”]
If combined with CMD, the CMD provides default arguments to the ENTRYPOINT
Create a user with the same UID/GID as host
ARG USER_UID
ARG USER_GID
RUN groupadd -g ${USER_GID} newuser
RUN useradd newuser -u ${USER_UID} -g ${USER_GID} -m -s /bin/bash
USER newuser
docker build --build-arg USER_UID=$(id -u) --build-arg USER_GID=$(id -g) -t image-name .
Useful commands
List the containers:
# Only running containers
docker ps
# All the containers
docker ps -a
# Custom formatting
docker ps --format "table {{.Image}}\t{{.Ports}}\t{{.Names}}\t{{.Mounts}}"
You can set the default formatting by editing the file ~/.docker/config.json
, example for the docker ps
command:
{
"psFormat": "table {{.ID}}\\t{{.Image}}\\t{{.Status}}\\t{{.Names}}\t{{.Mounts}}"
}
Get a container IP adress:
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id
Delete all containers:
docker container stop $(docker container ls -aq)
docker container prune -f # Only delete non-running containers
Delete all images:
# Containers using the image need to be removed first
docker rmi -f $(docker images -aq)
Docker volumes:
# Create a volume
docker volume create volume_name
# List the volumes
docker volume ls
# Inspect a volume (eg to get its mount point)
docker volume inspect volume_name
# Delete a volume
docker volume rm volume_name
Sources:
https://www.pgadmin.org/docs/pgadmin4/latest/container_deployment.html#examples
https://stackoverflow.com/questions/17157721/how-to-get-a-docker-containers-ip-address-from-the-host
https://stackoverflow.com/questions/27701930/how-to-add-users-to-docker-container?rq=3
https://stackoverflow.com/questions/52073000/how-to-remove-all-docker-containers