In this tutorial you will learn how to create Docker container (based on CentOS) with PHP 5.6 and Apache web server using supervisor service. PHP code will be run from the host machine. This setup is useful if you need to support legacy PHP application and you don’t want to pollute host machine with another parallel PHP installation. Of course, XDebug will be configured as well.
Requirements
- Installed and working docker. If you don’t have it visit docs.docker.com/install .
- Basic knowledge of Docker.
Note
All config files are available from github: github.com/dribtech/centos7-apache-php56-fpm.
Steps
1. Create new directory, for example centos-apache-php56.
$ mkdir centos-apache-php56
$ cd centos-apache-php56
2. Clone config files from github:
$ git clone https://github.com/dribtech/centos7-apache-php56-fpm.git
or
$ git clone git@github.com:dribtech/centos7-apache-php56-fpm.git
3. Review config files
Or just skip to the next step. 🙂
Dockerfile
Docker file is a text file containing instructions to Docker how to build an image. For very simple images – Dockerfile is the only configuration file needed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
FROM centos:7 USER root LABEL maintainer = "contact@drib.tech" RUN yum -y update && \ yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm && \ yum clean all # mod_fastcgi \ RUN yum -y install --enablerepo=remi httpd \ supervisor \ php56 \ php56-php-common \ php56-php-cli \ php56-php-mbstring \ php56-php-mcrypt \ php56-php-pear \ php56-php-xml \ php56-php-runtime \ php56-php-mysqlnd \ php56-php-fpm \ php56-php-bcmath \ php56-php-pecl-xdebug.x86_64 && \ yum clean all RUN rm -f /etc/httpd/conf.d/welcome.conf COPY supervisord.conf /etc/supervisord.conf COPY php.conf /etc/httpd/conf.d/php.conf COPY www.conf /opt/remi/php56/root/etc/php-fpm.d/www.conf COPY xdebug.ini /etc/opt/remi/php56/php.d/15-xdebug.ini EXPOSE 8080 CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] |
- FROM – tells docker on which existing image our image will be based. I used CentOS.
- USER – which user to use for running the image and for any RUN, CMD and ENTRYPOINT instruction.
- LABEL maintainer – replacement for now deprecated MAINTAINER instruction
- RUN – execute commands, creates new layer based on the previous layer. In this case we use it to install additional packages like apache web server, php56 and supervisor daemon.
- COPY – copies files from host system to the container
- EXPOSE – on which ports Docker container will listen during runtime. In this case we will connect to the apache in the Docker container, from the host system, on the port 8080.
- CMD – which command will be executed when the container is run. In this case supervisord is executed since we are running 2 services (apache and php56-fpm) in one container.
So, basically, building the Docker container is very easy. Just select the base image, and run commands to install or configure the container in very similar way you would do if you were installing GNU/Linux distribution on your server or desktop. You can find appropriate image by running:
$ docker search centos
Which will display various images based on centos. Or explore: hub.docker.com/explore.
/etc/supervisord.conf
It is recommended to have one service per container, but in this example it makes sense to have two services, Apache web server and php56-fpm. Running PHP as FPM (FastCGI Process Manager) has performance benefits, enable us to have more PHP versions installed on the system (if we desire so) and for some distributions (Fedora) older versions of PHP are available only as FPM.
Supervisor enables us to start two (or more) services when the container is started,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[supervisord] logfile=/var/log/supervisord.log ; supervisord log file logfile_maxbytes=50MB ; maximum size of logfile before rotation logfile_backups=10 ; number of backed up logfiles loglevel=error ; info, debug, warn, trace pidfile=/var/run/supervisord.pid ; pidfile location nodaemon=false ; run supervisord as a daemon minfds=1024 ; number of startup file descriptors minprocs=200 ; number of process descriptors user=root ; default user childlogdir=/var/log/ ; where child log files will live [program:php-fpm] command=/opt/remi/php56/root/usr/sbin/php-fpm -c /etc/opt/remi/php56/php-fpm.conf stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:httpd] command=/usr/sbin/httpd stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 |
For more info visit supervisord.org.
Configuring Apache and PHP-FPM
Next step is to configure Apache and PHP-FPM and it is done in the same way as you would do on “ordinary” GNU/Linux distribution. You can find very nice instructions here: www.stephenrlang.com/2018/02/centos-7-apache-2-4-with-php-fpm.
/etc/httpd/conf.d/php.conf
Tell Apache that it should use PHP-FPM:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# https://www.stephenrlang.com/2018/02/centos-7-apache-2-4-with-php-fpm/ # Proxy declaration <Proxy "unix:/opt/remi/php56/root/var/run/php-fpm/www.sock|fcgi://php-fpm"> # we must declare a parameter in here (doesn't matter which) or it'll not register the proxy ahead of time ProxySet disablereuse=off </Proxy> # Redirect to the proxy <FilesMatch \.php$> SetHandler proxy:fcgi://php-fpm </FilesMatch> # # Allow php to handle Multiviews # AddType text/html .php # # Add index.php to the list of files that will be served as directory # indexes. # DirectoryIndex index.php |
/opt/remi/php56/root/etc/php-fpm.d/www.conf
Configure PHP-FPM to use sockets. Copy existing config file (/opt/remi/php56/root/etc/php-fpm.d/www.conf) and change/set this options:
1 2 3 4 5 6 7 |
listen = /opt/remi/php56/root/var/run/php-fpm/www.sock listen.owner = apache listen.group = apache listen.mode = 0660 listen.allowed_clients = 127.0.0.1 |
View complete file: www.conf.
/etc/opt/remi/php56/php.d/15-xdebug.ini
In this case XDebug will auto start every time – just to make things simple for this tutorial.
1 2 3 4 5 6 7 8 9 |
zend_extension=xdebug.so xdebug.remote_enable=1 xdebug.remote_handler=dbgp xdebug.remote_port=9000 xdebug.remote_autostart=1 xdebug.remote_connect_back=1 xdebug.idekey=docker #not needed #xdebug.remote_host=0.0.0.0 |
4. Build the image
$ sudo docker build -t centos7-apache-php56-fpm .
(don’t forget the dot and the end of line)
5. Create test php 5.6 script. For example mine is in /srv/php56test/ .
index.php
1 2 3 |
<?php echo "<h1>".__FILE__ . __LINE__ ."</h2>"; phpinfo(); |
6. Run Docker
$ sudo docker run -dp 8080:80 -v /srv/php56test/:/var/www/html/ centos7-apache-php56-fpm
(replace /srv/php56test/ with path to your test script on the host machine)
Options
- -d starts docker container in the background
- -p maps host port 8080 to port 80 (inside container, Apache is listening on the port 80)
- -v files on the host system at the location /srv/php56test/ will be accessed in the container at the location /var/www/html/
7. Test
Visit http://localhost:8080 with the browser.
Configuring PhpStorm to work with XDebug
- Don’t change Settings : Languages & Frameworks : Debug : DBGp Proxy
- In the top right corner where debug controls are, select “Edit configurations …”.
- Click on the “Add new configuration” plus button and select “PHP Remote Debug”.
- In the name field enter whatever makes sense for you.
- Check the “Filter debug connection by IDE key. For IDE key enter “docker”, since this is the key I choose in the docker image config files.
- Click on the 3 dots in the “Server:” line above.
- Type any name, enter “localhost” for host, “8080” for the port. Debugger is XDebug.
- In my case path on the host machine is /srv/php56test/ . Next to it, in the column “Absolute path on the server” enter /var/www/html/ . Click “Ok”.
- For server select the server you just created. Click “Apply” and “Ok”.
- Put the breakpoint on the echo line in index.php. Make sure that PhpStorm is listening for the PHP Debug connection (headphone, top-right).
- Reload the localhost:8080 .
Cheat sheet
$ sudo docker pull <IMAGE NAME>
Get an image from the repository.
$ sudo docker images
List of top level images, you should see at least
centos7-apache-php56-fpm.
$ sudo docker rmi <IMAGE ID>
Remove the image.
$ sudo docker ps
List of running containers.
$ sudo docker exec -it <CONTAINER ID> bash
Run a command in the running container. In this case it will run bash – which means we can “get inside” of container and execute commands in the shell running in the container.
$ sudo docker top <CONTAINER ID>
Display the running processes of a container
$ sudo docker stop <CONTAINER ID>
Stops the container in more graceful way then the kill command. Stop will first send SIGTERM and the SIGKILL to the processes in the container.
$ sudo docker start <CONTAINER ID>
Starts one or more previously stopped containers.
$ sudo docker kill <CONTAINER ID>
Kill running container. Kill will just send SIGKILL signal. (Think of it like unix cmd kill -9 <pid>).
$ ls -al /var/lib/docker
Usual place where containers and other Docker files are stored. To change the location check the –graph option.
$ sudo docker login –username=<username>
Login to Docker registry with the same credentials you used to register on hub.docker.com
$ sudo docker push <IMAGE NAME>
Push image to the registry.
Links
- docker-curriculum.com
- docs.docker.com
- docs.docker.com/v1.11/engine/reference/commandline/daemon
- hub.docker.com/explore
- www.stephenrlang.com/2018/02/centos-7-apache-2-4-with-php-fpm
- rpms.remirepo.net/wizard
- devrant.com/rants/366708/job-interview