# Docker

## Installing Docker

```bash
$ 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 &gt; 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
        
        * ```json
            {
            "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
    
    * ```bash
        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
    
    * ```yaml
        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>`
