使用docker搭建LNMP开发环境

宿主机环境

系统:ubuntu 18.04
docker版本:18.03.1-ce

docker的安装请自行参考官方文档。

前言

这篇文章用于介绍如何使用docker在ubuntu系统上搭建一个LNMP开发环境,下面我们将会编写Dockerfile,基于官方docker hub镜像,分别构建我们自己的镜像,然后运行。要构建的镜像有:

  • PHP-FPM 7.4
  • Nginx 1.19
  • MySQL 5.7
  • Redis 6.2

为什么不直接使用官方镜像,而是自己再构建一个?
因为官方镜像一般安装的东西都很少,例如PHP-FPM的官方镜像,像redis、mysqli、pdo等等这些常用的扩展都是没有的,还有一些常用的系统命令也没有安装,例如ping、netstat、ps等等。

目录结构

我的项目路径是/home/rockyliang/mydocker,目录结构如下:
使用docker搭建LNMP开发环境_第1张图片

html目录用于存放网页文件和PHP文件,这个目录后面会通过挂载的方式,挂载到 PHP-FPM容器 和 nginx容器 里面去,以便它们可以访问这些文件。

redis目录下有一个redis.conf文件,这是从网上下载的redis配置文件,因为官方的redis镜像默认是没有配置文件的,后面构建redis镜像时,我们会把这个下载的配置文件复制进去。这个文件的下载地址是:
https://raw.githubusercontent.com/antirez/redis/6.2/redis.conf

注意URL里的版本号,因为我们要构建的redis镜像版本是6.2,因此配置文件版本也要用6.2的。

创建网络

因为各个容器之间需要通信,例如PHP-FPM容器需要跟MySQL、Redis容器连通,这样PHP才能查询数据库数据,因此我们先创建一个名为mynet的网络:

sudo docker network create mynet

创建好网络后,后续把各个容器加入到这个网络里面来就可以。

构建PHP-FPM镜像

Dockerfile文件
# 从官方基础版本构建
FROM php:7.4-fpm-buster

# 镜像信息
LABEL maintainer="ljfrocky" \
    version="2020.03.30" \
    description="PHP-FPM 7.4"

# 安装install-php-extensions
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

# 设置系统时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 安装常用命令工具包,根据自己的实际需要情况进行安装
# vim: vi、vim
# procps: ps
# iputils-ping: ping
# less: less
# net-tools: netstat
# iproute2: ss
RUN apt-get update && apt-get install -y --no-install-recommends vim procps iputils-ping less net-tools iproute2

# 安装mysqli、pdo等PHP扩展
# 如果需要安装特定版本的扩展,可以在扩展名后加版本号,例如:redis-5.1.1
RUN chmod +x /usr/local/bin/install-php-extensions \
    && install-php-extensions redis mysqli pdo_mysql pcntl gd mcrypt bcmath sockets zip

# 使用线上环境的php.ini配置文件
RUN cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
开始构建

执行docker build命令构建FPM镜像,镜像名字设置为img-php-fpm,标签(TAG)设置为7.4

cd /home/rockyliang/mydocker/php-fpm
sudo docker build -t img-php-fpm:7.4 .

因为国内访问github不太稳定,构建过程可能会在“安装install-php-extensions”这一步骤发生错误,一般重试构建多几次就可以解决。

构建完成后,执行docker images命令,已经能看到新的镜像:

sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
img-php-fpm         7.4                 d511ba9f4c3d        2 minutes ago       456MB
php                 7.4-fpm-buster      c1bb99843706        3 days ago          389MB

执行docker run命令运行新镜像,容器名字设置为DOCKER_FPM,为了让容器能访问到宿主机的html目录,还需要把宿主机的html目录挂载到容器里的/var/www/html目录:

sudo docker run --name DOCKER_FPM \
-p 9000:9000 \
--network mynet \
-v /home/rockyliang/mydocker/html:/var/www/html:ro \
-d img-php-fpm:7.4

构建nginx镜像

Dockerfile文件
# 从官方基础版本构建
FROM nginx:1.19

# 镜像信息
LABEL maintainer="ljfrocky" \
    version="2020.03.30" \
    description="Nginx 1.19"

# 设置系统时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 安装常用命令工具包,根据自己的实际需要情况进行安装
# vim: vi、vim
# procps: ps
# iputils-ping: ping
# less: less
# net-tools: netstat
# iproute2: ss
RUN apt-get update && apt-get install -y --no-install-recommends vim procps iputils-ping less net-tools iproute2
开始构建

执行docker build命令构建nginx镜像,镜像名字设置为img-nginx,标签(TAG)设置为1.19

cd /home/rockyliang/mydocker/nginx
sudo docker build -t img-nginx:1.19 .

构建完成后,执行docker run命令运行新镜像,容器名字设置为DOCKER_NGINX,为了让容器能访问到宿主机的html目录,还需要把宿主机的html目录挂载到容器里的/usr/share/nginx/html目录:

sudo docker run --name DOCKER_NGINX \
-p 80:80 \
--network mynet \
-v /home/rockyliang/mydocker/html:/usr/share/nginx/html:ro \
-d img-nginx:1.19

容器运行起来后,进入容器修改nginx的配置文件,让nginx可以转发PHP请求:

sudo docker exec -it DOCKER_NGINX bash
vim /etc/nginx/conf.d/default.conf

将配置文件里的这一段
使用docker搭建LNMP开发环境_第2张图片
去除前面的注释,内容替换成:
使用docker搭建LNMP开发环境_第3张图片

在容器里重启nginx:nginx -s reload

测试

至此,nginx和PHP容器都搭建好了,测试一下看nginx能不能处理PHP请求,在宿主机的html目录里新建一个phpinfo.php文件:


phpinfo();

在浏览器访问一下http://localhost/phpinfo.php,内容显示正常:
使用docker搭建LNMP开发环境_第4张图片

构建MySQL镜像

Dockerfile文件
# 从官方基础版本构建
FROM mysql:5.7

# 镜像信息
LABEL maintainer="ljfrocky" \
    version="2020.03.31" \
    description="MySQL 5.7"

# 设置系统时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 安装常用命令工具包,根据自己的实际需要情况进行安装
# vim: vi、vim
# procps: ps
# iputils-ping: ping
# less: less
# net-tools: netstat
# iproute2: ss
RUN apt-get update && apt-get install -y --no-install-recommends vim procps iputils-ping less net-tools iproute2
开始构建

执行docker build命令构建MySQL镜像,镜像名字设置为img-mysql,标签(TAG)设置为5.7

cd /home/rockyliang/mydocker/mysql
sudo docker build -t img-mysql:5.7 .

构建完成后,执行docker run命令运行新镜像,容器名字设置为DOCKER_MYSQL,root账号密码设置为123456

sudo docker run --name DOCKER_MYSQL \
-p 3306:3306 \
--network mynet \
-e MYSQL_ROOT_PASSWORD=123456 \
-d img-mysql:5.7

构建Redis镜像

Dockerfile文件
# 从官方基础版本构建
FROM redis:6.2-buster

# 镜像信息
LABEL maintainer="ljfrocky" \
    version="2020.03.31" \
    description="Redis 6.2"

# 官方镜像默认是没有redis.conf配置文件的,如果需要配置文件,需要自己编写或者到网络上下载
# 6.2版本配置文件下载地址:https://raw.githubusercontent.com/antirez/redis/6.2/redis.conf
# 把宿主机上已下载好的配置文件复制到容器里去
COPY ./etc/redis.conf /usr/local/etc/redis/redis.conf

# 设置系统时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 安装常用命令工具包,根据自己的实际需要情况进行安装
# vim: vi、vim
# procps: ps
# iputils-ping: ping
# less: less
# net-tools: netstat
# iproute2: ss
RUN apt-get update && apt-get install -y --no-install-recommends vim procps iputils-ping less net-tools iproute2

# 以指定配置文件的方式启动redis
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
开始构建

执行docker build命令构建Redis镜像,镜像名字设置为img-redis,标签(TAG)设置为6.2

cd /home/rockyliang/mydocker/redis
sudo docker build -t img-redis:6.2 .

构建完成后,执行docker run命令运行新镜像,容器名字设置为DOCKER_REDIS

sudo docker run --name DOCKER_REDIS \
-p 6379:6379 \
--network mynet \
-d img-redis:6.2

容器运行起来后,进入容器修改redis配置文件:

sudo docker exec -it DOCKER_REDIS bash
vim /usr/local/etc/redis/redis.conf

bind 127.0.0.1 -::1这一行改为bind *,保存,退出容器,然后重启容器:

sudo docker restart DOCKER_REDIS

测试

在宿主机的html目录里新建一个test.php文件,用于测试PHP是否能查询MySQL和redis:



function display($msg) {
    echo "{$msg}
"
; } /* * 测试连接MySQL */ $mysqlConn = new mysqli(); $ok = $mysqlConn->real_connect('DOCKER_MYSQL', 'root', '123456'); if (!$ok) { exit("MySQL connect failed:" . $mysqlConn->connect_error); } $mysqlConn->close(); display("测试MySQL连接:OK"); /* * 测试连接redis */ $redis = new Redis(); try { $redis->connect('DOCKER_REDIS', 6379, 2); } catch (Throwable $e) { exit("Redis connect failed:" . $e->getMessage()); } $redis->close(); display("测试Redis连接:OK");

在浏览器访问一下http://localhost/test.php,连接数据库正常:
在这里插入图片描述

日志/数据/配置文件路径

在部署服务时,我们一般都会关注日志路径、数据存储路径、配置文件路径,下面列一下上面几个镜像的一些默认路径:

镜像 日志 配置文件 数据
php:7.4-fpm-buster 默认无日志文件,access log和error log都是输出到标准输出,需要使用docker logs命令查看,如果需要将日志记录到文件里,请参阅后面章节内容 /usr/local/etc
(php.ini和php-fpm.conf等配置文件都在这个路径里)
nginx:1.19 /var/log/nginx/access.log
/var/log/nginx/error.log
这两个文件都是软链接到标准输出的,无法查看里面的内容,只能通过docker logs命令查看。解决方法见后面章节内容
/etc/nginx /usr/share/nginx/html
mysql:5.7 /var/log/mysql /etc/mysql /var/lib/mysql
redis:6.2-buster 默认无日志文件,日志都是输出到标准输出,需要使用docker logs命令查看,如果需要将日志记录到文件里,请参阅后面章节内容 默认无配置文件,可以自己指定 /data
(rdb文件存放路径)

记录日志到文件

通过上一章节,我们知道PHP-FPM、nginx、redis的日志是不记录到实体文件里的,只能通过docker logs {容器名称或ID}命令来查看,那么,如果我们想把日志记录到实体文件里,可以怎么做呢?

PHP-FPM

进入PHP-FPM容器,修改/usr/local/etc/php-fpm.d/zz-docker.conf文件:
使用docker搭建LNMP开发环境_第5张图片
新增图中两行内容,保存并重启容器,这样PHP-FPM的 access log 和 error log 就会记录到我们指定的文件里了。

nginx

nginx容器里的日志文件是个软链接:

root@adb13aee521c:/var/log/nginx# ls -l
total 0
lrwxrwxrwx 1 root root 11 May 12  2021 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 May 12  2021 error.log -> /dev/stderr

所以如果想把日志记录到文件里去,把软链接删除即可:

cd /var/log/nginx
unlink access.log
unlink error.log
nginx -s reload
redis

因为上面我们在构建redis镜像时,有通过COPY指令复制了一个redis.conf配置文件进去,我们通过修改配置文件来配置日志文件路径即可。

假设我们希望把日志文件保存在/var/log/redis目录里,首先我们要创建好这个目录,并确保redis用户对这个目录有写入的权限

mkdir /var/log/redis
chown redis:redis /var/log/redis/

修改/usr/local/etc/redis/redis.conf文件:
使用docker搭建LNMP开发环境_第6张图片
修改logfile参数,指定日志文件路径,保存退出,重启redis容器。

docker-compose

如果你觉得像上面那样一个一个的构建镜像和运行太麻烦,可以试下用docker-compose来减轻工作量,在项目根目录里编写一个docker-compose.yml,内容如下:

version: "3"
services:

  nginx:
    image: img-nginx:1.19
    build:
      context: ./nginx
      dockerfile: Dockerfile
    container_name: DOCKER_NGINX
    ports:
      - "80:80"
      - "443:443"
    networks:
      - lnmp-network
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: always
    depends_on:
      - php-fpm

  php-fpm:
    image: img-php-fpm:7.4
    build:
      context: ./php-fpm
      dockerfile: Dockerfile
    container_name: DOCKER_FPM
    volumes:
      - ./html:/var/www/html
    networks:
      - lnmp-network
    restart: always
    depends_on:
      - mysql
      - redis

  mysql:
    image: img-mysql:5.7
    build:
      context: ./mysql
      dockerfile: Dockerfile
    container_name: DOCKER_MYSQL
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: '123456'
    command: mysqld  --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    networks:
      - lnmp-network
    restart: always

  redis:
    image: img-redis:6.2
    build:
      context: ./redis
      dockerfile: Dockerfile
    container_name: DOCKER_REDIS
    ports:
      - "6379:6379"
    networks:
      - lnmp-network
    restart: always

networks:
  lnmp-network:
    driver: bridge
    ipam:
      config:
        - subnet: '172.31.0.0/16'

然后执行sudo docker-compose up -d命令,docker-compose就会一次性把所有镜像构建好,并且运行。

在搭建环境时遇到的一些坑

1.配置文件修改错了,导致容器启动不起来了

一般修改完配置文件,都需要重启容器来让新配置生效的,但如果不小心配置错了,导致容器起不来了就麻烦了,容器起不来,就无法进去重新修正配置文件。这时候可以通过docker cp命令,把有问题容器里的配置文件复制到宿主机上来,然后在宿主机上修改,修改完后,再docker cp回去容器里,这样就可以解决这个问题了。

你可能感兴趣的:(其它,Linux,PHP,docker,lnmp)