Docker by doing 2 - docker advanced

Syslog (container logging)

  1. Find rsyslog.conf
    1
    nano /etc/rsyslog.conf
  2. Edit the file uncomment the two lines under “Provides UDP syslog reception” by removing ‘#’
    1
    2
    $ModLoad imudp
    $UDPServerRun 514
  3. Start the syslog service and configure docker to use it via daemon.json
    1
    2
    3
    systemctl start rsyslog
    sudo mkdir /etc/docker
    nano /etc/docker/daemon.json
  4. Edit daemon.json
    1
    2
    3
    4
    5
    6
    {
    "log-driver": "syslog",
    "log-opts": {
    "syslog-address": "udp://<PRIVATE_IP>:514"
    }
    }
  5. Start the Docker service
    1
    2
    3
    systemctl start docker
    # are there docker logs?
    tail /var/log/messages
  6. Create two new containers using the httpd image
    • Syslog on log driver
      1
      2
      3
      4
      5
      6
      7
      docker container run -d --name syslog-logging httpd
      docker logs syslog-logging
      # Error response from daemon: configured logging does not support reading
      # check the content of '/var/log/messages':
      # verify that the syslog-logging container is sending its logs to syslog
      tail /var/log/messages
      # the output shows us the logs that are being input to syslog
    • JSON file as log driver
      1
      2
      3
      docker container run -d --name json-logging --log-driver json-file httpd
      docker logs json-logging
      # the logs do not appear in /var/log/messages

Watchtower (updating containers)

  • Watchtower: monitoring containers with other container and update them when the image is updated
  • Watchtower needs images pushed to a repository (see DockerHub)
    1. Create a dockerfile for a nodejs ‘express’ app
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # set base image
      FROM node

      # create the directory where the app will be copied to
      RUN mkdir -p /var/node
      # add our express content to that directory
      ADD content-express-demo-app /var/node/
      # set the working directory
      WORKDIR var/node/

      # scripts to build the app
      RUN npm install

      # execute
      CMD ./bin/www
    2. Log into DockerHub, build and push the image
      1
      2
      3
      4
      5
      docker login
      # -f = determine the dockerfile
      # . = the dockerfile in this directory
      docker build -t myDockerHubUser/express -f .
      docker push myDockerHubUser/express
    3. Execute dockerized app and watchtower
      1
      2
      3
      4
      5
      6
      7
      8
      9
      ## express app
      # -d = run in the background
      # -p = port, 80 on local, 3000 on container
      docker run -d --name demo -p 80:3000 --restart always myDockerHubUser/express
      docker ps

      ## watchtower
      # last paramerter is refresh period (30 seconds)
      docker run -d --name watchtower -p 80:3000 --restart always -v /var/run/docker.sock:/var/run/docker.sock v2tec/watchtower -i 30
    4. Make a small change on the ‘express’ app dockerimage, and push it to teh repository. Watchtower should autoupdate it

Metadata and labels

  • Use 2 different consoles to avoid issues (we will name them ‘docker workstation’ and ‘docker server’)
  1. Create a Dockerfile (on the docker workstation)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    FROM node

    LABEL maintainer=user@mail.com

    ARG BUILD_VERSION
    ARG BUILD_DATE
    ARG APPLICATION_NAME

    LABEL org.label-schema.build-date=$BUILD_DATE
    LABEL org.label-schema.applicaiton=$APPLICATION_NAME
    LABEL org.label-schema.version=$BUILD_VERSION
    RUN mkdir -p /var/node
    ADD weather-app/ /var/node/
    WORKDIR /var/node
    RUN npm install
    EXPOSE 3000
    CMD ./bin/www
  2. Build the Docker image (on the docker workstation)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # log in to DockerHub
    docker login
    # build the image with parameters
    docker build -t myDockerHubUser/weather-app --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
    --build-arg APPLICATION_NAME=weather-app --build-arg BUILD_VERSION=v1.0 -f Dockerfile .
    # show image id (IMAGE_ID), and use it to inspect it
    docker images
    docker inspect IMAGE_ID
    # push the image to DockerHub
    docker push myDockerHubUser/weather-app
  3. Create the weather-app container (on the docker server)
    1
    2
    docker run -d --name demo-app -p 80:3000 --restart always myDockerHubUser/weather-app
    docker ps
  4. Check out version v1.1 of the weather app (on the docker workstation)
    1
    2
    3
    cd weather-app
    git checkout v1.1
    cd ../
  5. Rebuild the weather-app image (on the docker server)
    1
    2
    3
    4
    5
    6
    docker build -t mydockerHubUser/weather-app --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') /
    --build-arg APPLICATION_NAME=weather-app --build-arg BUILD_VERSION=v1.1 -f Dockerfile .
    docker push USERNAME/weather-app
    # show image id (IMAGE_ID), and use it to inspect it
    docker ps
    docker inspect IMAGE_ID

Load balancing containers

  • 2 servers: swarm manager and swarm worker (always on swarm manager unless you are told so)
  1. Create a Docker Compose file on Swarm Server 1 (on lb-challenge directory)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    # Change to the lb-challenge directory
    version: '3.2'
    services:
    weather-app1:
    build: ./weather-app
    tty: true
    networks:
    - frontend
    weather-app2:
    build: ./weather-app
    tty: true
    networks:
    - frontend
    weather-app3:
    build: ./weather-app
    tty: true
    networks:
    - frontend

    loadbalancer:
    build: ./load-balancer
    image: nginx
    tty: true
    ports:
    - '80:80'
    networks:
    - frontend
    networks:
    frontend:
  2. Update nginx.conf (on load-balancer directory)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    events { worker_connections 1024; }

    http {
    upstream localhost {
    server weather-app1:3000;
    server weather-app2:3000;
    server weather-app3:3000;
    }
    server {
    listen 80;
    server_name localhost;
    location / {
    proxy_pass http://localhost;
    proxy_set_header Host $host;
    }
    }
    }
  3. Execute docker-compose up
    1
    2
    3
    cd ../
    docker-compose up --build -d
    docker ps
  4. Create a Docker service using Docker Swarm
    1
    2
    3
    4
    cd ~/
    # review the token
    cat swarm-token.txt
    # Copy the 'docker swarm join' command from the previous step
  5. On swarm worker: execute the command that was copied from the previous step
  6. Back to swam manager: create a Docker service
    1
    2
    3
    docker service create --name nginx-app --publish published=8080,target=80 --replicas=2 nginx
    docker ps
    #verify that the default nginx page loads in the browser (PUBLIC_IP_ADDRESS:8080)

Compose: building services

  1. Create a Ghost Blog and MySQL Service
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    version: '3'
    services:
    ghost:
    image: ghost:1-alpine
    container_name: ghost-blog
    restart: always
    ports:
    - 80:2368
    environment:
    database__client: mysql
    database__connection__host: mysql
    database__connection__user: root
    database__connection__password: P4sSw0rd0!
    database__connection__database: ghost
    volumes:
    - ghost-volume:/var/lib/ghost
    depends_on:
    - mysql
    mysql:
    image: mysql:5.7
    container_name: ghost-db
    restart: always
    environment:
    MYSQL_ROOT_PASSWORD: P4sSw0rd0!
    volumes:
    - mysql-volume:/var/lib/mysql
    volumes:
    ghost-volume:
    mysql-volume:
  2. Start Ghost blog service
    1
    docker-compose up -d