Asmir Mustafic
(and a couple of other tools)
June 2017 - Berlin User Group
Software Engineer and Consultant
Germany (Berlin), Italy (Venice), Bosnia
No absolute truth today
collabout.com
How to
"From my local application
to the world?"
FTP / SFTP / ssh / rsync / bash
and so on...
More machines, environments, tests, configurations....
Docker automates the deployment of applications inside software containers.
Docker containers can be deployed on any server that has docker support
Docker divided application dependencies from
operating system dependecies
Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications, whether on laptops, data center VMs, or the cloud.
docker-compose is a tool for defining and running multi-container Docker applications
Docker Machine is a tool that lets you install Docker Engine on virtual hosts, and manage the hosts with docker-machine commands
Docker Share is a tool that allows to export to a single tar.gz file configurations regarind a machine created/imported via docker-machine
https://github.com/grinnery/machine-share
Create a local development environment
with Docker
# docker-compose.yaml
version: '3'
services:
db:
image: postgres:9.6
ports:
- "5432:5432" # used to debug and develop
volumes:
- db_data:/var/lib/postgresql/data/pgdata
php:
image: goetas/php:${TAG}
build:
context: .
dockerfile: docker/php-fpm/Dockerfile
volumes:
- .:/var/www
www:
image: goetas/nginx:${TAG}
build:
context: .
dockerfile: docker/nginx/Dockerfile
ports:
- "8080:80" # used to debug and develop, http://localhost:8080/
volumes:
- .:/var/www
volumes:
db_data: {}
# docker/php/Dockerfile
FROM php:7-fpm
RUN curl https://getcomposer.org/composer.phar > /usr/local/bin/composer \
&& chmod a+x /usr/local/bin/composer
# customized ini directives for my app
# COPY docker/php/ini/app.ini /usr/local/etc/php/conf.d/app.ini
# copy application files
COPY app /var/www/app
COPY bin /var/www/bin
COPY var /var/www/var
COPY src /var/www/src
COPY composer.* /var/www
COPY web/app.php /var/www/web/app.php
WORKDIR /var/www
# install deps
RUN composer install -o -q
# docker/nginx/Dockerfile
FROM nginx:1
COPY docker/nginx/conf /etc/nginx
COPY web /var/www/web
Staging, test and so on...
Create locally your new application
and...
Push your code to a VCS server
Configure you VCS system to trigger a build on some server
github/bitbucket/gitlab
have already integrations with almost every CI server as
travisCI, circleCI, Jenkins, bamboo...
get dependencies
run tests
prepare images
(and push images to the registry [step 3])
run next steps (optional)
trigger deploy
(running build means just running some bash commands)
# build images
docker-compose build
# run containers
docker-compose up -d
# application deps
# docker exec node_container_name npm install
# docker exec other_container_name other command
Dependencies
# load some test data/fixtures into database
# magic command here
# run tests
phpunit
Tests
You have tests, right?
# login to docker registry
docker login -e $EMAIL -u $USERNAME -p $PASSWORD
# set the target version
export TAG="$BRANCH_NAME"
# rebuild to include composer vendor folder (depends on your app)
docker-compose build
# push to docker registry
docker-compose bundle --push-images
Step 3. push to docker registry
Decide if deploy or not
based mostly on
commit content / branch name / or something else
# create our instance, if not already done
docker-machine create --driver amazonec2 aws01
# syntax docker-machine
# docker-machine create [options] --driver [driver-options] machine-name
# export machine credentials to a file named aws01.tar.gz
machine-export aws01
This code can be executed on the CI server or manually
(depends on workflow)
# get docker machine credentials
machine-import aws01.tar.gz
# tell docker client to use instance aws01
eval $(docker-machine env aws01)
# set the deploy target
export TAG="$BRANCH_NAME"
# download latest docker images
docker-compose -f docker-compose.live.yml pull
# start your fresh application
docker-compose -f docker-compose.live.yml up -d
This code is executed on the CI server
# get docker machine credentials
machine-import aws01.tar.gz
# tell docker client to use instance aws01
eval $(docker-machine env aws01)
# set the deploy target
export TAG="$BRANCH_NAME"
# deploy a new application stack
docker stack deploy --compose-file=docker-compose.live.yml my-application-name
# docker-compose.live.yaml
version: '3'
services:
db:
image: postgres:9.6
volumes:
- db_data:/var/lib/postgresql/data/pgdata
php:
image: goetas/php:${TAG}
www:
image: goetas/nginx:${TAG}
ports:
- "1.2.3.4:80:80" # bind to external IP
volumes:
db_data: { }
docker-compose.live.yml
# docker-compose.yaml
version: '3'
services:
db:
image: postgres:9.6
volumes:
- db_data:/var/lib/postgresql/data/pgdata
# ports:
# - "5432:5432"
php:
image: goetas/php:${TAG}
# build:
# context: .
# dockerfile: docker/php-fpm/Dockerfile
# volumes:
# - .:/var/www
www:
image: goetas/nginx:${TAG}
ports:
- "80:80"
# build:
# context: .
# dockerfile: docker/nginx/Dockerfile
# volumes:
# - .:/var/www
volumes:
db_data: { }
docker-compose.yml vs docker-compose.live.yml
Uploads and similar...
Use S3... or other shared volume storages ...
Use Graylog, ELK, syslog.... whatever
Even files... but...
Use redis or similar shared storages!
Database migrations
# after deploy
# run database migrations or other tasks post deploy
docker exec container_name command
.dockerignore
tests
docker-compose*
circle.yml
.git
**/.git
.gitignore
.idea
web/app_dev.php
**.css.map
var/cache/*
var/logs/*
var/sessions/*
var/uploads/*
machine-import
# https://github.com/grinnery/machine-share
machine-export <machine-name>
>> exported to <machine-name>.tar
machine-import <machine-name>.tar
>> imported
Scaling
If your target machine is a swarm master, everything works as usual...
except that you are distributing your application across a cluster of nodes! :)
docker service scale php=10
no downtime deploy (rolling updates)
docker service update php --image=myimage:new-version