Intro to Docker

What is Docker?

What is Docker?

Docker is a containerization platform that packages your application and all its dependencies together in the form of Containers to ensure that your application works seamlessly in any environment.

Containers?

Containers are far from new; Google has been using their own container technology for years. Others Linux container technologies include Solaris Zones, BSD jails, and LXC, which have been around for many years.

https://linuxcontainers.org/

https://wiki.freebsd.org/Jails

VM vs Containers

Virtual machines have a full OS with its own memory management installed with the associated overhead of virtual device drivers.

 

Every guest OS runs as an individual entity from the host system.

 

VM vs Containers

On the other hand Docker containers are executed with the Docker engine rather than the hypervisor.

 

Containers are therefore smaller than Virtual Machines and enable faster start up.

What is Docker... again?

Open Source engine which:

- Allow us to create and share images (Docker-Hub)
- Provides an standard format for containers (layers, tarballs)
- Provides an standard reproducible way to easily build trusted images (Dockerfile)
- Provides an standard format to orchestrate multiple containers (Swarm, Compose)

Docker FTW

Build once - run anywhere

- A fully provisioned runtime environment for your services

- No more missing dependencies, packages version mismatch, permission issues and so on...
- Opens the door to an easier automation and continuous integration

- Reduces/eliminates concerns about compatibility on different platforms
- Easier to test monitor system upgrades (isolated incremental upgrades)

 

Build once - run anywhere

- Make deployments/scale-up/scale-out more efficient, consistent, and repeatable
- Eliminate inconsistencies between development, test, and production environments
- Significantly improves the speed and reliability of continuous deployment and integration

- Performance: Almost no overhead!, processes run straight on the host CPU (although isolated): performance = native performance!

Docker Components

Components

- Docker Engine: It’s a lightweight runtime and tooling that manages containers, images, builds, and more.
- The Docker Client is what you, as the end-user of Docker, communicate with  (ex, cli tool, docker gui)
 

Components

- Dockerfile: A Dockerfile is where you write the instructions to build a Docker image.

 

FROM ubuntu:latest

RUN apt-get update
RUN apt-get install -y python python-pip wget
RUN pip install Flask

ADD hello.py /home/hello.py

WORKDIR /home

Components

- docker-compose.yml: docker-compose is a tool for defining and running multi-container Docker applications. Used to configure your application's services. Then, using a single command, you create and start all the services from your configuration.

Components

- Docker-compose:

version: "2"
services:
  web:
    build: web
    command: python app.py
    ports:
     - "5000:5000"
    volumes:
     - ./web:/code
    links:
     - redis
    environment:
     - DATADOG_HOST=datadog
  redis:
    image: redis

Components

- Docker Image: Images are read-only templates that you build from a set of instructions written in your Dockerfile.

 

You can see already built images on Docker-hub for a multitude of services and components.

Components

- Docker containers: A Docker container wraps an application’s software into a box with everything the application needs to run. That includes the operating system, application code, runtime, system tools, system libraries, and etc. Docker containers are built off Docker images.

 

Components

- Docker Registry: Docker registry is a service that stores docker images. It may be private or public such as Docker-hub, Quay,
Google Container Registry,
AWS Container Registry.

 

 

Demo Time!

Demo

Running a docker image straight from Docker-hub

$ docker run -it alpine sh
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
8e3ba11ec2a2: Pull complete
Digest: sha256:7043076348bf5040220df6ad703798fd8593a0918d06d3ce30c6c93be117e430
Status: Downloaded newer image for alpine:latest
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 sh
    9 root      0:00 ps
/ #
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
fc4acdddee52        alpine              "sh"                About a minute ago   Up About a minute                       confident_noether

Demo

Building an image

$ docker build -t desyncr/node-docker-demo .
Sending build context to Docker daemon   5.12kB
Step 1/7 : FROM node:8
...
Digest: sha256:8be12ed3d805ec6e9847d9f09824d8ba80c43986efea5a3e02903748faa19115
Status: Downloaded newer image for node:8
...
Step 7/7 : CMD [ "npm", "start" ]
 ---> Running in b3f8f3da6893
Removing intermediate container b3f8f3da6893
 ---> c4ec364ea9ae
Successfully built c4ec364ea9ae
Successfully tagged desyncr/node-docker-demo:latest
$ docker images
$ docker run -p 8080:8080 -d desyncr/node-docker-demo
$ curl -i localhost:8080

Demo

Pushing an image to docker hub

$ docker login -u desyncr
Password:
Login Succeeded

$ docker push desyncr/node-docker-demo
The push refers to repository [docker.io/desyncr/node-docker-demo]
f8e0658646fe: Pushed
...
1618a71a1198: Mounted from library/node
latest: digest: sha256:876b4d8e257360318e2468ed9fa3630cbff7a2e98b1054b0f1c9e3b16ccb92f1 size: 2839
$ docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
desyncr/node-docker-demo   latest              c4ec364ea9ae        3 minutes ago       676MB

Demo

Using docker compose​ (1)

version: "2"
services:
  web:
    build: .
    ports:
     - "8080:8080"
    volumes:
     - ./:/code
    links:
     - redis
  redis:
    image: redis

