Docker
Installing Docker
$ sudo apt-get update
$ sudo apt-get install -y ca-certificates curl gnupg
$ sudo install -m 0755 -d /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg
$ echo \
"deb [arch="$(dpkg --print-architecture)" \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
"$(. /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 -y install docker-ce docker-ce-cli \
containerd.io docker-buildx-plugin docker-compose-plugin
$ sudo docker --version
## Allow regular user to use docker
$ sudo usermod -a -G docker <username>
Run a docker container
docker run hello-world
Docker registry
- DockerHub , Google Container Registry (GCR)
Artifact Registry
- Sonatype Nexus, JFrog Artifactory
Docker storage drivers and volumes
Docker data storage options
Volumes
store data directly in the host's filesystem.
Default - /var/lib/docker/volumes
Bind mounts
Allow to mount an existing host directory as a filesystem on the container
Processes other than docker can modify data.
tmpfs mounts
- store data in memory
Docker storage drivers
overlay2
- default and recommended
devicemapper
block based storage
Useful when writes > reads
btrfs and zfs
vfs
Configuring a storage driver
$ sudo vim /etc/docker/daemon.json
{ "storage-driver": "devicemapper" }
sudo systemctl restart docker
$ docker info | grep 'Storage Driver'
Running your first container
$ docker run hello-world
Running containers from versioned images
$ docker run nginx:1.18.0
Running Docker containers in the background
$ docker run -d nginx:1.18.0
Troubleshooting containers
$ docker ps
$ docker logs beb5dfd529c9
Best setting for HA nginx
$ docker run -d --name nginx --restart unless-stopped -p 80:80 --memory 1000M --memory-reservation 250M nginx:1.18.0
Other options for flag
unless-stopped , no, on_failure , always
-p 80:80: Forward traffic from host port 80 to container port 80
Restarting and removing containers
Stop
$ docker stop nginx
Start
$ docker start nginx
Stop and remove
$ docker stop nginx && docker rm nginx
or$ docker rm -f nginx
Docker logging
Logging drivers
none
local
json-file (default)
syslog
journald
gelf
fluentd
awslogs
splunk
etwlogs
gcplogs
logentries
Configuring logging drivers
$ docker info | grep "Logging Driver"
$ sudo vim /etc/docker/daemon.json
{ "log-driver": "journald" }
$ sudo systemctl restart docker
$ docker run --name nginx-journald -d nginx
$ sudo journalctl CONTAINER_NAME=nginx-journald
For splunk
{ "log-driver": "splunk", "log-opts": { "splunk-token": "<Splunk HTTP Event Collector token>", "splunk-url": "<Splunk HTTP(S) url>" } }
Passing from command line
$ docker run --name nginx-json-file --log-driver json-file -d nginx
Log directory -
/var/lib/docker/ containers/<container_id>/<container_id>-json.log
Approach to logging
- Store logs locally using JSON files then use another container to push the logs to log analytics solution
Docker monitoring with Prometheus
Uses Prometheus query language (PromQL), time series database.
Prometheus + cAdvisor
cAdvisor is a metrics collector that scrapes metrics from containers
Metrics to monitor
Host metrics
Host CPU
Host memory
Host disk space
Docker container metrics
Container CPU
Throttled CPU time
Container memory fail counters
Container memory usage
Container swap
Container disk I/O
Container network metrics
Declarative container management with Docker Compose
Requirements
Python Flask application listens on port 5000
Application connects to Redis database as a backend service on port 6379
Docker File
FROM python:3.7-alpine ENV FLASK_APP=app.py ENV FLASK_RUN_HOST=0.0.0.0 RUN apk add --no-cache gcc musl-dev linux-headers COPY requirements.txt requirements.txt RUN pip install -r requirements.txt EXPOSE 5000 COPY . . CMD ["flask", "run"]
Docker compose file
version: "2.4" services: flask: image: "image-directory/python-flask-redis:latest" ports: - "80:5000" networks: - flask-app-net redis: image: "redis:alpine" networks: - flask-app-net command: ["redis-server", "--appendonly", "yes"] volumes: - redis-data:/data networks: flask-app-net: driver: bridge volumes: redis-data:
$ docker compose up -d
Best Practices
Use an .env file to store sensitive variables
Be mindful of dependencies in production
$ docker-compose up --no-deps -d <container_service_name>