由于文章内容较长,在此分为三个部分:
上:基础工作和创建mysql容器
中:创建配置php-fpm和nginx容器(本文)
下:安装typecho及Lets Encrypt证书
创建配置php-fpm容器
在项目目录 ~/docker-blog
下创建 php-fpm
目录,用来存储 php-fpm 相关的文件。
本次由于使用了 mysql
数据库,需要安装 php
扩展,而且我们要自定义 php.ini
文件(本次只修改了时区信息⊙︿⊙),因此我们要自己构建一个基于 php:7.3.3-fpm
镜像的新镜像,在 ~/docker-blog/php-fpm
目录下创建 Dockerfile
文件,文件内容如下:
FROM php:7.3.3-fpm
RUN docker-php-ext-install pdo_mysql \
&& mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
这里说明一下
Dockerfile
中的$PHP_INI_DIR
目录指的就是容器实例中的/usr/local/etc/php
目录,在构建php-fpm
新镜像时,我们通过mv ...
命令生成了/usr/local/etc/php/php.ini
文件。对于
php
项目,如果没有设置php.ini
文件,则采用默认配置。
接下来,我们要获取容器相关的配置文件,操作和 创建配置mysql容器 一样,阅读镜像页面的 DESCRIPTION 以及对应的 Dockerfile 文件,这里我们仅需要容器目录中的 /usr/local/etc/php/php.ini-production
文件,执行以下操作:
docker run --name test_php -d php:7.3.3-fpm
docker cp test_php:/usr/local/etc/php/php.ini-production ~/docker-blog/php-fpm/php.ini
docker stop test_php
docker rm test_php
现在,修改 ~/blog/php-fpm/php.ini
修改内容如下:
date.timezone = Asia/Shanghai
这里附录一份 php:7.3.3-fpm
镜像实例中相关的配置文件所在目录(/usr/local/etc
):
/usr/local/etc/
- pear.conf
- php/
- conf.d/
- docker-php-ext-sodium.ini
- php.ini-development
- php.ini-production
- php-fpm.conf
- php-fpm.conf.default
- php-fpm.d/
- docker.conf
- www.conf
- www.conf.default
汇总一下,对于 php-fpm
容器,我们需要映射容器内的相关文件(夹):
/var/www/html
-php
文件的存储目录/usr/local/etc/php/php.ini
- 注意php.ini
文件是我们新构建镜像之后才有的
这里,我们也为以后续步骤做一些铺垫,在项目目录 ~/docker-blog
下创建 website
文件夹,用来存所有站点。
对于 ~/docker-blog/docker-compose.yml
文件,内容修改后如下(这里还定义了 容器依赖 ):
version: '3.7'
services:
mydb:
image: mysql:5.7.25
restart: on-failure
volumes:
- ./mysql/conf/my.cnf:/etc/mysql/conf.d/mysql.cnf:ro
- ./mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=blog123.
networks:
- blog-net
php-fpm:
build: ./php-fpm
volumes:
- ./website:/var/www/html
- ./php-fpm/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mydb
networks:
- blog-net
networks:
blog-net:
这里的 depends_on
只是表示容器间的依赖关系,并不能决定容器的启动顺序,关于控制容器的启动顺序请参考:Control startup and shutdown order in Compose
现在我们回到项目目录下,重新运行 docker-compose
,检查所有容器能否成功启动:
cd ~/docker-blog
docker-compose down
# 编译构建新的镜像
docker-compose build php-fpm
docker-compose up -d
至此,php-fpm
容器的配置告一段落。
创建配置nginx容器
nginx的基本配置
在项目目录 ~/docker-blog
下创建 nginx
文件夹,用于存储 nginx 相关的配置文件,接着再在 nginx
目录创建以下目录:
~/docker-blog/nginx/log
- 日志存储目录~/docker-blog/nginx/conf
- 主配置目录~/docker-blog/nginx/conf/vhost
- 虚拟主机配置目录
执行以下命令:
mkdir -p ~/docker-blog/nginx/log
mkdir ~/docker-blog/nginx/conf
mkdir ~/docker-blog/nginx/conf/vhost
通过阅读 nginx
镜像页面的 DESCRIPTION ,我们了解到下面这几个重要的容器内目录:
/etc/nginx
- 配置文件的存储目录/var/log/nginx
- 日志文件目录/usr/share/nginx/html
- Web站点目录
这里附录一份 nginx:1.15.9
容器中相关的配置文件:
/etc/nginx/
- fastcgi_params
- mime.types
- nginx.conf
- scgi_params
- conf.d/
- default.conf
本次将对 nginx
容器内的以下几个文件(夹)做数据卷映射:
/etc/nginx/nginx.conf
- nginx主配置文件,将对其重写,对应项目目录文件~/docker-blog/nginx/conf/nginx.conf
/etc/nginx/conf.d/
- nginx虚拟主机目录,将对应项目目录~/docker-blog/nginx/conf/vhost/
/var/log/nginx/
- 日志文件目录,将对应项目目录~/docker-blog/nginx/log/
/usr/share/nginx/html/
- Web站点目录,将对应项目目录~/docker-blog/website/
在进行 nginx 之前,我们先创建 typecho 博客项目的站点目录,在项目目录 ~/docker-blog/website
下创建 blog
目录。
接下来在项目目录 ~/docker-blog/nginx/conf
下创建 nginx.conf
文件,文件内容如下(这里引用了 lnmp 软件里的配置):
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 1024m;
client_body_buffer_size 10m;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 120;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
include /etc/nginx/conf.d/*.conf;
}
再在项目目录 ~/docker-blog/nginx/conf/vhost
下,创建 blog.conf
配置文件,文件内容如下:
server {
listen 80;
server_name www.demo.com;
index index.html index.htm;
root /usr/share/nginx/html/blog;
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 1h;
}
location ~ .*\.(js|css)?$ {
expires 12h;
}
location ~ /\. {
deny all;
}
}
完成以上操作后,改写 ~/docker-blog/docker-compose.yml
文件,修改后内容如下:
version: '3.7'
services:
mydb:
image: mysql:5.7.25
restart: on-failure
volumes:
- ./mysql/conf/my.cnf:/etc/mysql/conf.d/mysql.cnf:ro
- ./mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=blog123.
networks:
- blog-net
php-fpm:
build: ./php-fpm
volumes:
- ./website:/var/www/html
- ./php-fpm/php.ini:/usr/local/etc/php/php.ini:ro
depends_on:
- mydb
networks:
- blog-net
nginx:
image: nginx:1.15.9
restart: on-failure
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf/vhost:/etc/nginx/conf.d:ro
- ./nginx/log:/var/log/nginx
- ./website:/usr/share/nginx/html
environment:
- "TZ=Asia/Shanghai"
depends_on:
- php-fpm
networks:
- blog-net
networks:
blog-net:
上面的 docker-compose.yml 文件里,对nginx
容器的时区做了调整,并开启了443
这个为后续做铺垫。
现在我们创建一个测试文件 hello.html
放到项目目录 ~/docker-blog/website/blog
下,内容随便写,这里不附代码了,接着我们执行相应的 docker-compose
命令运行所有容器,并访问地址 *http://www.demo.com/hello.html* ,检查容器是否运行成功,命令如下:
cd ~/docker-blog
docker-compose down
docker-compose up -d
nginx与php-fpm的通信
nginx 与 [php-fpm] 的通信分为两种,一种是 unix socket
,另一个种是 tcp socket
。两者的主要区分在于 tcp socket
支持跨服务器,而 unix socket
则不支持,而且配置文件也不相同,这一点很重要。有关更多的详细信息,请参考:nginx与php-fpm通信。
这里我就选择了 tcp socket
通信模式(理由是处于同一局域网下的不同服务器),同时决定了在 nginx 配置 fastcgi
通信的内容。
下面是这两个通信的配置,注意这是单机模式下的:
# tcp-socket 通信模式
location ~ [^/]\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# unix-socket 通信模式
location ~ [^/]\.php(/|$) {
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
下面讲一个不恰当的故事:一位顾客去银行办理业务,去了501房间,这时候501房间的经理发现自己解决不了顾客的业务,于是赶忙寻找了解相关业务的人员,帮忙处理业务,并告知业务人员顾客在501房间,业务人员去了501房间,处理完业务并告知了501房间的经理,经理随后送走了客户,整个业务流程结束。
其实上面的流程就是 nginx 与 php-fpm 的交互,浏览器请求 index.php
页面, nginx 在配置项 root
里配置的目录中找到了 index.php
,但发现自己处理不了 php
文件,于是便告诉 php-fpm 文件在 $document_root
目录中,名称叫做 $fastcgi_script_name
(即:index.php
),php-fpm 便在 $document_root
目录中找到 index.php
文件,读取并处理完成后,返回给 nginx,由 nginx 返回浏览器,注意这上面讲的都是 nginx
和 php-fpm
在同一台机器上。
在 ~/docker-blog/docker-compose.yml
文件里,已经对 nginx
和 php-fpm
指向了同一目录(nginx
转发的是相对路径),这样就保证了访问 nginx
容器的文件(请求),在 php-fpm
容器中的站点目录也能找到并处理(通过 SCRIPT_FILENAME
转换路径)。下面将对项目目录文件 ~/docker-blog/nginx/conf/nginx.conf
和 ~/docker-blog/nginx/conf/vhost/blog.conf
文件进行改进,达到与 php-fpm
容器进行交互。
修改 ~/docker-blog/nginx/conf/nginx.conf
文件(nginx主配置文件),修改后内容如下:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 1024m;
client_body_buffer_size 10m;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 120;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
include /etc/nginx/conf.d/*.conf;
}
修改 ~/docker-blog/nginx/conf/vhost/blog.conf
文件(blog站点配置文件),修改后内容如下:
server {
listen 80;
server_name www.demo.com;
index index.html index.htm index.php;
root /usr/share/nginx/html/blog;
location ~ [^/]\.php(/|$) {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/html/blog/$fastcgi_script_name;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 1h;
}
location ~ .*\.(js|css)?$ {
expires 12h;
}
location ~ /\. {
deny all;
}
}
注意上面配置中3项,这里分别说明一下:
index
- 添加了index.php
,如果不配置,访问后续的 typecho 会出现404
的问题。fastcgi_pass php-fpm:9000
- 这里的php-fpm
指的是容器的别名,使用的好处是不用关心具体服务器的IP地址。由于nginx
和php-fpm
是两个不同的容器,但处理同一网络内,所以这里采用tcp socket
的通信方式fastcgi_param SCRIPT_FILENAME /var/www/html/blog/$fastcgi_script_name
- 通过以下三项组合php-fpm
程序就能在自己的服务器(容器)中找到相应的文件了:SCRIPT_FILENAME
- 指的是php
脚本的绝对路径/var/www/html/blog
- 该目录指的是php-fpm
容器中的路径$fastcgi_script_name
- 指的是请求的php
脚本名称(e.g:index.php
)
现在我们在 ~/docker-blog/website/blog
目录下,新建 index.php
文件内容为下:
<?php
phpinfo();
执行 docker-compose
相应命令,重启 nginx
容器,检测是否能正常访问 http://www.demo.com/index.php:
cd ~/docker-blog
docker-compose restart nginx
在正常访问的情况下,我们改进 ~/docker-blog/website/blog/index.php
让其支持访问 MySQL 数据库,修改后脚本如下:
<?php
$db_type = 'mysql';
$host = 'mydb';
$db_port = '3306';
$db_name = 'blog';
$user = 'blog';
$passwd = 'blog123.';
$dsn = "$db_type:host=$host;port=$db_port;dbname=$db_name";
try {
$db_pdo = new PDO($dsn, $user, $passwd);
echo 'successful<br/>';
} catch (PDOException $e) {
die('Error!: '. $e->getMessage() . '<br/>');
}
关于配置中使用的容器名称,因为我们在部署应用之前无法确定IP,而且使用IP也相对麻烦。使用容器名称,实际内部是使用 docker 自带的 DNS 服务,注意要使用 docker 的 DNS 服务,我们必须自己新建网络,无法使用自带的 default
网络(注:DNS 域名解析服务,简单一句话:把域名解析为具体的IP地址)。
本文由 waynelone 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。