随着容器技术的成熟及火热,博主也从最初的无感变为拥趸,于是在某次更换服务器时直接将 PHP 项目(博客)全部容器化,本文记录此过程。
概述
容器的出现拯救了众多运维和开发人员,将其从复杂的运维工作中解放出来,让其专注于代码和功能实现。
容器实现了快速部署和高移植性(类似于 Java)只要支持 Docker 的宿主机不论环境如何都能产生相同的效果。
实际上容器最适合部署无永久数据存储的纯运行环境类项目,目前基于性能等方面考虑,并不推荐数据库容器化。不过随着容器技术的提高,相信性能等瓶颈终将消失。
过程
应他人要求,本文记录了 Typecho (PHP 项目)引擎的博客迁移至容器的过程。
部署基础环境
在 CentOS/RadHat 上安装 Docker 可以参考 从零开始的 Docker 使用教程。
因本环境使用 Debian 系统,因此仅写 Debian 的部署方式。其他发行版请替换包管理器相关命令,容器向命令并无区别。
目前 Docker CE 支持 Debian 9/10 等系统,本文基于 Debian 10 Buster 系统进行操作。
移除旧版本
apt remove docker docker-engine docker.io containerd runc
小贴士:容器的工作目录 /var/lib/docker/ 可以选择手动删除,注意备份旧的镜像等。
安装 Docker CE
更新源并安装依赖
apt update && apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common
添加官方源密钥
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
添加仓库
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
小贴士:此命令会将官方源添加至/etc/apt/sources.list
,实际上推荐将其单独存放至/etc/apt/sources.list.d/docker.list
。
安装 Docker CE
apt install docker-ce docker-ce-cli containerd.io
修改系统启动参数
Debian 系统为了使用内存限制功能,请查看 解决 Docker 启动容器时内存限制失效警告问题。其他发行版请忽略此部分内容。
容器部署
将容器所需文件及逻辑卷准备好
本文文件结构
ll /usr/mystack/
.
├── backups # 备份
├── data # 数据库卷
├── www # 网站文件
│ └── html
├── nginx # 服务配置
│ ├── cert.d
│ ├── conf.d
│ ├── logs.d
│ └── nginx.conf
├── php # 服务配置
│ ├── php.ini
│ └── www.conf
├── sbin # 可执行文件
└── scripts # 脚本文件
拉取镜像
为了安全起见,本文全部镜像使用官方镜像进行构建。
docker pull redis:5-alpine
docker pull nginx:stable-alpine-perl
docker pull php:7-fpm-alpine
docker pull mariadb:latest
docker pull memcached:1-alpine
构建私有网络
容器间互联之前使用 --link
现在此特性已经废弃,在未来的版本可能去除,因此推荐不要使用和依赖此功能,本文使用私有网络来进行容器互联。
docker network create backend
小贴士:创建私有网络(类似于 IaaS 中的 VPC)后,容器之间即可使用容器 Alias 进行通讯( --name 参数中的名称)即可使用,比如数据库可用 mymdb:3306 进行连接。
构建容器
启动数据库
docker run --name mymdb --memory=512m --restart=always --network=backend \
-p 127.0.0.1:3306:3306 \
-v /usr/mystack/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password -d mariadb:latest --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
小贴士:字符集使用 utf8mb4
为了使用 emoji 表情,监听至本地环回是为了使用工具等可连接,方便导入数据。生产环境上可以不将端口挂载出来。
启动网页服务
docker run --name myngx --memory=64m --restart=always --network=backend \
-p 80:80 -p 443:443 \
-v /usr/mystack/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/mystack/nginx/conf.d:/etc/nginx/conf.d \
-v /usr/mystack/nginx/logs.d:/etc/nginx/logs.d \
-v /usr/mystack/nginx/cert.d:/etc/nginx/cert.d \
-v /usr/mystack/www:/var/www -d nginx:stable-alpine-perl
小贴士:限制内存 128M 实际测试时 10 个工作进程大约占用 12M 内存,因此可以适当削减其内存限制阈值。
启动 PHP 服务
docker run --name myphp --memory=512m --restart=always --network=backend \
-v /usr/mystack/php/php.ini:/usr/local/etc/php/php.ini:ro \
-v /usr/mystack/www:/var/www -d php:7-fpm-alpine
小贴士:启动 PHP 时内存限制推荐调整高一些,若系统内存足够时,可以多添加工作进程。
启动 Memcached 服务
docker run --name mymcd --memory=64m --restart=always --network=backend \
-p 127.0.0.1:11211:11211 \
-d memcached:1-alpine
小贴士:memcached 用来缓存 session 内存限制可以根据需要增加或者较减少。
容器优化
此时启动的容器组是无法工作的(报错 500),因为官方的 PHP 镜像内扩展不全,需要安装额外组件,没有数据库相关扩展。
先进入容器
docker exec -it myphp /bin/sh
安装数据库支持及基础依赖 GD 扩展(图片处理相关)
docker-php-ext-install pdo_mysql pdo opcache
apk add --no-cache libxml2-dev libpng-dev
docker-php-ext-install gd xml xmlrpc
安装 igbinary 及 msgpack 扩展
apk add --no-cache autoconf build-base
pecl install igbinary
docker-php-ext-enable igbinary
pecl install msgpack
docker-php-ext-enable msgpack
安装 memcached 及 redis 扩展
apk add --no-cache libmemcached \
libmemcached-libs \
libmemcached-dev \
build-base \
zlib-dev \
php7-dev \
autoconf \
cyrus-sasl-dev
pecl install memcached
docker-php-ext-enable memcached
pecl install redis
docker-php-ext-enable redis
小贴士:编译相关的依赖安装完成后可以删除,使用 apk del
命令即可,安装扩展后需要重启容器才能生效。
迁移项目
将项目文件放入网站目录( /usr/mystack/www/ 中),修改数据库连接方式。将数据库表放入共享的目录中,导入到容器数据库中。或者也可以使用工具远程连接导入(推荐)。
架构优化
将 PHP 的 session 存放到 memcached 中,修改 PHP 的参数。
session.save_handler = memcached
session.save_path = "mymcd:11211"
注意:很多文章中都说save_path
写为tcp://127.0.0.1:11211
,这是不对的!只有 memcache 需要写明协议,memcached 并不需要。
之所以前面将 memcached 监听至本地环回,也是为了在机器上可以连接进行调试。
检查缓存是否成功,使用 stats items
即可查询全部 keys ,类似于 redis 中的 keys *
。
# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
stats items
STAT items:3:number 1
STAT items:3:number_hot 0
STAT items:3:number_warm 0
STAT items:3:number_cold 1
STAT items:3:age_hot 0
STAT items:3:age_warm 0
STAT items:3:age 13
STAT items:3:evicted 0
STAT items:3:evicted_nonzero 0
STAT items:3:evicted_time 0
STAT items:3:outofmemory 0
STAT items:3:tailrepairs 0
STAT items:3:reclaimed 0
STAT items:3:expired_unfetched 0
STAT items:3:evicted_unfetched 0
STAT items:3:evicted_active 0
STAT items:3:crawler_reclaimed 0
STAT items:3:crawler_items_checked 0
STAT items:3:lrutail_reflocked 0
STAT items:3:moves_to_cold 1
STAT items:3:moves_to_warm 0
STAT items:3:moves_within_lru 0
STAT items:3:direct_reclaims 0
STAT items:3:hits_to_hot 0
STAT items:3:hits_to_warm 0
STAT items:3:hits_to_cold 0
STAT items:3:hits_to_temp 0
END
小贴士:需要先使用浏览器打开浏览器访问后后再查询键值对。
查询容器挂载的存储卷
docker inspect --format='{{json .Mounts}}' 容器名 | python3 -m json.tool
附录
相关链接
参考链接
- Get Docker CE for Debian - Docker Docs
- How to install more PHP extensions - Docker Docs
- memcached - PECL
- Compiling shared PECL extensions with the pecl command - PHP
- Sessions support - PHP
- docker-php添加memcached扩展 - 一年三班马同学
本文由 柒 创作,采用 知识共享署名4.0
国际许可协议进行许可。
转载本站文章前请注明出处,文章作者保留所有权限。
最后编辑时间: 2023-08-13 10:01 AM