本文来简单通过 Docker 部署一套可用的 LAMP 环境,在这个过程中你不再需要考虑依赖缺失的问题,不再考虑调整编译参数的问题,这一切都交给 Docker 和成熟可用的 Docker 镜像。
我们需要做的就是将项目路径、文件配置规划好,方便 后期移植、升级、更替容器镜像。
如果你还没安装 Docker 可以参照这篇文章 Docker离线安装及基础操作使用教程 快速安装好 Docker。
规划配置
当前系统采用 debian10 记录,其他系统类似,可以参考。
为移植方便,我们将所有数据存储在一个路径下:/mnt/veracrypt
# Docker 数据存储路径:
mkdir /mnt/veracrypt/docker -p
#MySQL 数据存储路径:
mkdir /mnt/veracrypt/mysql/data -p
#Nginx 配置路径:
mkdir /mnt/veracrypt/nginx -p
#PHP 配置路径:
mkdir /mnt/veracrypt/phpconf -p
#Redis 数据路径:
mkdir /mnt/veracrypt/redis -p
#站点数据路径:
mkdir /mnt/veracrypt/web -p
为后面网络访问通畅,我们为后续要装的这些软件所在容器创建一个公用的 bridge 网络
docker network create b1
查看网络
[email protected]:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
7c1c2ced15f0 b1 bridge local
10fe945000c1 bridge bridge local
efb07245d56e host host local
7b1c4ff2d09e none null local
安装 PHP-FPM
和常规 nginx + php-fpm 部署逻辑一样,先创建一个 php-fpm 容器,稍后再去部署 nginx。
选用镜像,你可以在 https://hub.docker.com/search?q=php&type=image 这里找到你想要的镜像,一般第一条搜索结果是官方的。
我们采用一款第三方镜像,稍微的轻量一点:https://github.com/bitnami/bitnami-docker-php-fpm
下载 git 项目
cd ~ && git clone https://github.com/bitnami/bitnami-docker-php-fpm.git --depth=1
构建 PHP7.4
cd ~/bitnami-docker-php-fpm/7.4-prod/debian-10/ && docker build -t phpfpm:7.4 .
自定义 php 配置
cat >/mnt/veracrypt/phpconf/custom.ini <<\EOF
expose_php = Off
date.timezone = PRC
EOF
创建 php-fpm 容器
docker run -d --name phpfpm-74 -v /mnt/veracrypt/web:/app -v /mnt/veracrypt/phpconf/custom.ini:/opt/bitnami/php/etc/conf.d/custom.ini --network=b1 phpfpm:7.4
解释命令:
- -d 后台守护运行
- --name 将容器命名为 phpfpm-74
- -v 映射绑定外部目录和容器内部目录,其中 /app 为容器内默认的站点根目录。
- --network 将其网络绑定到 b1 中。
composer 使用
这个镜像已经内置了 composer2,你可以直接连入容器使用 bash 操作来更新你的项目依赖;
docker exec -it phpfpm-74 bash
或者直接使用:
docker exec -it -v $PWD:/app phpfpm-74 composer install --ignore-platform-reqs
设置权限:
之所以将用户改为 daemon 是因为这个 phpfpm 的镜像中,php-fpm.ini 中默认用户是 daemon 。
# 容器外
cd /mnt/veracrypt/web && chown -R daemon:daemon . && chmod -R 775 .
# 容器内
cd /app && chown -R daemon:daemon . && chmod -R 775 .
安装 MySQL
MySQL采用官方的镜像,参照这里:https://hub.docker.com/_/mysql
拉取镜像
docker pull mysql:5.7
创建MySQL容器
docker run --name mysql --network=b1 -v /mnt/veracrypt/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=your_password -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
解释:
- -e ROOT_PASSWORD= 将你的密码设置为your_password
- -v /mnt/veracrypt/mysql/data:/var/lib/mysql 将你的数据存储在指定位置
- -character-set-server= 及 --collation-server= 指定默认数据库编码
- --network 将其网络绑定到 b1 中。
使用mysql命令连接到mysql数据库:
docker exec -it mysql mysql -uroot -p
# 之后输入你的mysql密码就可以了
安装 Redis
镜像地址:https://hub.docker.com/_/redis
之前我们创建了Redis存放数据的目录,在这里还需要给他创建一个存放配置文件的目录。
mkdir /mnt/veracrypt/redis/conf
你可以将你自定义的配置信息写入这个配置文件中,需要什么加什么就行了,配置来源可以参考官网或者稍后进入容器后,将配置复制一份出来用作参考。
比如,我给配置文件增加一项登录密码设定:
cat >/mnt/veracrypt/redis/conf/redis.conf <<\EOF
requirepass "redis_password"
EOF
这个Redis为了在容器之间通信方便,已经关闭网络安全保护,即相当于加上了 protected-mode no这一项,不限制任何网络的链接,所以当你打算开放 Redis 链接到公网时,更需要设置密码。
创建Redis容器
docker run --name redis -v /mnt/veracrypt/redis:/data -v /mnt/veracrypt/redis/conf:/usr/local/etc/redis --network=b1 -d redis redis-server /usr/local/etc/redis/redis.conf --appendonly yes
解释:
- -v 绑定数据目录和配置目录。
- --network=b1 将网络连接配置到b1网络中
- --appendonly yes 持久化存储,会将你的所有写操作记录到文件,有利于恢复数据,却占文件系统体积。
- /usr/local/etc/redis/redis.conf 启动时指定加载配置文件
- --network 将其网络绑定到 b1 中。
安装 Nginx
拉取 nginx 最新镜像:
docker pull nginx
创建一份临时 nginx 容器获取其 nginx.conf
docker run --name tmp-nginx-container -d nginx
docker cp tmp-nginx-container:/etc/nginx/nginx.conf $(pwd)/nginx.conf
docker rm -f tmp-nginx-container
查看 nginx.conf ,可以看出他会默认加载 /etc/nginx/conf.d/*.conf 下的配置文件。
这样我们待会儿就只需要绑定这个目录到容器中就能自动加载了,为方便修改 nginx.conf,也将其绑定上。
创建站点目录、配置目录:
mkdir /mnt/veracrypt/web/default/wwwroot -p
mkdir /mnt/veracrypt/web/default/log -p
mkdir /mnt/veracrypt/nginx/conf.d -p
mkdir /mnt/veracrypt/nginx/cache -p
Nginx配置文件示例,你可以将其存放到 /mnt/veracrypt/nginx/conf.d/default.conf 中:
log_format default.log.format '$remote_addr - $remote_user [$time_local] $request'
'$status $body_bytes_sent $http_referer '
'$http_user_agent $http_x_forwarded_for';
server {
listen 80;
listen 443 ssl http2;
server_name default.com;
index index.html index.htm index.php;
root /app/default/wwwroot;
#/root/.acme.sh/default.com/fullchain.cer
ssl_certificate /app/default/fullchain.cer;
#/root/.acme.sh/default.com/default.com.key
ssl_certificate_key /app/default/default.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
if ($scheme != 'https') {
rewrite ^ https://$http_host$request_uri? permanent;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ .*\.(php|php5)?$ {
fastcgi_pass phpfpm-74:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PHP_ADMIN_VALUE "open_basedir=/tmp/:/proc/:/app/default/wwwroot:$document_root";
include fastcgi_params;
}
access_log /app/default/log/access.log default.log.format;
error_log /app/default/log/error.log;
}
重点说明:
phpfpm-74:9000 这里原本是127.0.0.1:9000 的常规配置,在这里使用之前创建的 php-fpm 时指定的名字就可以在 b1 网络中访问到对应的容器了。
同样,在 b1 网络下任意容器中,都可以通过容器名代替IP地址使用。
创建 nginx 容器
docker run --name nginx \
-v /mnt/veracrypt/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /mnt/veracrypt/nginx/cache:/var/cache/nginx \
-v /mnt/veracrypt/nginx/conf.d:/etc/nginx/conf.d:ro \
-v /mnt/veracrypt/web:/app \
-p 80:80 -p 443:443 --network=b1 -d nginx
如果你在宿主机安装了 acme.sh 可以使用下面的命令:
docker run --name nginx \
-v /mnt/veracrypt/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /mnt/veracrypt/nginx/cache:/var/cache/nginx \
-v /mnt/veracrypt/nginx/conf.d:/etc/nginx/conf.d:ro \
-v /mnt/veracrypt/web:/app \
-v ~/.acme.sh:/root/.acme.sh \
-p 80:80 -p 443:443 --network=b1 -d nginx
解释:
- --network 将其网络绑定到 b1 中。
- -v 分别绑定了主要 nginx.conf 配置,虚拟主机配置文件目录 conf.d/*.conf,nginx的cache目录,网站的起始根目录,acme.sh的脚本目录。
- -p 绑定80和443端口
容器网络
在上面 nginx 的配置过程中,也介绍了可以通过容器名代替IP使用,比如 phpfpm-74:9000 替代 127.0.0.1:9000。
同样,在 php项目的配置文件中填写关于redis、mysql的host地址信息时,可以用容器名代替,如:
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
...
REDIS_HOST=redis
REDIS_PORT=6379
测试可以通过curl
curl nginx:80
curl mysql:3306
curl redis:6379
开机自启
将以上创建的容器更新为开机自启:
docker update --restart=always mysql
docker update --restart=always nginx
docker update --restart=always phpfpm-74
docker update --restart=always redis
计划任务
如果你想执行计划任务,这比以往复杂一点。
建议还是在宿主机调度计划任务,前提也需要将容器运行起来,如果容器挂了那么就会失败。
这里以 laravel 项目的计划任务调度写法举例:
* * * * * docker exec -it phpfpm-74 bash -c "cd /app/default/wwwroot && php artisan schedule:run"