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 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
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.
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.
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)
- 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)
- 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 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)
- 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
- 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.
- 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
- 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.
- 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.
- 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.
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
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
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
Using docker compose (1)
version: "2"
services:
web:
build: .
ports:
- "8080:8080"
volumes:
- ./:/code
links:
- redis
redis:
image: redis
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
- Environments
- Images
- Docker-compose
- Makefile
- 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
- Images
images
├── efs
├── nginx
├── php
├── platform
├── varnish
└── web
- 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
- 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
- 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/