Install Docker #
Installation Script #
Note: This scripts install the Docker CE Community Edition, this is the version provided directly by Docker.
Ubuntu Script
Install Docker and Docker-Compose (apt)
#!/bin/bash
# Install Docker and Docker Compose on Ubuntu
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release -y
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
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
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Debian Script
Install Docker and Docker-Compose (apt)
#!/bin/bash
# Install Docker and Docker Compose on Debian
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Raspberry Pi 5 64-bit (Debian ARM) Script
Install Docker and Docker-Compose (apt)
#!/bin/bash
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
# REF:
https://docs.docker.com/engine/install/debian/#install-using-the-repository
- Create / run script
# Create file and insert script
vi docker_setup.sh
# Change file mode to executable
chmod +x docker_setup.sh
# Run installation script
./docker_setup.sh
# Check Docker Version
docker --version
- Add user to Docker group
Some Linux distributions do not automatically create a Docker group. Create a Dockergroup if it does not yet exist, Docker will bind to this group.
# Create Docker group (Ubuntu does this by default)
sudo groupadd docker
# Add user to Docker group: RedHat, Ubuntu
sudo usermod -aG docker username
# Add user to Docker group: Debian
sudo adduser username docker
Ansible Playbook #
- Ubuntu Version
---
- name: Install Docker on Ubuntu
hosts: all
become: true
tasks:
- name: Update apt
apt:
update_cache: yes
- name: Install dependencies
apt:
name: ca-certificates,curl,gnupg,lsb-release
state: present
- name: Create Docker keyring directory
file:
path: /etc/apt/keyrings
state: directory
- name: Add Docker GPG key
shell: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
- name: Add Docker repository to apt sources
shell: 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
- name: Update apt again
apt:
update_cache: yes
- name: Install Docker
apt:
name: docker-ce,docker-ce-cli,containerd.io,docker-buildx-plugin,docker-compose-plugin
state: present
- name: Add ubuntu user to docker group
user:
name: ubuntu
groups: docker
append: yes
Docker Compose Overview #
Docker Compose Commands #
Depending on the Docker Version start the command with either docker-compose
for the old version,
or docker compose
for the new version.
# Check Docker Compose Version
docker compose version
- Test yml syntax
# Check the yml syntax without starting the Container
docker compose config
# Check the yml syntax without starting the Container: Quiet (Dont list the yml file to shell)
docker compose config -q
- Pull image
# Pull latest Image (Stop Container first)
docker compose pull
- Create, start & stop containers
# Start Containers
docker compose up -d
# Start only a specific service / container from docker compose file
docker compose up -d servicename
# Start Containers: Custom filename
docker compose -f filename.yaml up -d
# Stop Containers
docker compose down
# Stop Containers: Custom filename
docker compose -f filename.yaml down
# Restart Containers
docker compose restart
- Start & stop specific container / service from the Docker Compose stack
# Start, stop, restart, pause & unpause a Docker Container
docker compose start servicename
docker compose stop servicename
docker compose restart servicename
docker compose pause servicename
docker compose unpause servicename
- Logs
# List Logs till Command execution
docker compose logs
# List Logs all logs (running)
docker compose logs -f
- List Docker Containers
# List (only) Containers from Docker Compose file
docker compose ps
# List processes running inside each Container
docker-compose top
Docker Project Name #
Note: Docker Compose generates a default project name based on the name of the directory where the docker-compose.yml file is located. This project name is then used as a prefix for network names and container names.
# Create environment file
sudo vi .env
# .env
COMPOSE_PROJECT_NAME=name-of-the-stack
Depends On #
Define the order in which services are started up.
version: "3.9"
services:
web:
build: .
depends_on:
- db # Wait for db Service
- redis # Wait for Redis Service
redis:
image: redis
db:
image: postgres
Container Image Tag #
Go to hub.docker.com to find the latest image tags. Use a colon to define the image tag after the image, for example:
version: '3'
services:
app:
container_name: upload_nextcloud:25.0.5-apache
Or just the define the image with the latest
tag,
to automatically pull the latest version of the image,
for example:
version: '3'
services:
app:
container_name: upload_nextcloud:latest
Networking #
Note: Docker Compose generates a default project name based on the name of the directory where the docker-compose.yml file is located. This project name is then used as a prefix for the internal Docker network names.
Overview #
# Create new external Docker network
sudo docker network create external-network-1
# List Docker networks
sudo docker network ls
version: "2.4"
services:
db:
image: ...
...
networks:
- internal-network-1 # Define the internal Docker stack network
docker-app:
depends_on:
- db
image: ...
...
networks:
- internal-network-1 # Define the internel Docker stack network
- external-network-1 # Define external reverse proxy network
networks:
external-network-1: # Define external reverse proxy network
external: true
internal-network-1: # Define internal Docker stack network
Custom Subnet #
# Create new external Docker network: With custom subnet
sudo docker network create --subnet=192.168.11.0/24 external-network-2
version: "2.4"
services:
db:
image: ...
...
networks:
- internal-network-1 # Define the internal Docker stack network
docker-app:
depends_on:
- db
image: ...
...
networks:
networks:
internal-network-1: # Define the internel Docker stack network
external-network-2: # Define external reverse proxy network
ipv4_address: 192.168.11.11 # Define IP address
networks:
external-network-2: # Define external reverse proxy network
external: true
internal-network-1: # Define internal Docker stack network
Ports #
- Example: Expose port to container network only
This means port “443” is exposed to other containers within the same Docker network but not mapped to the host’s port 443.
version: "3.9"
services:
web:
ports:
- "443"
- Example: Bind port to specific interface
Container port “443” is only exposed to the host interface with the IP “192.168.30.90”.
version: "3.9"
services:
web:
ports:
- "192.168.30.90:443:443"
Environment File #
Use environment variables defined in an external file
# Create environment file
sudo vi .env
version: "2"
services:
docker-app:
image:
container_name:
env_file: # Define external environment file
- .env
DNS & Hosts #
- Define host entry in Docker Compose file
version: "2"
services:
docker-app:
image:
container_name:
extra_hosts:
- "host1.jklug.local:192.168.30.31" # Define host entry
- "host2.jklug.local:192.168.30.32"
- Define DNS serer in Docker Compose file
version: "2"
services:
docker-app:
image:
container_name:
dns:
- 1.1.1.1 # Define DNS server
- 8.8.8.8
Dockerfile #
Build and create container from cutom image define in Dockerfile
version: '3.9'
services:
app:
build:
context: ./ # Path to Dockerfile
dockerfile: Dockerfile
image: image-name:tag # Define image name and tag
container_name: container-name # Define container name
restart: unless-stopped
hostname: hostname # Define host name
ports:
- 8080:80
Docker Volumes #
Standard Docker Volume #
version: "3.9"
services:
application:
image: image:latest
working_dir: /app
volumes:
- application_data:/app
volumes:
application_data:
Docker Volume Defined Location #
version: '3.9'
services:
application:
image: image:latest
volumes:
- application_data:/data
volumes:
application_data:
driver: local
driver_opts:
type: none
device: /opt/app/application_data
o: bind
Host Mapping #
version: "3.9"
services:
application:
image: image:latest
working_dir: /app
volumes:
- "./application_data:/app"
Note: Depending on the necessary permissions inside the container, it’s necessary to create the folder on the host with the required permissions before the container is started.
Working Directory & Commands #
This is the directory where the container will start, and it’s where commands defined with CMD in the Dockerfile, or commands specified in the Docker Compose file under command or entrypoint, will be executed.
version: "3.9"
services:
application:
image: image:latest
working_dir: /app
volumes:
- application_data:/app
command: ["/bin/sh", "-c", "while :; do sleep 10; done"]
volumes:
application_data:
Systemd Service Units #
Create Service Unit
vi /etc/systemd/system/docker-compose-example.service
[Unit]
Description=Docker Compose Service
Requires=docker.service #Requires Docker service
After=docker.service #Start after Docker service
[Service]
Type=oneshot #Service exits after the ExecStart command completes
WorkingDirectory=/home/ubuntu/docker-compose/
ExecStart=/usr/bin/docker compose -f /home/ubuntu/docker-compose/docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f /home/ubuntu/docker-compose/docker-compose.yml down
StandardOutput=syslog
SyslogIdentifier=docker-compose-example
RemainAfterExit=yes #Service considered active after its process exits
[Install]
WantedBy=multi-user.target #Service is started during system startup process
Reload the systemd daemon to load the new service unit:
systemctl daemon-reload
Enable service to start on boot:
systemctl enable docker-compose-example.service
Start the service & start the containers defined in Docker-Compose file:
systemctl start docker-compose-example.service
Docker Overview #
Docker Version #
# Check Docker Version
docker version
# Check Docker Compose Version
docker compose version
Docker Images #
Dockerhub: https://hub.docker.com/
Note when no Image tag is defined, the “latest” tag is used.
# Login to Dockerhub
docker login
# Pull Image from Dockerhub
docker pull image-name
# List Docker Images
docker images ls
# Delete Docker Image
docker image rm Image-ID
# Create Image from Container
docker container commit container-name image-name:tag
# Create Image from Container: Set Author and Commit Message
docker container commit -a "Author Name" -m "Commit message" container-name image-name:tag
# List history (commands) from Image
docker history image-name:tag
Create & Run Container #
# Create & start Container
docker run --name Container-name Image-name
# Create & start Container: Detached
docker run -d --name Container-name Image-name
# Create / start Container: Bind Port
docker run -d -p8080:80 --name Container-name Image-name
# Create / start Container: Line break
docker run -d \
-p 8080:80 \
--name Container-name \
--mount source=Volume-name,target=/vol \
--net Network-name \
--restart unless-stopped \
image # Define Container image
# Create / start Container: Restart Policy
docker run -d --restart always Image-name
--restart always
--restart unless-stopped
--restart no
# Update Restart Policy from running Container
docker update --restart unless-stopped ContainerID
# Keep Container runing in the background (Debug)
docker run -dt Container-name . sleep infinity
# Rename Container
docker rename container-name new-container-name
Start & Stop Container #
# Start Container
docker start Container-ID
##Start several Containers at once
docker start Container-ID &&
docker start Container-ID
# Stop Container
docker stop Container-ID`
# Immediately stop Container
docker kill Container-ID
# Restart Container
docker restart Container-ID
# List running Containers
docker ps
# List running and stopped Containers
docker ps -a # or
docker ps --all
Delete Stopped Container #
# List running & stopped Containers
docker ps -a
# Delete stopped Container
docker rm Container-ID
Docker PS - Format Output #
This command is very useful in environments with lots of running containers, it provides a more manageable overview.
# List ID's, Names & Image Versions
docker ps --format '{{ .ID }}\t{{.Names}}\t{{ .Image }}'
# List ID's, Names & Ports
docker ps --format '{{ .ID }}\t{{.Names}}\t{{ .Ports }}'
# List ID's, Names & Uptime
docker ps --format '{{ .ID }}\t{{.Names}}\t{{.Status}}'
# List ID's, Names & Creation Time
docker ps --format '{{ .ID }}\t{{.Names}}\t{{.RunningFor}}'
# List ID's & Names
docker ps --format '{{ .ID }}\t{{.Names}}'
# List only ID's
docker ps --format '{{ .ID }}'
# Save Docker PS output into file
docker ps | sort > /path/to/file
Container Logs #
# Follow logs of specific container
docker logs -f container_id_or_name
# Follow logs of docker compose stack
docker compose logs -f
List Container Environment Variables #
# List environment variables set in the container
docker exec -it container-name env
Execute Internal Terminal #
Depending on the base image used for a container, bash is not always available. Here are some alternatives:
# Open shell inside Container
docker exec -it Container-ID /bin/bash
docker exec -it Container-ID bash
docker exec -it Container-ID ash
docker exec -it Container-ID sh
# Open shell inside Container: Define user
docker exec -it -u www-data Container-ID bash
# Exit Internal Terminal
exit
Run Command inside Container
# List Container directory / print to host shell: Without interactive TTY
docker exec container-name ls /app
Copy files from / to Container #
# Copy file from Container to host
docker cp ContainerID:/container/path /host/path
# Copy file from host to Container
docker cp /host/path/ ContainerID:/container/path
Container Changes #
# List changes made inside a Container
docker diff container-name
A Added
C Changed
D Deleted
Import & Export Images #
Export Container, Import Image from Container
# Export stopped Container to tar file
docker export Container-ID > container-name.tar
# Import Image from exported Container
docker import - container-name < container-name.tar
Export & Import Image
# Export Docker Image
docker save -o image-name.tar image-name:tag
# Import Docker Image
docker load -i image-name.tar # or
docker load < image-name.tar
Docker Inspect #
List Container Details
# List Container Details
docker container inspect Container-Name
# Grep Container IP
docker inspect Container-ID | grep IPAddress
List Image Details
# List Image Details
docker inspect image-name:tag
# Grep Image Author
docker inspect image-name:tag | grep "Author"
Docker Network #
When not otherwise defined all Containers start in the default bridge network. Containers can communicate with each other using Container names as their DNS addresses.
Docker Network Commands:
# List Networks
docker network ls
# Inspect Network: E.g bridge
docker network inspect bridge
# Create Docker Network
docker network create network-name
# Delete Docker Network
docker network rm network-name
# Connect Container to Network
docker network connect network-name Container-ID
# Disconnect Container to Network
docker network disconnect network-name Container-ID
Start Container in specific network:
# Start container in specific network: e.g nginx
docker run --net network-name --name container-name -d nginx
# Start container in specific network, define custom IPv4 address:
docker run --net network-name --ip 192.168.60.11 --name container-name -d nginx
Dockerfile #
Dockerfile Commands
FROM # Define base Image for Container
FROM ubuntu # Example
WORKDIR # Define working directory for RUN, CMD, ENTRYPOINT, COPY & ADD instructions
WORKDIR /app # Example
COPY # Copy files from host into Container WORKDIR
COPY . . # Example
PULL # Adds files from Docker repository
RUN # Execute shell
RUN apt-get update # Example
CMD # Run Command (can only be used once)
CMD ["echo", "Hi there"] # Example
EXPOSE # Expose Port
EXPOSE 80 # Example
Docker Build #
Create & Start Image from Dockerfile
# Build Image from Dockerfile
docker build .
# Build Image from Dockerfile: Define image name
docker build -t image-name .
# Start Container from image
docker run --name container-name image-name
# The Container image looks as follows: List images
docker image ls
# Shell output
REPOSITORY TAG IMAGE ID CREATED SIZE
image-name tag 34ac7f7fb9ce About a minute ago 265MB
# The running Container looks as follows: List running containers
docker ps
# Shell output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1fb84ec5e41f image-name:tag "docker-entrypoint.s…" 9 seconds ago Up 7 seconds 3000/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp container-name
Open the Container terminal with docker exec -it container-name ash
and check the hostname with hostname
.
Container Registry #
Authenticate #
# Authenticate to the registry: DockerHub
docker login
# Authenticate to the registry: Define Server and port
docker login registry.example.com:5000
# Credential file
~/.docker/config.json
Image Name #
In order to push a local image to the registry, the image name must be in the following
format: My-Docker-ID/Imagename
# Tag an existing image with a new name or tag
docker image tag source-image My-Docker-ID/target-image
Push & Pull #
# Push image to DockerHub
docker image push My-Docker-ID/Imagename
# Run image from DockerHub
docker container run My-Docker-ID/Imagename
Docker Volumes #
# Create Docker Volume
docker volume create volume-name
# Delete Docker Volume
docker volume rm volume-name
# Delete all Docker Volumes that are not mounted
docker volume prune
# List Docker Volumes
docker volume ls
# Inspect Docker Volume
docker volume inspect volume-name
# Inspect Docker Volume: Shell Output
[
{
"CreatedAt": "2023-06-02T19:39:29Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/volume-name/_data",
"Name": "volume-name",
"Options": null,
"Scope": "local"
}
]
Change Docker Directory #
# Default Docker directory
/var/lib/docker/
# Stop Docker
sudo systemctl stop docker
# Open Docker configuration file
sudo vi /etc/docker/daemon.json
# Define data root
{
"data-root": "/new/path/to/docker-data"
}
# Move data
sudo mv /var/lib/docker /new/path/to/docker-data
# Start Docker
sudo systemctl start docker
# Verify changes
docker info | grep "Docker Root Dir"
Trouble-shooting #
When the Docker service itself want start it can be very helpful to output the following logs:
dockerd --debug
Show Docker logs
It could also be helpful to check your /etc/docker/daemon.json
configuration.
Clean Up #
Docker Prune #
# Remove dangling (not tagged) images
docker image prune
# Remove unused and dangling (not tagged) images
docker image prune --all
# Remove unused and dangling (not tagged) image: (Do not prompt for confirmation)
docker image prune --all --force
# Remove all stopped containers
docker container prune
# Remove unused networks
docker network prune
# Remove unused volumes
docker volume prune
# Remove all stopped containers, unused networks, and unused volumes
docker system prune
# Remove all unused data (containers, networks, volumes, and images)
docker system prune -a
Delete All Resources #
# Stop all Contrainers
docker kill $(docker ps -q)
# Delete all Containers
docker container rm -f $(docker container ls -aq)
# Delete all Volumes
docker volume rm -f $(docker volume ls -q)
# Delete all Images
docker image rm -f $(docker image ls -q)
# Delete all Dockernetworks
docker network prune -f
Stop & Delete at once:
docker kill $(docker ps -q) &&
docker container rm -f $(docker container ls -aq) &&
docker volume rm -f $(docker volume ls -q) &&
docker network prune -f
Delete Docker #
When the docker services want start and nothing else helps, sometimes the fastest way to solve the problem is to reinstall docker. To do so, first stop the docker service and uninstall all docker services.
Remove Docker | Explanation |
---|---|
systemctl stop docker.service |
Stop Docker Service |
sudo apt remove docker-ce docker.io docker |
Remove Docker |
Also it could be necessary to delete the following Docker directories:
/var/lib/docker/
/run/docker.pid
/run/docker.sock
After everything is removed use the script provided at the top of this tutorial to reinstall Docker.
Links #
# Docker Compose Versions
https://docs.docker.com/compose/compose-file/compose-versioning/