Demo

Using docker compose​ (2)

$ docker-compose up                                                                                                                                          Creating network "node-docker-demo_default" with the default driver
Pulling redis (redis:)...
latest: Pulling from library/redis
...
Creating node-docker-demo_redis_1 ... done
Creating node-docker-demo_web_1   ... done
Attaching to node-docker-demo_redis_1, node-docker-demo_web_1
redis_1  | 1:C 12 Jul 10:12:20.972 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
...
redis_1  | 1:M 12 Jul 10:12:20.973 * Ready to accept connections
web_1    |
web_1    | > docker_web_app@1.0.0 start /usr/src/app
web_1    | > node server.js
web_1    |
web_1    | Running on http://0.0.0.0:8080
Killing node-docker-demo_web_1    ... done
Killing node-docker-demo_redis_1  ... done

Afluenta-Docker

Components

- Environments

- Images

- Docker-compose

- Makefile

Components

- Environments

env
├── local.ar
├── local.mx
├── local.pe
├── pkg.ar
│   ├── beta
│   └── prod
├── pkg.mx
└── pkg.pe

$ cat env/pkg.ar/beta
# ECS/ECR configs
ENV=beta
GEO=ar
PKG=pkg.${GEO}
HOSTNAME=beta-aws.afluenta.com
PHP_CONFIG=php.ini-aws-beta-ecs
FPM_CONFIG=php-fpm.conf-aws-beta-ecs
NGINX_CONFIG=nginx.config-beta-ecs
VARNISH_CONFIG=afluenta.dev.vcl
PLATFORM=aws-prod
PLATFORM_BO=aws-backoffice
REGISTRY=<redacted>.dkr.ecr.us-east-1.amazonaws.com
WEB_ROOT=/afluenta-platform/afluenta_web/web
LOG_PATH_SUFFIX=${HOSTNAME}

# EFS configs
EFS_URI=fs-<redacted>.efs.us-east-1.amazonaws.com
EFS_MOUNT_POINT=/afluenta-platform
EFS_OPTIONS=nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2

# Platform configs
MEMCACHED_CONTENTS_1_HOST=v-mc-01-beta.amzn.i.afluenta.com
MEMCACHED_CONTENTS_1_PORT=11311
MEMCACHED_CONTENTS_2_HOST=v-mc-01-beta.amzn.i.afluenta.com
MEMCACHED_CONTENTS_1_PORT=11211
MEMCACHED_SESSION_HOST=v-mc-01-beta.amzn.i.afluenta.com
GEARMAN_HOST=v-mc-01-beta.amzn.i.afluenta.com
DB_HOST=v-db-01-beta.amzn.i.afluenta.com
DB_USER=afluenta
DB_PASS=<redacted>
DB_NAME=afluenta
SERVER_USER=www-data
SERVER_GROUP=www-data
CONFIG_SERVER_USER=www-data
CONFIG_SERVER_GROUP=www-data

# aws logs
AWSLOGS_GROUP=afluenta-ecs
AWSLOGS_REGION=us-east-1
AWSLOGS_PREFIX=${ENV}-${GEO}

# VPC
VPC_ID=vpc-<redacted>
SUBNET_IDS=subnet-6666666
SECURITY_GROUP=sg-6666666666,sg-6666666666
CLUSTER_KEYPAIR=afluenta-ecs-beta

# Cluster
CLUSTER_SIZE=1
CLUSTER_LAUNCH_TYPE=EC2
CLUSTER_REGION=us-east-1
CLUSTER_INSTANCE_TYPE=c5.xlarge

CLUSTER_CONFIG=afl-ecs-cluster-config-beta
CLUSTER_NAME=afl-ecs-web-cluster-beta
CLUSTER_PROFILE=afluenta-ecs-profile-beta
DB_PASS=<redacted>
DB_NAME=afluenta
SERVER_USER=www-data
SERVER_GROUP=www-data
CONFIG_SERVER_USER=www-data
CONFIG_SERVER_GROUP=www-data

# aws logs
AWSLOGS_GROUP=afluenta-ecs
AWSLOGS_REGION=us-east-1
AWSLOGS_PREFIX=${ENV}-${GEO}

# VPC
VPC_ID=vpc-<redacted>
SUBNET_IDS=subnet-<redacted>
SECURITY_GROUP=sg-<redacted>,sg-<redacted>
CLUSTER_KEYPAIR=afluenta-ecs-beta

# Cluster
CLUSTER_SIZE=1
CLUSTER_LAUNCH_TYPE=EC2
CLUSTER_REGION=us-east-1
CLUSTER_INSTANCE_TYPE=c5.xlarge

CLUSTER_CONFIG=afl-ecs-cluster-config-beta
CLUSTER_NAME=afl-ecs-web-cluster-beta
CLUSTER_PROFILE=afluenta-ecs-profile-beta

Components

- Images

images
├── efs
├── nginx
├── php
├── platform
├── varnish
└── web

 

Components

- Docker-compose

 

