由于文章内容较长,在此分为三个部分:
上:基础工作和创建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 -dnginx与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 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。