Docker for PHP Developers Chris Tankersley @dragonmantank php[world] 2017 1
php[world] 2017 Setup! WIFI: “php world”, code is `php2017` Example App: https://github.com/learningcontainers/dockerfordevs Lunch: Around 12:30pm Breaks: Every so often 2
php[world] 2017 What Is Docker? “Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications. Consisting of Docker Engine, a portable, lightweight runtime and packaging tool, and Docker Hub, a cloud service for sharing applications and automating workflows, Docker enables apps to be quickly assembled from components and eliminates the friction between development, QA, and production environments.” 3 https://www.docker.com/whatisdocker/
php[world] 2017 What is a Container? 4
php[world] 2017 Normal Bare-Metal Server 5 CPU RAM HD Network Operating System nginx PHP DB
php[world] 2017 Normal Bare-Metal Server 6 CPU RAM HD Network Operating System nginx PHP DB
php[world] 2017 Virtual Machines 7 CPU RAM HD Network Operating System nginx PHP DB Operating System nginx PHP DB Operating System Hypervisor
php[world] 2017 Containers 8 CPU RAM HD Network Operating System nginxnginx PHP DB PHP DB
php[world] 2017 Containers vs VMs
php[world] 2017 Containers Are Not New • LXC (Linux Containers) • OpenVZ • Systemd-nspawn • BSD Jails • Solaris Zones • chroot 10
php[world] 2017 Containers are just walled processes 11 Ubuntu Kernel / + bin/ + etc/ + dev/ + home/ + usr/ + var/ + lib/ + … nginx bash / + bin/ + etc/ + dev/ + home/ + usr/ + var/ + lib/ + … php
php[world] 2017 What is Docker? 12
php[world] 2017 Docker is an Ecosystem 13 Docker Engine
php[world] 2017 Docker is an Ecosystem 14 Docker ComposeDocker Machine Docker Swarm
php[world] 2017 How does it work? 15 Uses a variety of existing Container technologies Server Containers Hyper-V Containers xhyve Virtualization
php[world] 2017 Sorry OSX < 10.10 and Windows < 10 Users Docker Toolbox 16
php[world] 2017 Let’s use Docker 17
php[world] 2017 Running a container • `docker run` will run a container • This will not restart an existing container, just create a new one • docker run [options] IMAGE [command] [arguments] • [options ]modify the docker process for this container • IMAGE is the image to use • [command] is the command to run inside the container • [arguments] are arguments for the command 18
php[world] 2017 Running a simple shell 19
php[world] 2017 Running a simple shell 20
php[world] 2017 Running a simple shell 21
php[world] 2017 What’s Going On? 22 Ubuntu Kernel / + bin/ + etc/ + dev/ + home/ + usr/ + var/ + lib/ + … nginx bash / + bin/ + etc/ + dev/ + home/ + usr/ + var/ + lib/ + … php
php[world] 2017 Running Two Webservers 23
php[world] 2017 Running Two Webservers 24
php[world] 2017 Running Two Webservers 25
php[world] 2017 Running Two Webservers 26
php[world] 2017 Running Two Webservers 27
php[world] 2017 Running Two Webservers 28
php[world] 2017 Running Two Webservers 29
php[world] 2017 Running Two Webservers 30
php[world] 2017 Some Notes • All three containers are 100% self contained • Docker containers share common ancestors, but keep their own files • `docker run` parameters: • --rm – Destroy a container once it exits • -d – Run in the background (daemon mode) • -i – Run in interactive mode • --name – Give the container a name • -p [local port]:[container port] – Forward the local port to the container port 31
php[world] 2017 Volumes 32
php[world] 2017 Modifying a running container • `docker exec` can run a command inside of an existing container • Use Volumes to share data 33
php[world] 2017 Persistent Data with Volumes • You can designate a volume with –v • Create a named volume with `volume create` • Volumes can be shared amongst containers • Volumes can mount data from the host system 34
php[world] 2017 Mounting from the host machine 35
php[world] 2017 Mounting from the host machine 36
php[world] 2017 Mounting from the host machine 37
php[world] 2017 Mounting from the host machine 38
php[world] 2017 Mounting from the host machine 39
php[world] 2017 Mounting from the host isn’t perfect • The container now has a window into your host machine • Permissions can get screwy if you are modifying in the container • Most things it creates will be root by default, and you probably aren’t root on the host machine • Host-mounted volumes are not portable at all • OSX and Hyper-V VMs have limited pathings to mount • OSX has poor I/O performance 40
php[world] 2017 Named Data Volumes • Creates a space that becomes persistent • Can be mounted anywhere inside your images • Have our app containers use the data volume to store data • Use ‘editor containers’ to go in and modify data when needed 41
php[world] 2017 vim Tutorial • vim is a Modal text editor • ESC will drop you back to default mode • :new /opt/webconfig/default to create a new file • In default mode, i will get us into interactive (edit) mode • :w to save a file • :q will quit 42
php[world] 2017 Mounting Data Volumes 43
php[world] 2017 Mounting Data Volumes 44
php[world] 2017 Mounting Data Volumes 45
php[world] 2017 Mounting Data Volumes 46
php[world] 2017 Mounting Data Volumes 47
php[world] 2017 Mounting Data Volumes 48
php[world] 2017 Why go through the hassle? • Data volumes are portable, depending on the driver • Data volumes are safer • Separates the app containers from data • Production can use a data volume, dev can use a host volume • Our app containers stay small • Works directly with other tools 49
php[world] 2017 Networking 50
php[world] 2017 Networking • Docker can create multiple network “pools” • Each container gets an IP address • Containers can be attached to multiple networks • Docker network allow service discovery inside networks 51
php[world] 2017 Legacy - Docker Links • Legacy Links work with `--link` • Only works on the legacy “bridge” network • Doesn’t support service discovery • Not worth it to use anymore 52
php[world] 2017 Docker Networks • Discreet IP pool for containers • Containers can be added and removed to the network at whim • Service discovery though ‘--network-alias’ • Can be set up to work across hosts 53
php[world] 2017 Create a network 54
php[world] 2017 Attach to a network 55
php[world] 2017 Ping the web container 56
php[world] 2017 Add another web and kill web1 57
php[world] 2017 BREAK TIME! WOO! 58
php[world] 2017 Other Helpful Commands 59
php[world] 2017 Inspect a container docker inspect [options] CONTAINER_NAME • Returns a JSON string with data about the container • Can also query • docker inspect -f “{{ .NetworkSettings.IPAddress }}” web_server • Really handy for scripting out things like reverse proxies 60
php[world] 2017 Work with images • docker pull IMAGE – Pulls down an image before using • docker images – Lists all the images that are downloaded • docker rmi IMAGE – Deletes an image if it’s not being used 61
php[world] 2017 Containerizing An Application 62
php[world] 2017 Our Goals • Not change our workflow (much) • Run PHP 7, Unit Tests, and webserver • Deploy “easily” 63
php[world] 2017 Just try and run it docker run -d --name d4dapp -v C:dragoProjectsdockerfordevs-app:/var/www/ -p 8080:80 php:apache 64
php[world] 2017 65
php[world] 2017 Checking Logs • Containers log to stdout/stderr • Docker aggregates the logs • Can be viewed with docker logs 66
php[world] 2017 Oops 67
php[world] 2017 Custom Images • PHP images are pretty bare • Lots of times need to install extensions 68
php[world] 2017 Dockerfile • Dockerfile is the configuration steps for an image • Can be created from scratch, or based on another image • Allows you to add files, create default volumes, ports, etc • Can be used privately or pushed to Docker Hub 69
php[world] 2017 docker/Dockerfile FROM php:apache RUN a2enmod rewrite 70
php[world] 2017 Build it docker build -t tag_name ./ • This runs through the Dockerfile and generates the image • We can now use the tag name to run the image 71
php[world] 2017 Build it docker build -t d4dapp docker/ 72
php[world] 2017 73
php[world] 2017 Use the new image docker run -d --name d4dapp -v C:dragoProjectsdockerfordevs-app:/var/www/ -p 8080:80 d4dapp 74
php[world] 2017 Use the new image 75
php[world] 2017 Slightly better 76
php[world] 2017 Install Dependencies 77
php[world] 2017 Running Composer docker run --rm -v c:/Users/drago/.composer:/root/.composer -v c:/Users/drago/Projects/workshop:/app -v c:/Users/drago/.ssh:/root/.ssh composer/composer install 78
php[world] 2017 Better! 79
php[world] 2017 Look at queues! 80
php[world] 2017 docker/Dockerfile FROM php:apache RUN a2enmod rewrite && docker-php-ext-install pdo_mysql 81
php[world] 2017 Rebuild the image docker build -t d4dapp docker/ 82
php[world] 2017 Rebuild the container $ docker rm -f d4dapp $ docker run -d --name d4dapp -v C:dragoProjectsdockerfordevs-app:/var/www/ -p 8080:80 d4dapp 83
php[world] 2017 Progress! 84
php[world] 2017 Docker Compose 85
php[world] 2017 What is Docker Compose? • Multi-container orchestration • A single config file holds all of your container info • Works with Docker Swarm and a few other tools, like Rancher 86
php[world] 2017 Sample docker-compose.yml version: '2' volumes: mysqldata: driver: local services: d4dapp: build: ./docker/ volumes: - ./:/var/www/ ports: - 8080:80 mysqlserver: image: mysql environment: MYSQL_DATABASE: dockerfordevs MYSQL_ROOT_PASSWORD: 's3curep@assword' volumes: - mysqldata:/var/lib/mysql 87
php[world] 2017 No longer use docker run $ docker rm –f d4dapp $ docker-compose up -d 88
php[world] 2017 Now we have 2 containers 89
php[world] 2017 Config for DB now points to the service name 90 <?php return [ 'debug' => true, 'config_cache_enabled' => false, 'db' => [ 'driver' => 'Pdo_Mysql', 'hostname' => 'mysqlserver', 'port' => '3306', 'database' => 'dockerfordevs', 'user' => 'root', 'password' => 's3curep@assword', ], ];
php[world] 2017 Yay! 91
php[world] 2017 Install our DB Migration Software docker run --rm -v c:/Users/drago/.composer:/root/.composer -v c:/Users/drago/Projects/workshop:/app -v c:/Users/drago/.ssh:/root/.ssh composer/composer require robmorgan/phinx 92
php[world] 2017 Set up phinx docker run --rm -v C:UsersdragoProjectsdockerfordevs-app:/app -w /app php:cli php vendor/bin/phinx init 93
php[world] 2017 Run the migration docker run --rm -v C:UsersdragoProjectsdockerfordevs-app:/app -w /app --network dockerfordevsapp_default php:cli php vendor/bin/phinx migrate 94
php[world] 2017 Oops 95
php[world] 2017 Let’s use the existing container docker-compose run --rm -v C:UsersdragoProjectsdockerfordevs-app:/app -w /app d4dapp php vendor/bin/phinx migrate 96
php[world] 2017 Good… 97
php[world] 2017 It Lives! 98
php[world] 2017 Unit Testing docker run --rm -v C:UsersdragoProjectsdockerfordevs-app:/app -w /app d4dapp php vendor/bin/phpunit -c . 99
php[world] 2017 Running the tests
php[world] 2017 Build a service service: testrunner: build: ./docker/ volumes: - ./:/app working_dir: /app command: vendor/bin/phpunit -c . 101
php[world] 2017 Run the tests with the service docker-compose run --rm testrunner 102
php[world] 2017 Running the tests
Docker Machine ZendCon, October 2016 104
What is Docker Machine? • A provisioning tool that is used to set up a box with Docker • Used in Docker Toolbox to create the VM • Supports: • EC2 • Azure • Digital Ocean • Hyper-V • OpenStack • Virtualbox • VMWare php[tek] 2017 105
Why use it? • Makes it very easy to spin up new boxes • Docker Machine handles all of the dirty stuff for you • Docker Toolbox users are already using it • Integrates with Docker Swarm • It is not necessarily portable php[tek] 2017 106
Let’s make a machine! php[tek] 2017 107
Let’s Connect! php[tek] 2017 108
php[world] 2017 BREAK TIME AGAIN! WOO! 109
Production Considerations 110
12 Factor Applications php[tek] 2017 111
1. Codebase One codebase tracked in revision control, many deploys php[tek] 2017 112
Repo Tips • Keep everything in your repository • Tag releases • Never move tags php[tek] 2017 113
2. Dependencies Explicitly declare and isolate dependencies php[tek] 2017 114
Dependencies • Commit both composer.json and composer.lock files • Commit Dockerfiles to the same repo as the codebase php[tek] 2017 115
3. Config Store config in the environment php[tek] 2017 116
Configuration • Anything that is environment specific should move to environment vars • Makes it much easier to build and deploy code • Code cares less what external services it is talking to php[tek] 2017 117
Use Environment Vars • Can specify them one-by-one – docker run ­e VAR_NAME=value • Can specify a file – docker run ­­env­file=filename • Can specify in docker-compose.yml php[tek] 2017 118
4. Backing Services Treat backing services as attached resources php[tek] 2017 119
Everything is “external” • Never talk to local sockets • Don’t make a determination between “locally” hosted and third party • Easier to switch environments • Easier to scale up php[tek] 2017 120
5. Build, release, run Strictly separate build and run stages php[tek] 2017 121
The Workflow • Build step installs dependencies, compiles files, and generates a Build Artifact that can be deployed – Does not contain any deployment configuration • Release step pushes a Build Artifact into an environment – Runs DB migrations, anything needed to happen before running • Run step runs the app fully in the environment php[tek] 2017 122
Tips • Build Artifact can be an image • Builds should be completely reproducible • Release always take a build artifact, never directly from the repo • Tag all your builds • Track all your releases php[tek] 2017 123
Build Step - Start Small • Build your application • Run composer • Run npm/bower • Build JS/CSS • Use the compiled output to build an image with docker build • Push full image to private registry php[tek] 2017 124
docker build • Additional options to look at • -f, --file – Specify a different filename for the Dockerfile • --no-cache – Don’t use a cached layer • --pull – Always pull a new version of the image php[tek] 2017 125
Sample usage docker build --no-cache –f docker/php/phpserver.dockerfile –t prod_php /opt/builds/20161010 php[tek] 2017 126
phpserver.dockerfile FROM php:fpm RUN docker-php-ext-install pdo pdo_mysql COPY ./ /var/www php[tek] 2017 127
6. Processes Execute the app as one or more stateless processes php[tek] 2017 128
Built Into Docker • One Process per container • Allows tools to scale just what needs to be scaled • Allows images to be swapped out as needed php[tek] 2017 129
7. Port Binding Export services via port binding php[tek] 2017 130
Built Into Docker (Again) • Each container gets its own IP and exposes its own ports • Processes should already be talking over a network • Can work with service locators that are port-based php[tek] 2017 131
8. Concurrency Scale out via the process model php[tek] 2017 132
How well does your app handle scaling? php[tek] 2017 133
Built Into Docker (Again) (Again) • One Process per container • Scale up just the container that is needed • App should not care how many instances of each service are running php[tek] 2017 134
9. Disposability Maximize robustness with fast startup and graceful shutdown php[tek] 2017 135
Signals • Docker starts containers fairly quickly • Applications should gracefully shut down, not just die • Docker sends a SIGTERM when shutting down a container • Your CLI apps may need to handle SIGTERM properly – Cal Evans, “Signalling PHP” php[tek] 2017 136
10. Dev/prod Parity Keep development, staging, and production as similar as possible php[tek] 2017 137
11. Logs Treat logs as event streams php[tek] 2017 138
Logging in Docker • Various logging options built in – JSON file (default) – Fluentd – Syslog – Journald – Gelf – Splunk – Aws – Etwlogs – Gcplogs php[tek] 2017 139
Push logs remotely • When possible, push Docker logs to a remote service – Container logs only exist while the container exists • Allows logs to be viewed in a single place • No need to get into actual servers • Can host yourself, or pay for a SaaS • ELK stack is very popular – Docker uses fluentd instead php[tek] 2017 140
Setting up fluentd services:   d4dapp:     build: ./docker/d4dapp     depends_on:       ­ fluentd     volumes:       ­ ./:/var/www/     ports:       ­ 8080:80     logging:       driver: "fluentd"       options:         fluentd­address: 127.0.0.1:24224         tag: apache.access php[tek] 2017 141
Setting up fluentd services:   fluentd:     build: docker/fluentd     depends_on:       ­ elasticsearch     volumes:       ­ ./docker/fluentd/fluent.conf:/fluentd/etc/fluent.conf     ports:       ­ 24224:24224       ­ 24224:24224/udp php[tek] 2017 142
Setting up fluentd FROM fluent/fluentd RUN ["gem", "install", "fluent­plugin­elasticsearch", "­­no­rdoc", "­­no­ri", "­­version",  "1.9.2"] php[tek] 2017 143
Setting up fluentd [See Config File in repo] php[tek] 2017 144
Setting up ElasticSearch and Kibana services:   elasticsearch:     image: elasticsearch     expose:       ­ 9200     ports:       ­ 9200:9200   kibana:     image: kibana     depends_on:       ­ elasticsearch     ports:       ­ 5601:5601 php[tek] 2017 145
Viewing Logs php[tek] 2017 146
Logging notes • docker logs does not work with external logging, only JSON • This example can be cleaned up a bit • Kibana syntax can be a bit odd to work with php[tek] 2017 147
12. Admin Processes Run admin/management tasks as one-off processes php[tek] 2017 148
php[world] 2017 BREAK TIME AGAIN! WOO! 149
Deployment using Docker Compose php[tek] 2017 150
Very Good for Small Deployments • Can be used to augment your dev environment • Works well with Docker Machine php[tek] 2017 151
Create a machine docker-machine create --driver digitalocean --digital-ocean-access-token [token] phpworld2017 php[tek] 2017 152
SunshinePHP 2017 153
Switch to the remote node • Run docker-machine env phpworld2017 & "C:Program FilesDockerDockerResourcesbindocker- machine.exe" env phpworld2017 | Invoke-Expression eval $(docker-machine env phpworld2017) php[tek] 2017 154
Set up docker-compose • Docker Compose allows multiple config files with -f • Have a base docker-compose.yml for Production • Add a secondary one for Development php[tek] 2017 155
version: '2' volumes: mysqldata: driver: local services: nginx: build: context: ./ dockerfile: ./nginx.dockerfile ports: - 80:80 - 443:443 phpserver: build: context: ./ dockerfile: ./phpserver.dockerfile working_dir: /var/www/public mysqlserver: image: mysql environment: [redacted] volumes: - mysqldata:/var/lib/mysql php[tek] 2017 156 docker-compose.yml
version: '2' volumes: mysqldata: driver: local services: nginx: image: nginx volumes: - ./output_dev:/var/www/public:ro - ./app/nginx/default.conf:/etc/nginx/conf.d/default.conf - ./ssl:/etc/nginx/ssl/ phpserver: build: context: ./ dockerfile: ./phpserver.dockerfile working_dir: /var/www/public volumes: - ./app:/var/www/ - ./vendor:/var/www/vendor mysqlserver: image: mysql environment: [redacted] volumes: - mysqldata:/var/lib/mysql php[tek] 2017 157 docker-compose.dev.yml
When doing development docker-compose –f docker-compose.yml –f docker-compose.dev.yml up -d php[tek] 2017 158
When doing a deployment docker-compose up -d php[tek] 2017 159
Other Alternative – Variable Substitution • Docker Compose allows variable substitution inside the file • Wrap variables in ${} • image: ${DEPLOY_VERSION}_php php[tek] 2017 160
When doing a deployment docker-compose up -d php[tek] 2017 161
Docker Swarm php[tek] 2017 162
What is Swarm? • Docker-supplied clustering • Define a series of services that can be deployed php[tek] 2017 163
Setup php[tek] 2017 164 Manager Node 2Node 1
Register a node as a Manager docker swarm init ----advertise--addr 172.16.0.245 php[tek] 2017 165
Add nodes docker swarm join --token [token] 172.16.0.245:2377 php[tek] 2017 166
docker-compose.yml version: '3' services: phpserver: image: php:apache ports: - 80:80 php[tek] 2017 167
Deploy the stack $ docker stack deploy -c docker-compose.yml myapp Creating network myapp_default Creating service myapp_phpserver php[tek] 2017 168
docker-compose.yml version: '3' services: phpserver: image: php:apache ports: - 80:80 php[tek] 2017 169
Deploy the stack $ docker stack deploy -c docker-compose.yml myapp Creating network myapp_default Creating service myapp_phpserver php[tek] 2017 170
docker-compose.yml version: '3' services: phpserver: image: php:apache ports: - 80:80 php[tek] 2017 171
docker-compose.yml version: '3' services: phpserver: image: php:apache ports: - 80:80 php[tek] 2017 172
docker stack ps myapp ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 72mud5othsjf myapp_phpserver.1 nginx:latest node2 Running Running 8 minutes ago wsf3m32u9vcr _ myapp_phpserver.1 php:apache manager1 Shutdown Shutdown 11 minutes ago xf3wyh289bec myapp_phpserver.2 nginx:latest node1 Running Preparing 20 seconds ago fehf1vdx4m0r myapp_phpserver.3 nginx:latest manager1 Running Preparing 20 seconds ago pwnq65e6w7ew myapp_phpserver.4 nginx:latest manager1 Running Preparing 20 seconds ago roxtanjughq8 myapp_phpserver.5 nginx:latest node2 Running Running 20 seconds ago php[tek] 2017 173
php[world] 2017 Thank You! • Software Engineer for InQuest • Author of “Docker for Developers” • https://leanpub.com/dockerfordevs • Co-Host of “Jerks Talk Games” • http://jerkstalkgames.com • http://ctankersley.com • chris@ctankersley.com • @dragonmantank 174

Docker for PHP Developers - php[world] 2017

Editor's Notes

  • #2 &amp;lt;number&amp;gt;