How to Deploy PHP Development Environment With Docker

This article mainly introduces how to use Docker to build a PHP development environment. The author also explores whether to build a Docker-based development environment using a single container or multiple containers. Recommended for PHP developers. I hope to be helpful.

Environment deployment has always been a big problem, whether it is a development environment or a production environment, but Docker packages the development environment and production environment in a lightweight way to provide a consistent environment. Greatly improved the consistency of development and deployment. Of course, the actual situation is not so simple, because the configuration of the production environment and the development environment are completely different, such as logging and other issues need to be configured separately, but at least it is simpler and more convenient than here. PHP development is used as an example to explain how Docker Layout the development environment.

In general, a PHP project will require the following tools:

  1. Web server: Nginx / Tengine
  2. Web Application: PHP-FPM
  3. Database: MySQL / PostgreSQL
  4. Cache service: Redis / Memcache

This is the simplest architectural method. In the early days of Docker development, Docker was abused a lot. For example, multiple services are started in one image. The log collection is still based on Syslog or other old methods. The image capacity is very large and the basic image can be reached. 80M, which is completely different from the idea originally proposed by Docker, and the Alpine Linux distribution as a lightweight Linux environment is very suitable as a Docker base image. Docker officially recommends using Alpine instead of Debian as the base image. Existing official images will also be migrated to Alpine. All images in this article will be based on Alpine.

Nginx / Other

In this part, the author has explained the Docker practice of Tengine in the Nginx practice of Docker container, and given the Dockerfile. Since Tengine is preferred, and the official Alpine image of Nginx has been given, so Tengine is used here. I have uploaded the image to the official DockerHub.

docker pull chasontang/tengine:2.1.2_f

Get the image, see Dockerfile for details.

PHP-FPM

Docker official has provided the 7.0.7-fpm-alpine image of PHP. The Dockerfile is as follows:

FROM alpine:3.4

 

# persistent / runtime deps

ENV PHPIZE_DEPS \

    autoconf \

    file \

    g++ \

    gcc \

    libc-dev \

    make \

    pkgconf \

    re2c

RUN apk add --no-cache --virtual .persistent-deps \

    ca-certificates \

    curl

 

# ensure www-data user exists

RUN set -x \

  && addgroup -g 82 -S www-data \

  && adduser -u 82 -D -S -G www-data www-data

# 82 is the standard uid/gid for "www-data" in Alpine

# http://git.alpinelinux.org/cgit/aports/tree/main/apache2/apache2.pre-install?h=v3.3.2

# http://git.alpinelinux.org/cgit/aports/tree/main/lighttpd/lighttpd.pre-install?h=v3.3.2

# http://git.alpinelinux.org/cgit/aports/tree/main/nginx-initscripts/nginx-initscripts.pre-install?h=v3.3.2

 

ENV PHP_INI_DIR /usr/local/etc/php

RUN mkdir -p $PHP_INI_DIR/conf.d

 

##<autogenerated>##

ENV PHP_EXTRA_CONFIGURE_ARGS --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data

##</autogenerated>##

 
ENV GPG_KEYS 1A4E8B7277C42E53DBA9C7B9BCAA30EA9C0D5763

ENV PHP_VERSION 7.0.7

ENV PHP_FILENAME php-7.0.7.tar.xz

ENV PHP_SHA256 9cc64a7459242c79c10e79d74feaf5bae3541f604966ceb600c3d2e8f5fe4794

RUN set -xe \

  && apk add --no-cache --virtual .build-deps \

    $PHPIZE_DEPS \

    curl-dev \

    gnupg \

    libedit-dev \

    libxml2-dev \

    openssl-dev \

    sqlite-dev \

  && curl -fSL "http://php.net/get/$PHP_FILENAME/from/this/mirror" -o "$PHP_FILENAME" \

  && echo "$PHP_SHA256 *$PHP_FILENAME" | sha256sum -c - \

  && curl -fSL "http://php.net/get/$PHP_FILENAME.asc/from/this/mirror" -o "$PHP_FILENAME.asc" \

  && export GNUPGHOME="$(mktemp -d)" \

  && for key in $GPG_KEYS; do \

    gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \

  done \

  && gpg --batch --verify "$PHP_FILENAME.asc" "$PHP_FILENAME" \

  && rm -r "$GNUPGHOME" "$PHP_FILENAME.asc" \

  && mkdir -p /usr/src \

  && tar -Jxf "$PHP_FILENAME" -C /usr/src \

  && mv "/usr/src/php-$PHP_VERSION" /usr/src/php \

  && rm "$PHP_FILENAME" \

  && cd /usr/src/php \

  && ./configure \

    --with-config-file-path="$PHP_INI_DIR" \

    --with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \

    $PHP_EXTRA_CONFIGURE_ARGS \

    --disable-cgi \

# --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself)

    --enable-mysqlnd \

# --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)

    --enable-mbstring \

    --with-curl \

    --with-libedit \

    --with-openssl \

    --with-zlib \

  && make -j"$(getconf _NPROCESSORS_ONLN)" \

  && make install \

  && { find /usr/local/bin /usr/local/sbin -type f -perm +0111 -exec strip --strip-all '{}' + || true; } \

  && make clean \

  && runDeps="$( \

    scanelf --needed --nobanner --recursive /usr/local \

      | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \

      | sort -u \

      | xargs -r apk info --installed \

      | sort -u \

  )" \

  && apk add --no-cache --virtual .php-rundeps $runDeps \

  && apk del .build-deps

COPY docker-php-ext-* /usr/local/bin/

##<autogenerated>##

WORKDIR /var/www/html

RUN set -ex \

  && cd /usr/local/etc \

  && if [ -d php-fpm.d ]; then \

    # for some reason, upstream's php-fpm.conf.default has "include=NONE/etc/php-fpm.d/*.conf"

    sed 's!=NONE/!=!g' php-fpm.conf.default | tee php-fpm.conf > /dev/null; \

    cp php-fpm.d/www.conf.default php-fpm.d/www.conf; \

  else \

    # PHP 5.x don't use "include=" by default, so we'll create our own simple config that mimics PHP 7+ for consistency

    mkdir php-fpm.d; \

    cp php-fpm.conf.default php-fpm.d/www.conf; \

    { \

      echo '[global]'; \

      echo 'include=etc/php-fpm.d/*.conf'; \

    } | tee php-fpm.conf; \

  fi \

  && { \

    echo '[global]'; \

    echo 'error_log = /proc/self/fd/2'; \

    echo; \

    echo '[www]'; \

    echo '; if we send this to /proc/self/fd/1, it never appears'; \

    echo 'access.log = /proc/self/fd/2'; \

    echo; \

    echo 'clear_env = no'; \

    echo; \

    echo '; Ensure worker stdout and stderr are sent to the main error log.'; \

    echo 'catch_workers_output = yes'; \

  } | tee php-fpm.d/docker.conf \

  && { \

    echo '[global]'; \

    echo 'daemonize = no'; \

    echo; \

    echo '[www]'; \

    echo 'listen = [::]:9000'; \

  } | tee php-fpm.d/zz-docker.conf

EXPOSE 9000

CMD ["php-fpm"]

##</autogenerated>##

First, the image inherits from the alpine: 3.4 image. Use the apk command to install PHP’s minimum dependencies. At the same time, add www-data as the running user of php-fpm. Specify the php configuration file to / usr / local / etc / php, then download php-src, compile and install, you can refer to the php compile and install article I wrote before. The parameters are quite satisfactory. The installation directory is specified to /usr/local, then scanelf is used to obtain a list of dependent runtime libraries, and other installation packages are deleted. Copy docker-php-ext-configure, docker-php-ext-enable, docker-php-ext-install to the container, these three files are used for subsequent installation of extensions. Then copy php-fpm.conf to the configuration directory, specify error_log and access_log to the terminal standard output, daemonize = no means not to run as a service process. The EXPOSE 9000 port is used to communicate with other containers, and then CMD [“php-fpm”] runs php-fpm. And the working directory is specified to /var/www/html.

docker-compose

Now that we have the base image, we can use the base image to configure the container, but starting the container through the manual docker command will be very troublesome. Fortunately, the official docker-compose command has been provided to orchestrate the container. You only need to write a docker-compose.yaml file. For details, please refer to the official documentation.

version: '2'

services:

 php-fpm:

  image: php:7.0.7-fpm-alpine

  volumes:

   - "./src:/var/www/html"

  restart: always

 

 tengine:

  depends_on:

   - php-fpm

  links:

   - php-fpm

  image: chasontang/tengine:2.1.2_f

  volumes:

   - "./nginx.vh.default.conf:/etc/nginx/conf.d/default.conf"

  ports:

   - "80:80"

  restart: always

Very easy to understand, two services are defined here. Php-fpm depends on the php: 7.0.7-fpm-alpine image, and the src folder is mapped to the /var/www/html folder. The tengine service depends on the php-fpm service. And link the php-fpm service so that it can communicate with the php-fpm container over the network. The tengine service is based on the chasontang/tengine:2.1.2_f image and maps the nginx.vh.default.conf file to /etc/nginx/conf.d/default.conf file. Then look at nginx.vh.default.conf

server {

  listen    80;

  server_name localhost;

 

  #charset koi8-r;

 

  #access_log logs/host.access.log main;

 

  location / {

    root  html;

    index index.html index.htm;

  }

 

  #error_page 404       /404.html;

 

  # redirect server error pages to the static page /50x.html

  #

  error_page  500 502 503 504 /50x.html;

  location = /50x.html {

    root  html;

  }

 

  # proxy the PHP scripts to Apache listening on 127.0.0.1:80

  #

  #location ~ \.php$ {

  #  proxy_pass  http://127.0.0.1;

  #}

 

  location ~ [^/]\.php(/|$) {

    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    fastcgi_pass php-fpm:9000;

    fastcgi_index index.php;

    fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;

    fastcgi_param PATH_INFO $fastcgi_path_info;

    include fastcgi_params;

  }

 

  # deny access to .htaccess files, if Apache's document root

  # concurs with nginx's one

  #

  #location ~ /\.ht {

  #  deny all;

  #}

}

All the files, because /etc/nginx/nginx.conf uses include /etc/nginx/conf.d/*.conf; This directory is included, that is, you don’t need to manage other configurations of nginx, just use You can replace the default virtual host configuration with your own nginx virtual host configuration, or add a virtual host configuration.

As you can see from the above, the default.conf file defines a location that matches a URL containing .php, then splits it out of the PATH_INFO parameter, and passes these variables to the php-fpm:9000 php-fpm service.

It should be noted here that because Nginx and PHP-FPM are not on the same host, Nginx only performs static file processing and routing and forwarding. The actual PHP file execution occurs in the PHP-FPM container. So the SCRIPT_FILENAME variable must use the directory in the PHP-FPM container, so here it is specified using hard coding. Of course, it is also possible to let two containers share the same data volume, but the author believes that this is only for the convenience of container orchestration, and the other is completely unhelpful.

It’s easy! Now we can quickly start and update the environment.

The above is the details of how to deploy PHP development environment using Docker

#php #docker

How to Deploy PHP Development Environment With Docker
12.25 GEEK