.
Docker

Containerize applications for faster deployment and scaling
🚀 About
In this HashiQube DevOps lab, you'll get hands-on experience with Docker. You'll learn how to:
- Build a custom Docker image from a Dockerfile
- Run Docker containers
- Configure a Docker daemon with authentication
- Set up a Docker registry
This lab follows the official Docker installation guide for Ubuntu-based systems.
📋 Provision
vagrant up --provision-with basetools,docsify,docker
docker compose exec hashiqube /bin/bash
bash hashiqube/basetools.sh
bash docker/docker.sh
bash docsify/docsify.sh
📦 What You'll Build
When you run the provisioner, it will:
- Install Docker on your HashiQube environment
- Build an Apache 2.4 container from a Dockerfile
- Run the container and expose it to your host machine
- Make the container accessible at http://localhost:8889
🛠️ Dockerfile Walkthrough
Below is the Dockerfile used to build the Apache web server container:
FROM ubuntu:18.04
# Install dependencies
RUN apt-get update && \
apt-get -y install apache2
# Install apache and write hello world message
RUN echo 'Hello World!' > /var/www/html/index.html
# Configure apache
RUN echo '. /etc/apache2/envvars' > /root/run_apache.sh && \
echo 'mkdir -p /var/run/apache2' >> /root/run_apache.sh && \
echo 'mkdir -p /var/lock/apache2' >> /root/run_apache.sh && \
echo '/usr/sbin/apache2 -D FOREGROUND' >> /root/run_apache.sh && \
chmod 755 /root/run_apache.sh
EXPOSE 80
CMD /root/run_apache.sh
This Dockerfile:
- Uses Ubuntu 18.04 as the base image
- Installs Apache web server
- Creates a simple "Hello World" web page
- Sets up a script to run Apache in the foreground
- Exposes port 80 for web traffic
- Specifies the command to run when the container starts
📊 Monitoring Docker
HashiQube includes Prometheus and Grafana for monitoring Docker containers.
For detailed information, see the Monitoring Docker guide.
🧩 Key Docker Concepts
Images vs Containers
- Images: Read-only templates used to create containers
- Containers: Runnable instances of images
Basic Docker Commands
# List running containers
docker ps
# List all containers (including stopped ones)
docker ps -a
# List available images
docker images
# Pull an image from Docker Hub
docker pull ubuntu:latest
# Run a container
docker run -d -p 8080:80 --name my-container nginx
# Stop a container
docker stop my-container
# Remove a container
docker rm my-container
# Remove an image
docker rmi nginx
🔌 Docker Networking
Docker creates isolated networks for containers by default. You can:
- Create custom networks
- Connect containers to multiple networks
- Configure network settings
# Create a custom network
docker network create my-network
# Run a container connected to the custom network
docker run -d --network=my-network --name my-db postgres
# Connect an existing container to a network
docker network connect my-network my-container
📦 Docker Volumes
Volumes provide persistent storage for containers:
# Create a named volume
docker volume create my-data
# Run a container with a volume
docker run -d -v my-data:/data --name my-container ubuntu
# Mount a host directory as a volume
docker run -d -v /host/path:/container/path --name my-container ubuntu
🔍 Docker Provisioner
The script below automates the setup of Docker in your HashiQube environment:
#/bin/bash
# https://docs.docker.com/install/linux/docker-ce/ubuntu/
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"Installing Docker Dependencies"
echo -e '\e[38;5;198m'"++++ "
sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq < /dev/null > /dev/null
sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq --assume-yes apt-transport-https ca-certificates curl gnupg-agent software-properties-common < /dev/null > /dev/null
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
arch=$(lscpu | grep "Architecture" | awk '{print $NF}')
if [[ $arch == x86_64* ]]; then
ARCH="amd64"
elif [[ $arch == aarch64 ]]; then
ARCH="arm64"
fi
echo -e '\e[38;5;198m'"CPU is $ARCH"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"Installing Docker"
echo -e '\e[38;5;198m'"++++ "
sudo add-apt-repository -y "deb [arch=$ARCH] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update -qq < /dev/null > /dev/null
# BUG: error reopening /dev/null https://bugs.launchpad.net/ubuntu/+source/docker.io/+bug/1950071 so we pin docker-ce=5:20.10.16~3-0~ubuntu-focal and containerd.io=1.5.11-1
# BUG: https://github.com/containerd/containerd/issues/6203
# FIXED: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error reopening /dev/null inside container: open /dev/null: operation not permitted: unknown
sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq --allow-downgrades --assume-yes docker-ce docker-ce-cli containerd.io docker-compose-plugin < /dev/null > /dev/null
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"Set Docker Configs"
echo -e '\e[38;5;198m'"++++ "
sudo usermod -aG docker vagrant
sudo mkdir -p /etc/docker
# https://docs.docker.com/config/daemon/prometheus/
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"metrics-addr": "0.0.0.0:9323",
"experimental": true,
"storage-driver": "overlay2",
"insecure-registries": ["10.9.99.10:5001", "10.9.99.10:5002", "localhost:5001", "localhost:5002"]
}
EOF
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"Restart Docker Daemon"
echo -e '\e[38;5;198m'"++++ "
sudo service docker restart
cd /vagrant/docker
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"Docker System prune"
echo -e '\e[38;5;198m'"++++ "
docker stop registry
docker rm registry
docker stop apache2
docker rm apache2
yes | sudo docker system prune -a
yes | sudo docker system prune --volumes
# echo -e '\e[38;5;198m'"++++ "
# echo -e '\e[38;5;198m'"Creating Private Docker Registry"
# echo -e '\e[38;5;198m'"++++ "
# # https://docs.docker.com/registry/deploying/#customize-the-published-port
# docker run -d --restart=always \
# --name registry \
# -v "$(pwd)"/auth:/auth \
# -e "REGISTRY_AUTH=htpasswd" \
# -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
# -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
# -e REGISTRY_HTTP_ADDR=0.0.0.0:5002 \
# --memory 256M -p 5002:5002 registry:2
# cat <<EOF | sudo tee /etc/docker/auth.json
# {
# "username": "admin",
# "password": "password",
# "email": "admin@localhost"
# }
# EOF
# echo -e '\e[38;5;198m'"++++ "
# echo -e '\e[38;5;198m'"++++ Docker Login to Registry"
# echo -e '\e[38;5;198m'"++++ "
# sleep 10;
# sudo --preserve-env=PATH -u vagrant docker login -u="admin" -p="password" http://10.9.99.10:5002
# echo -e '\e[38;5;198m'"++++ "
# echo -e '\e[38;5;198m'"++++ Docker build -t apache2 ."
# echo -e '\e[38;5;198m'"++++ "
# docker build -t apache2 .
# echo -e '\e[38;5;198m'"++++ "
# echo -e '\e[38;5;198m'"++++ Docker images --filter reference=apache2"
# echo -e '\e[38;5;198m'"++++ "
# docker images --filter reference=apache2
# echo -e '\e[38;5;198m'"++++ "
# echo -e '\e[38;5;198m'"++++ Docker run -t -d -i -p 8889:80 --name apache2 --rm apache2"
# echo -e '\e[38;5;198m'"++++ "
# docker run -t -d -i -p 8889:80 --name apache2 --memory 16M --rm apache2
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Docker ps"
echo -e '\e[38;5;198m'"++++ "
docker ps
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Docker stats"
echo -e '\e[38;5;198m'"++++ "
docker stats --no-stream -a
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Docker Daemon installed"
echo -e '\e[38;5;198m'"++++ "
# echo -e '\e[38;5;198m'"++++ open http://localhost:8889 in your browser"
# echo -e '\e[38;5;198m'"++++ you can also run below to get apache2 version from the docker container"
# echo -e '\e[38;5;198m'"++++ vagrant ssh -c \"docker ps; docker exec -it apache2 /bin/bash -c 'apache2 -t -v; ps aux'\""
🔗 Additional Resources
- Docker Official Website
- Docker Documentation
- Docker Compose Documentation
- Docker Hub - Repository for Docker images
- Docker Best Practices
- Docker Cheat Sheet