Home  >  Article  >  Backend Development  >  How to tailor a single Nginx image for multiple PHP-FPM containers

How to tailor a single Nginx image for multiple PHP-FPM containers

不言
不言Original
2018-07-09 09:28:522103browse

This article mainly introduces the method of tailoring a single Nginx image for multiple PHP-FPM containers. It has certain reference value. Now I share it with you. Friends in need can refer to it

Recently I've been working on deploying a set of PHP microservices using Docker containers. One of the issues is that our PHP application is set up to work with PHP-FPM and Nginx (rather than a simple Apache/PHP[1] setup as stated here), so two containers are required per PHP microservice (also It is equivalent to two Docker images):

  • PHP-FPM container

  • Nginx container

Assuming that an application runs more than six PHP microservices, including your dev and prod environments, there will eventually be close to 30 containers. Instead of building a unique Nginx image for each PHP-FPM microservice image, I decided to build a separate Nginx Docker image and map the PHP-FPM hostname as an environment variable to a unique configuration file in this image.

How to tailor a single Nginx image for multiple PHP-FPM containers


In this blog post, I will outline my process from method 1 to method 2 above, concluding with an introduction to how to use the new custom Nginx Docker image. Solution to end this blog.
I have made this image open source on GitHub[2], so if this happens to be a problem you often encounter, please feel free to check it out.

Why Nginx?

How to tailor a single Nginx image for multiple PHP-FPM containers

PHP-FPM and Nginx used together can produce better PHP application performance [3], but the disadvantage is that the PHP-FPM Docker image does not default to the PHP Apache image. Bundled with Nginx.
If you want to connect an Nginx container to a PHP-FPM backend, you need to add the DNS records for that backend to your Nginx configuration.
For example, if the PHP-FPM container is running as a container named php-fpm-api, then your Nginx configuration file should read:

nginx
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        # This line passes requests through www.dongfan178.com to the PHP-FPM container
        fastcgi_pass php-fpm-api:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param www.huayi1.cn/ www.dongfan178.com SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param www.00534.cn PATH_INFO $fastcgi_path_info;
    }

If you only serve one PHP-FPM container application, It is possible to hardcode the corresponding name in your Nginx container's configuration file. However, as I mentioned above, each PHP service requires a corresponding Nginx container, so we need to run multiple Nginx containers. Creating a new Nginx image (which we will have to maintain and upgrade later) will be a pain because even managing a bunch of different volumes seems like a lot of work to do to change a single variable name.

First solution: Use the method envsubst mentioned in the Docker documentation

How to tailor a single Nginx image for multiple PHP-FPM containers

At first, I thought it was easy. There is a nice little chapter in the Docker documentation on how to use envsubst[4], but unfortunately this does not work with my Nginx config file:
vhost.conf

nginx
server {
    listen 80;
    index index.php index.html;
    root /var/www/public;
    client_max_body_size 32M;
    location / {
        try_files $uri /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass ${NGINX_HOST}:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

my vhost The .conf file uses several Nginx built-in environment variables. As a result, when I run the following command line mentioned in the Docker documentation, an error message appears: $uri and fastcgi_script_name are not defined.

shell
/bin/bash -c "envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"

These variables are usually passed in by Nginx itself [5], so it is not easy to figure out what they are and how to pass parameters, and this will affect the dynamic configurability of the container

Another Docker image that almost succeeded

How to tailor a single Nginx image for multiple PHP-FPM containers

Next, I started searching for different Nginx base images. I found two, but both of them have not been updated in two years. I started with martin/nginx[6] and tried to see if I could get a working prototype.
Martin's image is a little different because it requires a specific file directory structure. I first added to the Dockerfile:

FROM martin/nginx

Next, I added the app/ empty directory and the conf/ directory containing only a vhost.conf file.
vhost.conf

nginx
server {
    listen 80;
    index index.php index.html;
    root /var/www/public;
    client_max_body_size 32M;
    location / {
        try_files $uri /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass $ENV{"NGINX_HOST"}:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

This is similar to my original configuration file, with only one line modified: fastcgi_pass $ENV{"NGINX_HOST"}:9000;. Now when I want to start an Nginx container and a PHP container called php-fpm-api, I can first compile a new image and then pass it the corresponding environment variable when it runs:

shell
docker build -t shiphp/nginx-env:test .
docker run -it --rm -e NGINX_HOST=php-fpm-api shiphp/nginx-env:test

Success! However, there are two problems that bother me with this method:

  1. The base image version is old and has not been updated in more than two years. This can create security and performance risks.

  2. It seems unnecessary to require an empty directory for an app, plus my files are placed in different directories.

Final solution

How to tailor a single Nginx image for multiple PHP-FPM containers

I think Martin's mirror is a good custom solution choice. So, I forked his repository and built a new Nginx base image that solved the above two problems. Now, if you want to run a dynamically named backend application with an nginx container, you simply do this:

shell
# Pull down the latest from Docker Hub
docker pull shiphp/nginx-env:latest
# Run a PHP container named "php-fpm-api"
docker run --name php-fpm-api -v $(pwd):/var/www php:fpm
# Start this NGinx container linked to the PHP-FPM container
docker run --link php-fpm-api -e NGINX_HOST=php-fpm-api shiphp/nginx-env

如果你想自定义这个镜像,添加你自己的文件或者Nginx配置文件,只需要像下面这样扩展你的Dockerfile:

FROM shiphp/nginx-env
ONBUILD ADD  /etc/nginx/conf.d/

现在我所有的PHP-FPM容器都使用单个Nginx镜像的实例,当我需要升级Nginx、修改权限或者配置一些东西的时候,这让我的生活变得简单多了。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

PHP缓存区ob的介绍

如何配置php客户端(phpredis)并连接Redis

使用PHPstudy在Windows服务器下部署PHP系统

The above is the detailed content of How to tailor a single Nginx image for multiple PHP-FPM containers. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn