参考:阮一峰Docker 入门教程、犬小哈、Docker 日常命令大全、
From: https://www.nodeseek.com/post-32012-1
由于最近的lnmp.org一键包投毒事件,不太敢再继续用lnmp一键包来装lnmp环境了。个人不太喜欢用面板,不如乘着这个机会把环境移植到docker去。用docker最大的好处就是全部东西都是官方的,不太担心会被投毒。但是用了这么多年lnmp一键包,还是有点感情的(很多config不想自己手动再搓一遍)。于是决定同时尽量使用来自一键包的各种配置文件。
Docker这边,目标是做出一个lnmp最小环境并全部使用nignx,mysql,php-fpm官方镜像。
太长不看版
https://github.com/anshi233/lnmp-docker
这个repo里包含了理论上走完全文能得到的一个完整lnmp环境。使用方法请参考README。比一键包麻烦一点但是基本上就是跑几行命令的事。
但是还是强烈推荐自己手搓一个环境出来。
Docker架构
经过一段时间研究后,于是决定参考https://lnmp.org/faq/lnmp-software-list.html把关键的配置文件全部映射到docker环境里面去。
Docker大致架构决定如下,主要使用docker compose来达成类似“一键”包的效果。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
├── docker-compose.yml (docker compose 配置文件) ├── dockerfiles (自定义的dockerfile存放文件夹) │ ├── nginx.Dockerfile (nginx 的dockerfile) │ └── php-fpm.Dockerfile (php-fpm 的dockerfile) ├── mysql (mysql相关文件存放文件夹) │ ├── conf.d (.cnf配置文件存放文件夹) │ └── mysql (mysql主要数据库文件存放文件夹) ├── nginx (nginx相关文件存放文件夹) │ ├── conf (nginx配置文件存放文件夹) │ ├── logs (nginx logs文件夹) │ └── wwwlogs (nginx 网站访问log文件夹) ├── php (php相关文件存放文件夹) │ ├── etc (php配置文件夹) │ │ ├── php-fpm.conf (php-fpm主要配置文件) │ │ ├── php-fpm.d (php-fpm额外配置文件存放文件夹) │ │ └── php.ini (php.ini) │ └── var │ └── log (php log存放文件夹) ├── ssl (https ssl证书存放文件夹) ├── www (www用户文件夹,主要存放网站) └── wwwroot (lnmp默认的网站存放文件夹) |
现在,我们可以尝试把lnmp一键包搭建的环境的配置文件复制到以上设计好的docker的目录里去了。
lnmp的环境的配置文件来源很自由,你可以从你已经搭了环境的机器复制过来。或者单开一台临时vps装上lnmp2.0然后复制到其他机器。这里只复制nginx,php,www的文件夹。mysql打算重新创建文件夹并手动导入sql来迁移。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#原目录 docker目录 #nginx /usr/local/nginx/conf --> [你的docker文件夹根目录]/nginx/conf /usr/local/nginx/logs --> [你的docker文件夹根目录]/nginx/logs /usr/local/nginx/wwwlogs --> [你的docker文件夹根目录]/nginx/wwwlogs #php /usr/local/php/etc --> [你的docker文件夹根目录]/php/etc #如果没有/usr/local/php/var/log就创建一个 /usr/local/php/var --> [你的docker文件夹根目录]/php/var #旧版lnmp 有/home/www lnmp2.0没有这个 #也可以复制到其他地方然后软链接过来 /home/www --> [你的docker文件夹根目录]/www /home/wwwroot --> [你的docker文件夹根目录]/wwwroot |
mysql和dockerfile就手动创建
|
1 2 3 4 |
mkdir -p [你的docker文件夹根目录]/dockerfiles mkdir -p [你的docker文件夹根目录]/mysql/conf.d mkdir -p [你的docker文件夹根目录]/mysql/mysql |
运行权限方面,我强烈不推荐使用root权限去运行任何公开服务。所以计划使用www用户来运行nginx和php-fpm。mysql用户运行mysql。
如果是新机器,我们需要手动在host主机里创建www和mysql用户。推荐创建的同时指定一个uid。具体的创建命令每个发行版都可能不太一样,请google。
如果是已经有www mysql用户的老机器,我们可以通过查看/etc/passwd来查询www用户的uid。稍后会用到。
配置目录的权限
|
1 2 3 4 5 6 |
chown -R www:www [你的docker文件夹根目录]/nginx chown -R www:www [你的docker文件夹根目录]/php chown -R www:www [你的docker文件夹根目录]/www chown -R www:www [你的docker文件夹根目录]/wwwroot chown -R mysql:mysql [你的docker文件夹根目录]/mysql |
nginx
nginx的配置文件默认情况下是在/usr/local/nginx/conf 里面。理论上只要把这个文件映射到docker nginx的配置文件目录里就可以了。但是实际上,lnmp.org提供的配置文件模板里有些绝对路径也需要根据实际情况去修改。
首先理清下原设置应该被映射到docker容器里面的哪个路径
原设置
config: /usr/local/nginx/
ssl: /some_ssl_folder
web: /home/www or /home/wwwroot
logs: /usr/local/nginx/logs(原本是用来存放pid文件的的,可忽略) and /home/wwwlogs
而他们在官方nginx docker容器里的默认对应位置是
config: /etc/nginx
ssl: N/A (我们自己创建)
web: 我们自己创建
logs: 我们自己创建
于是只有config需要映射到/etc/nginx里面去,其他文件夹都是可以很灵活地放到其他地方。
我们在docker compose里可以创建以下卷映射:
|
1 2 3 4 5 6 7 |
- ./nginx/wwwlogs:/home/wwwlogs - ./nginx/logs:/usr/local/nginx/logs - ./www:/home/www - ./wwwroot:/home/wwwroot - ./nginx/conf:/etc/nginx - ./ssl:/ssl |
接下来我们可以把已经安装了lnmp2.0的机器上的/usr/local/nginx/conf文件夹全部复制到docker文件夹里面的nginx/conf里面去了。
同时原本的www用户也要加上。由于容器内的用户名和主机并不互通。为确保一致我们需要用uid。
然后就是修改nginx的配置文件了。我们只需要修改一些用绝对路径的选项。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
nginx.conf: 修改以下地方 //使用/tmp作为pid文件存放位置。 pid /tmp/nginx.pid; http { //在docker container里,tmp文件夹是才是所有用户可写的 client_body_temp_path /tmp/client_temp; proxy_temp_path /tmp/proxy_temp_path; fastcgi_temp_path /tmp/fastcgi_temp; uwsgi_temp_path /tmp/uwsgi_temp; scgi_temp_path /tmp/scgi_temp; ..... } enable-php.conf 和 enable-php-pathinfo.conf也需要修改成使用端口来访问php-fpm服务。 这里我们留到php部分再修改。 |
以上为nginx.conf需要修改的地方。
为了让容器运行在www用户下。我的方法为在docker compose文件里明文指定www用户的uid和gid。比如在nginx service下面加上这一行:
|
1 2 |
user: "1001:1001" #www用户的uid和gid |
同时,我还想给nginx加上lua支持,需要添加插件。这里有点坑,由于alpine apk能安装的nginx-lua插件不一定是最新版本的。在写这个文档时,nginx docker官方最新版本是1.25.2,apk上最新的版本是1.24.0,nginx运行时会因错误版本而报错。比较稳妥的方法就是让官方image手动编译我们要的模块。参考:docker-nginx/modules at master · nginxinc/docker-nginx (github.com)
创建dockerfiles/nginx.Dockerfile
|
1 2 3 |
FROM nginx:alpine ARG ENABLED_MODULES="ndk lua" |
这里使用alpine版容器因为感觉会省点内存?
(可选)如果要启动lua支持,还需要在nginx.conf里面加上
|
1 2 |
pcre_jit on; |
到这里,nginx配置部分就大致准备完毕。接下来再把wwwroot里的默认网页复制到docker文件夹里并创建以下docker-compose.yml文件看看能不能工作。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
services: nginx: build: dockerfile: dockerfiles/nginx.Dockerfile container_name: nginx user: "1001:1001" #your www user uid:gid volumes: - ./nginx/wwwlogs:/home/wwwlogs - ./nginx/logs:/usr/local/nginx/logs - ./www:/home/www - ./wwwroot:/home/wwwroot - ./nginx/conf:/etc/nginx - ./ssl:/ssl ports: - 80:80 - 443:443 restart: unless-stopped |
保存完docker compose文件后使用以下命令启动nginx容器
|
1 2 3 4 |
docker compose up nginx -d # 查看 nginx 的输出 docker compose logs nginx |
如果所有东西都配置完毕,访问host主机,我们应该能看见熟悉的lnmp模板网站了。
但是现在还没有结束,探针一打开就报502错误。我们还需要配置php部分。

