Asmir Mustafic
(and a couple of other tools)
PHP CE 2019 - Dresden - Germany
Cancelled
Berlin
<?php
echo "Hello world";Windows Notepad
C:\\Project\index.php
Apache + mod_php + MySQL
installed on laptop
ftp> put index.phpMore $$$, more users, compute power, environments, tests, configurations....
Docker
$ docker build ...Build
Run
$ docker run ...FROM debian:9.1
RUN apt install nginx -y
COPY nginx.conf /etc/nginx/
USER www-data
CMD ["nginx"]Small
Self-contained
Small
Self-contained
BUILD
RELEASE
RUN
PUSH
RELEASE
<?php
echo "Hello world";public/index.php
PHP + NGINX
docker run ...
docker build ...
docker rm ...
docker ls ...
docker volume ...
docker images ...
...dockerd
~REST API
Default LISTEN socket unix:///var/run/docker.sock
LISTEN tcp://1.2.3.4.5:2375
export DOCKER_HOST="tcp://1.2.3.4:2376"
docker run ...
docker build ...
docker rm ...
docker ls ...
docker volume ...
docker images ...
...docker login
docker logoutClient only
Build
Run
Build
Run
Build
Run
Build
Run
services:
web:
image: goetas/web
command: nginx -f
build:
dockerfile: docker/nginx/Dockerfile
php:
image: goetas/php
build: ./apps/docker/php
cache:
image: redisdocker-compose.yml
FROM php:7.1.6-fpm
# ...
php Dockerfile
FROM nginx:1.17.2
# ...
nginx Dockerfile
$ docker-compose build$ docker-compose upPUSH
get dependencies
run tests
prepare images
(and push images to the registry)
(running build means just running some bash commands)
cp .ci.env .env
export TAG=${CI_GIT_SHA}
export BUILD_ID=${CI_BUILD_ID}
Variables
version: '3.4'
services:
php:
image: goetas/php:${TAG}
build:
context: .
dockerfile: docker/php/Dockerfile
args:
BUILD_ID: ${BUILD_ID}docker-compose.build.yml
version: '3.4'
services:
php:
image: goetas/php:d0be2dc421be4fcd0172e5afceea3970e2f3d940
build:
context: .
dockerfile: docker/php/Dockerfile
args:
BUILD_ID: 878git clone ...
# build images
docker-compose build
# install composer dependencies
docker-compose run --no-deps --rm php \
composer install \
--no-progress --no-interaction \
--no-scripts --no-plugins
# re-build images with vendor
docker-compose buildDependencies
Successfully built d9dd746fcd75
Successfully tagged goetas/php:d0be2dc421be4f
Successfully built d9dd746fcd75
Successfully tagged goetas/web:d0be2dc421be4f# tests
docker-compose run --no-deps --rm php \
vendor/bin/phpunitRun tests
You have tests, right?
PHPUnit 8.3.0 by Sebastian Bergmann and contributors.
...
Time: 0 seconds, Memory: 3.25Mb
OK (3 tests, 4 assertions)# login to docker registry
echo Y | docker login -u "$USR" -p "$PASS"
# push images
docker-compose push Push images to registry
Pushing web (goetas/web)...
The push refers to a repository [docker.io/goetas/web]
latest: digest: sha256:b3dff3e82a0e12b54a10ed083b65fd size: 1786
Pushing php (goetas/php)...
The push refers to a repository [docker.io/goetas/php]
latest: digest: sha256:af07f1e4e3d1a311f35a92d5336dc2 size: 7836BUILD
Build
Run
Build
Run
Build
Run
Build
Run
Build
Run
Build
Run
Build
Run
$ docker swarm initSwarm initialized: current node (bvz81updecsj6wj)
is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-3pu6hszjas19xyp7ghgos \
172.17.0.2:2377
To add a manager to this swarm,
run 'docker swarm join-token manager'
and follow the instructions.Create a cluster (and a manager node)
$ docker swarm join \
--token SWMTKN-1-3pu6hszjas19xyp7ghgos \
172.17.0.2:2377
This node joined a swarm as a manager.Add a worker node to a cluster
$ docker node lsID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
38ciaotwjuri sw-wrk1 Ready Active
e216jshn25ck * sw-man1 Ready Active LeaderList nodes from a manager
TLS authentication
export DOCKER_HOST="tcp://1.2.3.4:2376"
export DOCKER_TLS_VERIFY="1"
export DOCKER_CERT_PATH="/etc/docker/server.pem"
$ docker node lsRELEASE
RELEASE
RUN
docker stack deploy -c docker-stack.yml my_appversion: '3.4'
services:
web:
image: goetas/web
php:
image: goetas/php
cache:
image: redisdocker-stack.yml
export DOCKER_HOST="tcp://1.2.3.4:2375"
docker stack deploy -c docker-stack.yml my_appexport DOCKER_HOST="tcp://1.2.3.4:2375"
docker stack deploy -c docker-stack.yml my_app-stagingMultiple environments
COMPOSE_FILE=a.yml:b.yml:c.ymldocker-compose -f a.yml -f b.yml -f c.yml buildCOMPOSE_FILE=a.yml:b.yml:c.yml docker-compose build.env
docker-compose buildversion: '3.4'
services:
web:
image: goetas/web:${TAG}
build:
context: .
dockerfile: docker/nginx/Dockerfile
php:
image: goetas/php:${TAG}
build:
context: .
dockerfile: docker/php/Dockerfile
args:
BUILD_ID: ${BUILD_ID}docker-compose.build.yml
(only what is necessary for the build)
version: '3.4'
services:
db:
image: postgres:11.4
cache:
image: redis:5.0.5-alpine
docker-compose.yml
Shared configs for all developers
version: '3.4'
services:
web:
ports:
- "8080:80" # 127.0.0.16:80:80
volumes:
- .:/app
php:
volumes:
- .:/app
db:
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data: {}
docker-compose.dev.dist.yml
(copy into docker-compose.dev.yml, ignored by GIT)
Customizations for developers
version: '3.4'
services:
php:
environment:
SECRET_API_KEY: ${TEST_API_KEY}
SMPT_HOST: smtp
volumes:
- ./:/rd
smtp:
image: tophfr/mailcatcher
docker-compose.ci.yml
Customizations for CI and Tests
COMPOSE_FILE=
docker-compose.build.yml: \
docker-compose.yml: \
docker-compose.dev.yml \
// Windows use ;
// COMPOSE_FILE=
// docker-compose.build.yml; \
// docker-compose.yml; \
// docker-compose.dev.yml \
TAG=dev
BUILD_ID=unknown.dist.env
(copy into .env, ignored by GIT!)
COMPOSE_FILE=
docker-compose.build.yml: \
docker-compose.yml: \
docker-compose.ci.yml.ci.env
(copy into .env on CI)
FROM php:7.1.6-fpm
# ...
docker/php/Dockerfile
FROM nginx:1.17.2
# ...
docker/nginx/Dockerfile
cp .dist.env .env
cp docker-compose.dev.dist.yml docker-compose.dev.yml
docker-compose upnode_modules/
var/
vendor/*
.git
.dockerignore
.gitignore
.gitlab-ci.yml
.php_cs.cache
docker-compose*
README.md.dockerignore
Docker is client server
docker build .FROM php:7.3.6-fpm
# ...Exact versions
FROM php:7.3.6-fpm
RUN apt-get update
RUN apt-get install -y nginxRepeatable builds
FROM php:7.3.6-fpm
RUN apt-get update && \
apt-get install -y nginxFROM php:7.3.6-fpm
RUN apt-get update \
&& apt-get install -y git
COPY index.php index.php
COPY src srcCache friendly and fast
FROM php:7.3.6-fpm
COPY src src
COPY index.php index.php
RUN apt-get update \
&& apt-get install -y gitCache origin
version: '3.4'
services:
php:
image: goetas/php:${TAG}
build:
context: .
dockerfile: docker/php/Dockerfile
cache-from:
- goetas/php:${TAG}
- goetas/php:${CACHE_TAG}IMAGES=$(
docker-compose config
| python \
-c 'import sys,yaml,json; json.dump(yaml.load(sys.stdin), sys.stdout)'
| jq -r '([.services[].build.cache_from]|flatten) | del(.[]|nulls)[]'
| sort
| uniq
)
for i in $IMAGES; do docker pull "$i" || true; doneDownload caches
FROM nginx:1.14.0
RUN apt update && \
apt install vim -y
RUN rm -rf /var/cache/apt
Small images
FROM nginx:1.14.0
RUN apt update \
&& apt install vim -y \
&& rm -rf /var/cache/apt
Build arguments
version: '3.4'
services:
php:
image: goetas/php:${TAG}
build:
context: .
dockerfile: docker/php/Dockerfile
args:
BUILD_ID: ${BUILD_ID}FROM php:7.3.6-fpm
ARG BUILD_ID unknown
RUN echo "$BUILD_ID" > config/verson.txtFROM nginx:1.14.0
COPY docker/nginx/www.conf /www.conf
COPY docker/nginx/entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Environment variables everywhere
#!/bin/bash -e
envsubst < /www.conf > /etc/nginx/nginx.conf/entrypoint.sh
server {
listen ${HTTP_PORT};
root /var/www/app/public;
}/www.conf
version: '3.4'
services:
php:
image: goetas/php:${TAG}
logging:
driver: gelf
options:
gelf-address: "udp://logging.myserver.com:12302"none, local, json-file, syslogm journald, gelf, fluentd, awslogs, splunk, etwlogs, gcplogs, logentries
One container on each node of the cluster
version: '3.4'
services:
php:
image: goetas/php:${TAG}
deploy:
mode: globalversion: '3.4'
services:
php:
image: goetas/php:${TAG}
deploy:
replica: 5Run 5 copies of the PHP container
version: '3.4'
services:
php:
image: goetas/php:${TAG}
deploy:
placement:
constraints:
- engine.labels.data-center == eu-west-1
- node.role == frontendDecide on which node place the containers
$ docker node update --add-label "role=frontend" 2l9kajahy2version: '3.4'
services:
php:
image: goetas/php:${TAG}
deploy:
resources:
limits:
cpus: '0.50'
memory: '50M'
reservations:
cpus: '0.25'
memory: '20M'Limit/Reserve CPU or memory
version: '3.4'
services:
web:
image: goetas/web:${TAG}
healthcheck:
test: curl -f -sS http://localhost/health
interval: 20s
timeout: 5s
retries: 2
start_period: 2sCheck container health
Restart on failure
version: '3.4'
services:
web:
image: goetas/web:${TAG}
secrets:
- ssh_private_key
- ssl_certificate
ssh_private_key:
file: ./my_key.rsa
ssl_certificate:
external: trueForward secret credentials/configurations
/run/secrets/ssh_private_key and /run/secrets/ssl_certificate
crated inside the containers
$ docker secret create ssl_certificate my.crtversion: '3.4'
services:
web:
image: goetas/web:${TAG}
deploy:
replicas: 6
update_config:
parallelism: 2
delay: '10s'
order: start-first
rollback_config:
parallelism: 2
delay: '20s'
order: start-firstTiming for container updates/rollback