Deploy your PHP app with
Docker
Asmir Mustafic
(and a couple of other tools)
May 2017 - NomadPHP
Me
Asmir Mustafic
- Twitter: @goetas_asmir
- Github: @goetas
- LinkedIn: @goetas
- WWW: goetas.com
Software Engineer and Consultant
Germany (Berlin), Italy (Venice), Bosnia
Open source
- Doctrine (contributor)
- JMS Serializer (maintainer)
- HTML5-PHP (maintainer)
- XSD2PHP (author)
- Twital (author)
- Many SOAP-related packages...
The problem
How to
"From my local application
to the world?"
The past
FTP / SFTP / ssh / rsync / bash
and so on...
Now
More machines, environments, tests, configurations....
Docker
Docker
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 a set of Tools
docker
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
docker-compose is a tool for defining and running multi-container Docker applications
docker-machine
Docker Machine is a tool that lets you install Docker Engine on virtual hosts, and manage the hosts with docker-machine commands
docker-share
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
Intro
Create a local development environment
with Docker
# docker-compose.yaml
version: '2'
services:
db:
image: postgres:9.6
ports: # used to debug
- "5050:5432"
volumes:
- .docker_data/pg-data:/var/lib/postgresql/data/pgdata
www:
image: goetas/nginx:${TAG}
build: ./docker/nginx
ports: # used to debug and develop, http://localhost:8080/
- "8080:80"
depends_on:
- php
volumes_from:
- data
php:
image: goetas/php:${TAG}
build: ./docker/php-fpm
volumes_from:
- data
data:
image: goetas/data:${TAG}
build: .
volumes:
- .:/var/www
# 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 ini/app.ini /usr/local/etc/php/conf.d/app.ini
WORKDIR /var/www
php
# docker/nginx/Dockerfile
FROM nginx:1
COPY conf /etc/nginx
nginx
# Dockerfile
FROM busybox
COPY . /var/www
VOLUME /var/www
ENTRYPOINT busybox tail -f /dev/null
data
Docker volumes are a good alternative...
docker-compose up
Done!
build, test, commit, repeat
Production?
Staging, test and so on...
The big picture
Step 1. Push code
Create locally your new application
and...
Push your code to a VCS server
The big picture
Step 2. Trigger build
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...
Build responsibilities
-
get dependencies
-
run tests
-
prepare images
(and push images to the registry [step 3])
-
run next steps (optional)
trigger deploy
Build
The CI server runs the build
(running build means just running some bash commands)
Build 1/3
# infrastructure deps
docker-compose up -d --build
# application deps
docker exec php_container_name composer install -o
# docker exec node_container_name npm install
# docker exec other_container_name other command
Dependencies
Build 2/3
# load some test data/fixtures into database
magic command here
# run tests
phpunit
Tests
You have tests, right?
Build 3/3
# rebuild to include composer vendor folder (depends on your app)
docker-compose build data
# login to docker registry
docker login -e $EMAIL -u $USERNAME -p $PASSWORD
# set the target version
export TAG="$BRANCH_NAME"
# push to docker registry
docker-compose bundle --push-images
Step 3. push to docker registry
The big picture
Step 4. Trigger Update
Decide if deploy or not
based mostly on
commit content / branch name / or something else
Where to deploy?
# 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)
The big picture
Step 5. Deploy
# get docker machine credentials
machine-import aws01.tar.gz
# tell docker client to use instance aws01
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
Done!
# docker-compose.live.yaml
version: '2'
services:
db:
image: postgres:9.6
volumes:
- /var/pg-data:/var/lib/postgresql/data/pgdata
data:
image: goetas/data:${TAG}
php:
image: goetas/php:${TAG}
volumes_from:
- data
www:
image: goetas/nginx:${TAG}
ports:
- "80:80"
depends_on:
- php
volumes_from:
- data
docker-compose.live.yml
Extras 1
Database migrations
# after deploy
# run database migrations ot other tasks post deploy
docker exec container_name command
Extras 2
.dockerignore
docker
tests
docker-compose*
circle.yml
Dockerfile
.docker_data
.git
**/.git
.gitignore
.idea
web/app_dev.php
**.css.map
var/cache/*
var/logs/*
var/sessions/*
var/uploads/*
Extras 3
machine-import
# https://github.com/grinnery/machine-share
machine-export <machine-name>
>> exported to <machine-name>.tar
machine-import <machine-name>.tar
>> imported
Extras 4
no downtime deploy
# deploy.sh [tag]
# nginx proxy + docker-gen (https://github.com/jwilder/docker-gen)
# ${name} is the project name
if [ $(docker ps --filter=name="${name}Va" --format "{{.ID}}" | wc -l) = "0" ]; then
project_up="${name}Va"
project_down="${name}Vb"
else
project_up="${name}Vb"
project_down="${name}Va"
fi
export TAG=$1
docker-compose -p $project_up pull
docker-compose -p $project_up up -d
# do health-check on $project_up and invoke docker-gen
docker-compose -p $project_down down -v
Extras 5
Docker swarm
If your target machine is a swarm master, everything works as usual
except that you are distributing your application across a cluster of nodes! :)
Thank you!
Enjoy Docker!
Deploy your app with Docker
By Asmir Mustafic
Deploy your app with Docker
- 1,994