PHP
根据lnmp.org官方文档和php-fpm docker的文档,我们需要映射以下文件进到我们的php-fpm容器。
|
1 2 3 4 5 6 7 8 |
#ro是只读的意思 - ./php/etc/php-fpm.conf:/usr/local/etc/php-fpm.conf:ro - ./php/etc/php.ini:/usr/local/etc/php/php.ini:ro - ./php/var:/usr/local/php/var #我们的网站目录也许要能够访问到 - ./www:/home/www - ./wwwroot:/home/wwwroot |
同时,php-fpm的配置文件也需要根据需求进行修改
Global块的修改:
|
1 2 3 4 5 6 |
[global] ;修改pid文件的位置到容器内可写的临时目录里 pid=/tmp/php-fpm.pid ;默认情况下php-fpm是后台运行的。为了在docker里运行,我们得让它跑在前台。 daemonize = no |
www块的修改
原本php-fpm.conf的内容
|
1 2 3 4 5 6 7 8 9 10 11 |
[www] listen = /tmp/php-cgi.sock listen.backlog = -1 listen.allowed_clients = 127.0.0.1 listen.owner = www listen.group = www listen.mode = 0666 user = www group = www |
需要改成监听端口模式
|
1 2 3 4 5 6 7 |
[www] ;只留下这两行 ;监听9000端口 listen = 0.0.0.0:9000 listen.backlog = -1 |
因为在docker里面,容器之间的交流推荐使用网络来解决。于是最好将php-fpm配置成端口监听模式。
到这里,php-fpm配置文件就修改完了。
nginx这边的php配置模板也需要更新。因为在容器里,我们需要拿端口来和php-fpm连接。
修改./nginx/conf/enable-php.conf 和 ./nginx/conf/enable-php-pathinfo.conf
|
1 2 3 4 |
# fastcgi_pass unix:/tmp/php-cgi.sock; #php-fpm容器host名和容器名一样 fastcgi_pass php-fpm:9000; |
但是目前还有一个问题,实际跑网站时我们需要很多额外的扩展(比如mysqli,gd,ioncube等等)。
可以通过dockefile里额外运行https://github.com/mlocati/docker-php-extension-installer这个项目来帮我们安装。
创建dockerfiles/php-fpm.Dockerfile
|
1 2 3 4 5 6 7 8 |
#这里使用php7.4 alpine版本,可以自己指定版本或者直接用最新版本 FROM php:7.4.32-fpm-alpine #下载docker-php-extension-installer ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ #运行并安装gd xdebug mysqli。也可以加上其他你想要的模块名。 RUN chmod +x /usr/local/bin/install-php-extensions && install-php-extensions gd xdebug mysqli |
接下来在 compose file nginx容器的后面加上php的部分
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
php-fpm: build: dockerfile: dockerfiles/php-fpm.Dockerfile user: "1001:1001" #你的www uid和gid container_name: php-fpm volumes: - ./php/etc/php-fpm.conf:/usr/local/etc/php-fpm.conf:ro - ./php/etc/php.ini:/usr/local/etc/php/php.ini:ro - ./php/var:/usr/local/php/var - ./www:/home/www - ./wwwroot:/home/wwwroot restart: unless-stopped |
然后运行php-fpm容器
|
1 2 3 4 |
docker compose php-fpm up -d # 查看php-fpm的输出,如果正常运行的话应该什么都不输出 docker compose logs php-fpm |
不出意外,我们就可以访问探针了

