TL;DR
设计模式有助于写出组织结构更为合理的代码,少数实现上也和语言特性有所关系。
设计模式的样例以及说明网上都存在很多的样例,本文作为学习笔记,只简要记录学习过程中的个人理解的一些要点,如有错误,烦请指出。
设计模式有助于写出组织结构更为合理的代码,少数实现上也和语言特性有所关系。
设计模式的样例以及说明网上都存在很多的样例,本文作为学习笔记,只简要记录学习过程中的个人理解的一些要点,如有错误,烦请指出。
集成方法参见 Yaf集成Eloquent 。
集成基类的多个 Model 如果要正确的运行事务,需要保证各个 Model 的实例使用的是同一个数据库连接,在代码上可以通过共用同一个 Illuminate\Database\Capsule\Manager
对象实现。
使用 DB Facade 需要为 Facade 提供已经关联了 db
作为键,以 Illuminate\Database\Capsule\Manager
的实例为值的容器。
PHP 中针对 Redis / MySQL 的长连接是生命周期级别的长连接,对于同一个进程的每一次请求都不会释放当前连接对象。而针对 TCP Socket 级别的连接是否已断开,则交给操作系统维持。
使用 PDO 对 MySQL 开启持久连接,要注意 PHP 执行的进程数量,不能超过 MySQL 设定的最大连接数。
上述结论的前提是使用 phpredis 扩展,PHP 版本为 5.4.41。
Docker作为目前主流的容器技术之一,可以更高效的利用系统资源,拥有更快的启动时间,提供一致的运行环境,能更轻松的维护和扩展。
作为开发者,在这项技术出现多年之后,是时候将他用于加速自己的App的开发、测试、部署阶段了。
本文是个人的学习笔记,目的在于描述如何让一个基于 Nginx + PHP 的应用程序在 Docker 中运行起来。原理性的内容会另起篇幅。
<!– more –>
使用 Ubuntu 16.04 LTS
完成,同样也可以选用 CentOS 7
,因为问题较多,放弃了在 CentOS 6.5
上的尝试(毕竟是很老的系统了)。
1.13
选用了比较喜欢的 Openresty
,版本为 1.13.6.1
,镜像为 openresty/openresty:alpine
。
本文为 7.2.2
,镜像为 php:7.2.2-fpm-alpine3.7
。
如果要用 Docker 运行自己的应用程序,首先要对镜像有一定的了解。
对于 OpenResty 来说,Dockerfile 需要了解的主要是 Nginx 的配置。
从 Dockerfile 中可以看到 nginx.conf 是在构建时拷贝到容器之中的。
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
在 GitHub 上可以看到 nginx.conf 文件的内容:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
可以了解到如下信息:
对于 PHP 来说,Dockerfile 需要了解的至少有如下几个方面:
Docker 在构建镜像时,通过 Dockerfile 对构建镜像的动作进行描述。可以通过分析一下这个文件了解一下选用镜像的特点。
源文件 内容虽然多,但是需要关注的东西并不多,带着之前的问题去阅读这个文件。
这个文件事实上完成的主要是如下几个工作:
在整个文件中没有看到诸如 --prefix
这样的参数,那么可以得知会把这些文件默认安装到 /usr/local/bin/
目录下。
启动一个容器进行验证:
➜ docker run -it --rm php:7.2.2-fpm-alpine3.7 /bin/sh
/var/www/html # ls /usr/local/bin/
docker-php-entrypoint docker-php-ext-install peardev phar.phar phpdbg
docker-php-ext-configure docker-php-source pecl php phpize
docker-php-ext-enable pear phar php-config
文件37行:
ENV PHP_INI_DIR /usr/local/etc/php
在后续构建 configure 阶段(92行开始):
RUN set -xe \
&& apk add --no-cache --virtual .build-deps \
$PHPIZE_DEPS \
coreutils \
curl-dev \
libedit-dev \
libressl-dev \
libxml2-dev \
sqlite-dev \
\
&& export CFLAGS="$PHP_CFLAGS" \
CPPFLAGS="$PHP_CPPFLAGS" \
LDFLAGS="$PHP_LDFLAGS" \
&& docker-php-source extract \
&& cd /usr/src/php \
&& gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \
&& ./configure \
--build="$gnuArch" \
--with-config-file-path="$PHP_INI_DIR" \
--with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \
可以看到也定义了这一个目录。
然而在整个文件中也没有看到拷贝 ini 文件到对应目录的操作,所以这个容器是没有使用 php.ini 文件进行配置的。
如果想要知道当前默认的配置项,不妨进入容器,通过 /usr/local/bin/php -i
进行查看。
类似 php.ini 文件的情况。
这里涉及到一个权限的问题,Docker 可以把应用代码拷贝到容器中,但是也可以通过挂载目录的方式完成,将目录的 owner 设定为当前容器运行的 uid 可以避免权限带来问题。
文件29行可以看到新增了 uid 为 82 的 www-data
用户。
RUN set -x \
&& addgroup -g 82 -S www-data \
&& adduser -u 82 -D -S -G www-data www-data
在构建阶段,也声明了 fpm 运行者为 www-data
:
ENV PHP_EXTRA_CONFIGURE_ARGS --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data
Docker 容器之间不能直接访问,可以用 link 的方式,也可以直接把端口映射到主机端口上,通过主机的网络进行通信。
需要先行启动 php-fpm 容器。
因为需要配置诸如时区等配置,然而当前容器又没有默认的 php.ini 文件,可以挂载一个自行配置 php.ini 文件。
php.ini
配置文件中将 PHP 错误日志目录定义为 /var/www/logs/php_error.log
,所以挂载可以写入日志的目录到容器中的 /var/www/logs
目录下。
docker run --name=test_phpfpm \
-v /data1/www/etc/test/conf/php/php.ini:/usr/local/etc/php/php.ini:ro \
-v /data1/www/etc/test/conf/php:/usr/local/etc/php/conf.d/:ro \
-v /data1/www/htdocs/test:/var/www/html \
-v /data1/www/logs:/var/www/logs \
-d php:7.2.2-fpm-alpine3.7
php-fpm 的容器名为 test_phpfpm
,与之连接的其他容器可以通过这个名字直接访问容器。
docker run --link=test_phpfpm --name=test_openresty -p 8808:80 \
-v /data1/www/etc/test/conf/nginx/nginx.test.config:/usr/local/openresty/nginx/conf/nginx.conf:ro \
-v /data1/www/etc/test/conf/nginx:/etc/nginx/conf.d/:ro \
-v /data1/www/logs:/usr/local/openresty/nginx/logs \
-v /data1/www/htdocs/test:/var/www/html \
-d openresty/openresty:alpine
对应的 Nginx 配置文件为:
worker_processes 1;
events {
worker_connections 65535;
}
http {
include mime.types;
#default_type application/octet-stream;
default_type text/html;
sendfile on;
keepalive_timeout 65;
server {
listen 80 default_server;
root /var/www/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php($|/) {
fastcgi_pass test_phpfpm:9000;
fastcgi_index index.php;
include fastcgi_params;
set $path_info "";
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param PHP_VALUE open_basedir=$document_root:/tmp/:/proc/:/dev/urandom;
}
}
include /etc/nginx/conf.d/*.conf;
}
至此,在宿主机 /data1/www/htdocs/test
目录下的 PHP 项目可以对外提供服务了。