docker-compose 搭建 dnmp 总结(附踩坑指南)
说明
从零开始写一份dnmp环境的docker-compose.yml(由于redis比较常用,也包括进来)。总体设计示意图:
网络分配上,让要直接通讯的容器同属于一个网络,不直接通讯的容器属于不同的网络,这样实现网络的隔离,如上图所示,Nginx和PHP-FPM同属于网络A,PHP-FPM、Redis和MySQL同属于网络B。数据存放上,将项目代码存放在宿主机上的folderA,同时创建数据卷映射到Nginx和PHP-FPM中。
目录规划如下:
├─conf # 1. 配置文件目录
│ ├─mysql # mysql配置文件目录,下同
│ │ my.cnf # 事先准备好的默认配置文件,下同
│ ├─nginx
│ │ │ nginx.conf
│ │ └─conf.d
│ │ default.conf
│ ├─php
│ │ │ php.ini
│ │ └─conf.d
│ ├─redis
│ │ redis.conf
│ └─supervisor
│ supervisord.conf
├─data # 2. 数据库数据、项目代码目录,可按mysql、php等目录划分
├─dockerfiles # 3. 存放Dockerfile的目录
│ Dockerfile.php73
├─log # 4. 日志目录,可按mysql、php等目录划分
└─ssl # 5. https证书文件存放目录
docker-compose.yml文件大概结构如下:
接下来我们逐个服务编写配置、调试和解决遇到的问题。
注:宿主机系统为 Ubuntu 18,所有命令都是用非root账号运行
Redis
配置
redis:
image: redis:latest # 使用最新镜像
volumes:
- ./data/redis:/data # 数据目录
- ./conf/redis/redis.conf:/etc/redis/redis.conf # 配置文件
networks:
- mysql
ports:
- "6379:6379"
sysctls:
- net.core.somaxconn=1024
command: > # 注意多个命令时的写法
bash -c "echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
&& redis-server /etc/redis/redis.conf --appendonly yes"
遇到的问题
docker-compose.yml文件所在目录下,运行:docker-compose up redis,有如下错误信息:
报错:WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
解决:如上面的配置所示,添加:
sysctls: - net.core.somaxconn=1024
报错:WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add ‘vm.overcommit_memory = 1’ to /etc/sysctl.conf and then reboot or run the command ‘sysctl vm.overcommit_memory=1’ for this to take effect.
解决:如配置所示,command键中添加:
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
,该设置依赖宿主机,所以同时在宿主机中也要运行该命令。报错:WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command ‘echo never > /sys/kernel/mm/transparent_hugepage/enabled’ as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
解决:宿主机终端中依次运行:
echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag
MySQL
配置
mysql:
image: mysql:latest # 使用最新的版本
volumes:
- ./data/mysql:/var/lib/mysql # 数据目录
- ./conf/mysql/my.cnf:/etc/mysql/my.cnf # 配置文件
networks:
- mysql
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root # 密码设置,注意改成自己的密码
# 设置密码加密驱动,原因参见:https://learnku.com/articles/34823
command: --default-authentication-plugin=mysql_native_password
遇到的问题
mysqld: Can’t create/write to file ‘/var/lib/mysql/is_writable’ (Errcode: 13 - Permission denied)
解决:这个问题网上给出的方法是:将运行mysql的用户设置成当前的用户,比如,添加配置:
user: "1000:50"
, 或者user:"999:999"
, 但这用户1000或999是怎么获取的呢?于是,我找到更接近本质的方法是先获取当前用户,然后再添加到配置,比如,添加配置,user: ${CURRENT_UID}
,然后每次运行时,都要在宿主机上先运行:CURRENT_UID=$(id -u):$(id -g)
。
总觉得这样的方法不太完美,思来想去,决定先在宿主机查一下,当前运行mysql的用户,终端运行top
命令,发现其运行的用户是999,运行cat /etc/group
查看用户所属的组,发现最后有一行docker
,999用户是属于docker组的,于是,将我当前宿主机使用的用户(ubuntu)也添加到docker组,即运行:999
sudo usermod -aG docker ubuntu
。随后,再运行docker-compose up mysql
就不再有这个报错了。(记得将之前添加的user: ${CURRENT_UID}
配置删掉)
Nginx
配置
nginx:
image: nginx:alpine # 使用Alpine Linux,其内核比较小,大大较少镜像体积
volumes:
- ../project:/var/www/html # 项目源码所在目录
- ./conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # 主配置,设置read-only
- ./conf/nginx/conf.d:/etc/nginx/conf.d:ro
- ./log/nginx:/var/log/nignx
- ./ssl:/etc/nginx/ssl
networks:
- nginx
ports:
- "80:80"
- "443:443"
php-fpm
这一部分比较复杂,需要安装一些扩展,编译出新的镜像,所以使用到了Dockerfile文件。
配置
php-fpm73:
build:
context: . # 构建镜像的上下文
dockerfile: dockerfiles/Dockerfile.php73 # 指定Dockerfile文件,根据上下文找到地址
volumes:
- ../project:/var/www/html # 项目源码所在目录
- ./conf/php:/usr/local/etc/php
- ./conf/php/conf.d:/usr/local/etc/php/conf.d
- ./conf/supervisor:/etc/supervisor/conf.d
networks:
- mysql
- nginx
ports:
- "9000:9000"
遇到的问题
- 安装Laravel项目时,发现提示gd扩展不存在
- 解决*:之前在其他机子运行时是直接可用的,进入php-fpm的容器,运行
php --ini
,输出:
/usr/local/etc/php/conf.d中并没有额外的配置,我在另外的主机运行,是有额外配置的:Configuration File (php.ini) Path: /usr/local/etc/php Loaded Configuration File: /usr/local/etc/php/php.ini Scan for additional .ini files in: /usr/local/etc/php/conf.d Additional .ini files parsed: (none)
调整配置,重新编译,还是不行,最后只能手动修改php.ini,添加:Loaded Configuration File: /usr/local/etc/php/php.ini Scan for additional .ini files in: /usr/local/etc/php/conf.d Additional .ini files parsed: /usr/local/etc/php/conf.d/docker-php-ext-gd.ini, /usr/local/etc/php/conf.d/docker-php-ext-imagick.ini, /usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini, /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini, /usr/local/etc/php/conf.d/docker-php-ext-pcntl.ini, /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini, /usr/local/etc/php/conf.d/docker-php-ext-redis.ini, /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini, /usr/local/etc/php/conf.d/docker-php-ext-swoole.ini, /usr/local/etc/php/conf.d/docker-php-ext-zip.ini
最后,顺利安装Laravel项目。extension=gd.so
完整的配置文件和常用命令
所有配置参见:https://github.com/HubQin/dnmp
运行git clone https://github.com/HubQin/dnmp.git
,下载配置后,切换到dnmp目录,运行:docker-compose up -d
即可开启dnmp环境,注意在dnmp文件夹外部会生成一个project目录(如果没有的话),是用来方项目代码的。
docker-compose常用的命令有:
docker-compose up -d
后台运行docker-compose.yml 配置的所有服务- 进入容器,比如,进入php-fpm73容器,方式A:
docker container exec -it dnmp_php-fpm73_1 /bin/bash
,dnmp_php-fpm73_1
为容器名称,可以通过docker ps
查看;方式B:docker-compose exec php-fpm73 bash
,php-fpm73
为服务名称(docker-compose.yml 中配置的名称),注意该命令需在docker-compose.yml 所在目录下运行或者指定docker-compose.yml 所在位置。 - 重新编译镜像,
docker-compose build php-fpm73
- 指定后台启动php-fpm73服务:
docker-compose up -d php-fpm73
- 停止所有服务:
docker-compose stop
- 停止所有服务并删除容器:
docker-compose down
本作品采用《CC 协议》,转载必须注明作者和本文链接
请问出现以下错误:ERROR: Service 'php-fpm73' failed to build : Get registry-1.docker.io/v2/library/ph...: unauthorized: incorrect username or password 这是什么情况?无效的用户名和密码?
已解决:需要登录docker
参考 github.com/shunhua/dnmp