This tutorial contains some notes about using Docker as container for running virtual environments.

1. Introduction to Docker

1.1. What is Docker

Docker is a light weight container, allowing to run pre-configured system images on another operating system. It is developed as an open-source project, released under the Apache License, version 2.

You can package an application, libraries or operating systems in a container, for example: * OS, * JVM, * App server * Application with its configuration

This makes the virtual machine portable across environments. Developers can use the same setup as you can use in your production environment.

Docker requires a small amount of resources, as does not require an hypervisor for each container nor does it simulate a complete computer.

Docker addresses the following use cases:

  • You want to use a specific version of a operating system for testing

  • You want to run your software tests in an controlled environment

  • You want to configure a system and share the configuration

1.2. Docker components

Docker consists of the following components:

  • Images

  • Containers

  • Daemon

  • Clients

  • Registries

1.3. Dockerfile

A dockerfile allows defining images.

1.4. Images

Images are read-only templates that provide functionality for running an instance of this image. For example, the latest release of Ubuntu might be provided as image. Images are defined as layers, for example, you can add Java to the Ubuntu image and get another image based on this.

The Docker hub provides pre-configured images. You can modify existing images and save these modifications as new image.

1.5. Containers

Container are the started components based on images. They contain the actual application and dependencies but share the same kernel. They can be started, stopped, paused, deleted. Containers are immutable and disposable.

1.6. Docker Daemon

Is used to manage the container. It runs natively on Linux and inside a VM on Windows and macOS. To start it use the docker command.

1.7. Docker clients

Clients (CLI, IDE) run on host VM. They provide the tools to interact with container, i.e., to start them.

1.8. Docker registry

Images are saved in a registry and have an ID with consists of a repository and a tag. For example, fedora:22, is an image that contains the Fedora 22 OS from the fedora repository.

To use an image you have to pull it from a registry, to share an image with others you have to push it to one. The default Docker registry is the Docker Hub. You can upload your personal images to GitHub, in this case you add your user name as prefix to the image, e.g., vogella/fedore:22

1.9. Docker Compose

Compose is a tool for defining and running applications in multiple Docker container. You use a YAML file to configure your applications services.

1.10. Managing data in Docker

By default, Docker stores all data inside the container, which makes is harder to persist this data and to reuse the data in another container.

Docker offers two storage options for hosting data on the host machine:

  • volumes - stored on the host file system managed by Docker, preferred way of persisting data in Docker containers

  • bind mounts - old way of managing file includes, prefer using volumes

Docker volumes that are not explicitly created, are created the first time they are mounted to a container. If the container is stopped the volume still persists.

2. Docker installation and setup

Install Docker Toolbox from https://www.docker.com/. The installation is well described on the getting started page. For example, https://docs.docker.com/linux/step_one/ describes the installation for Linux

Afterwards, you can test you installation as described on the webpage:

sudo docker run hello-world

If you issue the command the first time, it downloads the hello-world image and start it.

To allow your user to run docker commands without the sudo prefix, configure a new group and add you user to it.

sudo usermod -aG docker ubuntu

Afterwards, you need to logout and login again. Validate that you can run docker commands without sudo.

docker run hello-world

3. Docker commands

3.2. List all available containers

Via the -a flag you list all contains. Without -a you only list the running containers.

docker ps -a

3.3. Create a new container

docker run image

3.4. Delete a container and an image

Use the following command to remove all your containers.

docker rm $(docker ps -a -q)

Use the following command to remove all your images.

docker rmi $(docker images -q)

3.5. Start a terminal session on a running container

Use this command to start a terminal session on a running container:

docker exec -it <container id> /bin/sh
If your image is using bash you have to replace /bin/sh with /bin/bash.

3.6. Start a terminal session on an image

Use this command to start a terminal session on an image:

docker run -i -t --entrypoint /bin/sh <image id>

3.7. Inspect a Docker container

docker inspect <image id>

4. Docker networking

4.1. Docker networking modes

Docker offers the following networking modes:

  • none

  • bridge (default)

  • host

  • container:<name|id>

  • user-defined network

4.1.1. None

docker run --net="none"

This option deactivates all external routes for the container. The only way to exchange data then is I/O or STDIN/STDOUT.

4.1.2. Bridge

docker run --net="bridge"

This is the default mode. In this mode the host and the container can communicate via their ip addresses. A veth (virtual ethernet interface) gets created on both host and container. Both of those veths are put into a bridge which enables the communication. The bridge is usually named docker0.