MYSQL
最后,我们来迁移mysql
由于一些原因,lnmp2.0创建的mysql数据库无法直接在docker版上运行。由于mysql可以很方便地通过mysqldump来导出整个数据库。所以采用了先导出整个数据库到sql文件,稍后再使用phpmyadmin之类的程序导入回去。
接下来准备mysql的docker compose部分。这里我使用了mysql容器官方的配置模板。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
mysql: container_name: mysql image: mysql:8 # NOTE: use of "mysql_native_password" is not recommended: https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-pas> # (this is just an example, not intended to be a production configuration) # 有一些旧的程序还是只支持native password的方式 command: --default-authentication-plugin=mysql_native_password # mysql用户的user id user: "1002:1002" environment: #mysql新数据库的root默认密码,请改成你自己想要的密码。 #创建完数据库后请删掉这两段 MYSQL_ROOT_PASSWORD: CHANGE_TO_YOUR_PASSWORD #让root用户可以被除了127.0.0.1以外的ip访问 MYSQL_ROOT_HOST: '%' volumes: #额外.cnf配置文件目录 - ./mysql/conf.d:/etc/mysql/conf.d #mysql主要的数据库数据目录 - ./mysql/mysql:/var/lib/mysql restart: unless-stopped |
如果路径权限配置正确的话,mysql容器是能直接跑起来的。
其中,./mysql/conf.d是用来存放mysql额外配置文件的。(可选)这里可以创建一个网上复制来的低内存占用参数
low-mem.cnf
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
[mysqld] #### These optimize the memory use of MySQL #### http://www.tocker.ca/2014/03/10/configuring-mysql-to-use-minimal-memory.html innodb_buffer_pool_size=5M innodb_log_buffer_size=256K #query_cache_size=0 #it has been removed in 8.0.3 max_connections=10 key_buffer_size=8 thread_cache_size=0 host_cache_size=0 innodb_ft_cache_size=1600000 innodb_ft_total_cache_size=32000000 # per thread or per operation settings #thread_stack=131072 sort_buffer_size=32K read_buffer_size=8200 read_rnd_buffer_size=8200 max_heap_table_size=16K tmp_table_size=1K bulk_insert_buffer_size=0 join_buffer_size=128 net_buffer_length=1K innodb_sort_buffer_size=64K #settings that relate to the binary log (if enabled) binlog_cache_size=4K binlog_stmt_cache_size=4K #### from https://mariadb.com/de/node/579 performance_schema = off |
为了让phpmyadmin能够连接到我们的数据库,我们还需要修改一些phpmyadmin的参数。
找到./wwwroot/default/phpmyadmin/config.inc.php
|
1 2 3 4 5 6 7 8 |
找到 $cfg['Servers'][$i]['host'] = 'localhost’; 改成 $cfg['Servers'][$i]['host'] = 'mysql’; |
最后,运行mysql容器
|
1 2 3 4 |
docker compose up mysql -d # 查看mysql的输出 docker compose logs mysql |
至此,我们应该可以得到一个的使用docker搭建的最小lnmp2.0环境了。mysql的数据可以轻松地通过phpmyadmin来导入。这里就不细说了。
如果要关闭服务的话可以使用
|
1 2 3 4 5 6 7 |
# 关闭 nginx docker compose down nginx # 关闭 php-fpm docker compose down php-fpm # 关闭 mysql docker compose down mysql |
SSL
SSL证书获取部分,由于SSL证书获取的方法多种多样,所以略过了。如果想让容器也能读取到SSL证书,本文使用的例子是把SSL文件放到主机里的”./ssl”文件夹里去。
并在nginx的配置文件里指定被映射的”/ssl”文件夹为ssl保存目录。
你也可以自由地映射自己的ssl目录到nignx容器的任何地方。只需要确定nginx配置文件里的位置是正确的就可以了。
来源:本人博客
lnmp-docker From: https://github.com/anshi233/lnmp-docker
又一个使用docker实现lnmp.org的docker-compose项目,所有的配置文件都来自lnmp.org的LNMP2.0安装脚本。 强烈推荐使用自己的配置文件替换掉原有的配置文件。
文件列表
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
├── docker-compose.yml (docker compose主配置文件) ├── dockerfiles (dockerfile文件夹) │ ├── nginx.Dockerfile (nginx dockerfile) │ └── php-fpm.Dockerfile (php-fpm dockerfile) ├── mysql (mysql配置和数据) │ ├── conf.d (mysql额外的.cnf配置文件) │ └── mysql (mysql数据) ├── nginx (nginx配置文件夹) │ ├── conf (nginx配置) │ ├── logs (nginx pid文件位置(未使用)) │ └── wwwlogs (nginx日志) ├── php (php配置) │ ├── etc (php配置) │ │ ├── php-fpm.conf (php-fpm主配置) │ │ ├── php-fpm.d (php-fpm额外配置文件夹) │ │ └── php.ini (php.ini) │ └── var │ └── log (php日志文件夹) ├── ssl (https ssl证书文件夹) ├── www (网站文件夹) └── wwwroot (lnmp模板网站文件夹) |
使用方法
首先创建www和mysql用户并指定uid(这里是基于debian的例子,实际上的命令可能因为发行版的不同而不同)。 如果你已经有www和mysql用户了,可以跳过这一步。
|
1 2 3 4 |
#如果uid 1001 或者 1002 已经被使用了,请换成其他你喜欢的数字 #别忘了修改docker-compose.yml文件中的uid值为你的www和mysql用户的uid useradd www -u 1001 useradd mysql -u 1002 |
下载这个repo
|
1 2 |
git clone https://github.com/anshi233/lnmp-docker.git cd lnmp-docker |
请务必修改mysql的root密码并在第一次启动后删除docker compose 文件上的这一行
|
1 2 3 4 |
nano docker-compose.yml #修改为你的密码并在第一次启动后删除这一行 MYSQL_ROOT_PASSWORD: CHANGE_TO_YOUR_PASSWORD |
创建文件夹并分配权限
|
1 2 3 4 5 6 7 8 9 10 11 12 |
#你可以直接创建文件夹或者软链接到已有文件夹上 mkdir ./www mkdir ./ssl #如果你没有自己的mysql数据文件夹,请创建这个文件夹 mkdir ./mysql/mysql chown -R www:www ./nginx chown -R www:www ./php chown -R www:www ./www chown -R www:www ./wwwroot chown -R www:www ./ssl chown -R mysql:mysql ./mysql |
运行服务
|
1 |
docker compose up -d |
The Default web port is 80 and 443 To enable or disable each service only
|
1 2 3 4 5 6 7 |
#启动 #选择nginx php-fpm mysql中的一个 docker compose up [nginx | php-fpm | mysql] -d #停止 docker compose down [nginx | php-fpm | mysql] #查看对应服务的命令行输出 docker compose logs [nginx | php-fpm | mysql] |