# vim: ts=4 sw=4 et filetype=yaml
version: "3.1"
services:
    memcached:
        image: memcached:alpine
        container_name: afl-memcached
        ports:
            - "11211:11211"

    gearmand:
        image: artefactual/gearmand
        container_name: afl-gearmand

    php:
        image: ${REGISTRY}/afluenta-php-dev:0.0.2
        container_name: afl-php
        working_dir: /afluenta-platform/afluenta_web/web
        hostname: ${HOSTNAME}
        ports:
            - "8080:8080"
        environment:
            PHP_CONFIG: php.ini
            FPM_CONFIG: fpm.conf
            MEMCACHED_CONTENTS_1_HOST: ${MEMCACHED_CONTENTS_1_HOST}
            MEMCACHED_CONTENTS_2_HOST: ${MEMCACHED_CONTENTS_2_HOST}
            MEMCACHED_SESSION_HOST: ${MEMCACHED_SESSION_HOST}
            GEARMAN_HOST: ${GEARMAN_HOST}
            DB_HOST: ${DB_HOST}
            DB_USER: ${DB_USER}
            DB_PASS: ${DB_PASS}
            DB_NAME: ${DB_NAME}
            SERVER_USER: ${SERVER_USER}
            SERVER_GROUP: ${SERVER_GROUP}
            CONFIG_SERVER_USER: ${CONFIG_SERVER_USER}
            CONFIG_SERVER_GROUP: ${CONFIG_SERVER_GROUP}
            HOSTNAME: ${HOSTNAME}
            LOG_PATH_SUFFIX: ${LOG_PATH_SUFFIX}
        volumes:
            - afl-fpm-osx-sync:/afluenta-platform:nocopy
            - ./images/php/conf.d/php.ini:/etc/defaults/php/php.ini
              #- ./images/php/conf.d/php.ini:/usr/local/etc/php/php.ini
            - ./images/php/conf.d/lite_php_browscap.ini:/etc/defaults/php/browscap.ini
            - ./images/php/conf.d/php-fpm.conf:/etc/defaults/php/fpm.conf

    webserver:
        image: ${REGISTRY}/afluenta-nginx:0.0.6
        container_name: afl-webserver
        working_dir: /afluenta-platform
        depends_on:
            - php
        links:
            - php
        environment:
            NGINX_CONFIG: default.conf
        volumes:
            - afl-fpm-osx-sync:/afluenta-platform:nocopy
            - ./images/nginx/conf.d/default.conf:/etc/defaults/nginx/default.conf
        ports:
            - "80:8080"

volumes:
  afl-fpm-osx-sync:
    external: true
            DB_PASS: ${DB_PASS}
            DB_NAME: ${DB_NAME}
            SERVER_USER: ${SERVER_USER}
            SERVER_GROUP: ${SERVER_GROUP}
            CONFIG_SERVER_USER: ${CONFIG_SERVER_USER}
            CONFIG_SERVER_GROUP: ${CONFIG_SERVER_GROUP}
            HOSTNAME: ${HOSTNAME}
            LOG_PATH_SUFFIX: ${LOG_PATH_SUFFIX}
        volumes:
            - afl-fpm-osx-sync:/afluenta-platform:nocopy
            - ./images/php/conf.d/php.ini:/etc/defaults/php/php.ini
            - ./images/php/conf.d/lite_php_browscap.ini:/etc/defaults/php/browscap.ini
            - ./images/php/conf.d/php-fpm.conf:/etc/defaults/php/fpm.conf

    webserver:
        image: ${REGISTRY}/afluenta-nginx:0.0.6
        container_name: afl-webserver
        working_dir: /afluenta-platform
        depends_on:
            - php
        links:
            - php
        environment:
            NGINX_CONFIG: default.conf
        volumes:
            - afl-fpm-osx-sync:/afluenta-platform:nocopy
            - ./images/nginx/conf.d/default.conf:/etc/defaults/nginx/default.conf
        ports:
            - "80:8080"

volumes:
  afl-fpm-osx-sync:
    external: true

Components

- Makefile

~/afluenta-docker $ make
up              Run docker-compose
teardown        Stop running containers
restart         Teardown and up
ps              Containers status
pull            Update container images
logs            Show logs from container (use logs CONTAINER=php|webserver)
~/afluenta-platform $ make
help            This help message
build           Run build (run_build.php -f) (make build BUILD_ARGS='-f')
grunt           Run grunt
grunt-public    Run grunt-public
sync            Sync actions (sync_actions.php)
cc              Clear cache (symfony cc)
sw              Switch geo (Use as make sw GEO=ar|mx|pe DB=nodb|full)
workers         Start gearman workers
logs            Tail logs from queries and phperror.log
exec            Executes a given command in afl-php (make exec CMD=...)
sh              Connect to a sh shell on afl-php in interactive mode
tests           Run test_sms.php

Fin

Questions?

Sources, references, docs, so on so forth...

 

- Great intro to docker: https://medium.freecodecamp.org/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b

- Another presentation on Docker: https://es.slideshare.net/jpetazzo/introduction-docker-linux-containers-lxc

- Docker vs VM: https://devops.com/docker-vs-vms/

Intro to Docker

By Darío Cavuotti