4.1.3. Host

docker run --net="host"

In this mode the container shares the complete network stack of the host. This is useful for containers that need high performance network connectivity since the network traffic doesn’t have to go through virtualization.

Since this mode gives the container full access to all network interfaces and services of the host it poses a security risk.

4.1.4. Container

docker run --network container:<name|id>

In this mode the container shares the network stack of another container.

4.1.5. User-defined network

docker network create -d bridge my-net
docker run --network=my-net

You do not have to use the default network bridge to connect your containers. There are multiple network drivers to use. This way you first create a network and then add the container you want to communicate with each other to it. The simplest way is to use the bridge driver. Docker container on a user-defined network can address each other via their host name since Docker provides an embedded DNS server. Other possibilities are the overlay and the macvlan network driver.

5. Exercise: Allow a container in bridge mode to connect to a database on the host

In this exercise we are going to enable a docker container to connect to a Postgresql database on the host machine.

First we want to set the default bridge to an IP of our liking.

In /etc/default/docker add the line:

DOCKER_OPTS="--bip=172.26.0.1/16"

This sets the ip address of the docker0 bridge to 172.26.0.1.

Then restart docker with

sudo /etc/init.d/docker restart

You can validate your change with

/sbin/ifconfig -a

Install postgresql, if you it already installed you can skip this step:

sudo apt-get install -y postgresql postgresql-contrib

Create a user and database:

sudo su - postgres
createuser --interactive -P my-user
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) y
Shall the new role be allowed to create more new roles? (y/n) n
createdb -O my-user testdb

By default, postgres is only listening on localhost for incoming connections. We want it to also listen on our docker0 bridge. In /etc/postgresql/9.5/main/postgresql.conf set

listen_addresses = 'localhost, 172.26.0.1'

Now we have to allow the user to connect through this addresss. In /etc/postgresql/9.5/main/pg_hba.conf set

# TYPE  DATABASE                   USER                       ADDRESS                 METHOD
# with docker:
host    testdb                     my-user                    172.26.0.1/16           md5

To activate the changes restart postgres with

sudo /etc/init.d/postgresql restart

Assuming your CMD in your dockerfile is start.sh you can add this to your starter shell script to expose the host ip to your application:

export DOCKER_HOST_IP=$(/sbin/ip route|awk '/default/ { print $3 }')

Now your docker container is ready to connect to the database on the host.

6. Exercise: Create an Ubuntu based system with Java

To run a shell on an Ubuntu 26.04 system, use the following command.

docker run -t -i ubuntu:26.04 /bin/bash

This starts the Ubuntu system and runs a shell in a new container.

To build your own image you describe it in a file named Dockerfile. See Dockerfile best practices.

The following Dockerfile is based on Ubuntu 26.04 and installs Java 25.

FROM ubuntu:26.04

LABEL maintainer="Lars Vogel"

# Install Java 25
RUN apt-get update && apt-get install -y openjdk-25-jdk

Build the image with docker build -t ubuntujava . and start it with docker run -t -i ubuntujava /bin/bash. Run java -version to verify the installation.

7. Running AI models in containers

Docker can run AI models in isolated containers with access to the host GPU through the NVIDIA Container Toolkit. Pass --gpus all to expose the GPU; without it the model runs on the CPU and is much slower.

7.1. Running a large language model with Ollama

Ollama serves local large language models through a REST API. The official image stores its models in the ollama volume so they survive container restarts.

docker run -d --gpus all -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama

Pull and chat with a model, for example Llama 3.2:

docker exec -it ollama ollama run llama3.2
Ollama has no authentication, so do not expose port 11434 on a public network.

7.2. Text-to-image generation with FLUX.2

ComfyUI is a node-based interface for image generation. The following image bundles ComfyUI with FLUX.2, the state-of-the-art open text-to-image model from Black Forest Labs. FLUX.2 [klein] is openly licensed (Apache 2.0) and runs on about 8 GB of VRAM, while the larger FLUX.2 [dev] needs a high-end GPU.

Set HF_TOKEN to a Hugging Face token so the container can download the model weights.

docker run -d --gpus all -p 8188:8188 \
  -e HF_TOKEN=<your-token> \
  -v $(pwd)/data:/app \
  frefrik/comfyui-flux:latest

Open http://localhost:8188 in a browser, enter a text prompt and generate the image. The downloaded models are kept in the mounted data directory.

Appendix A: Docker resources

Home Tutorials Training Consulting Books Company Contact us


Get more...