我们知道通过Dockerfile文件可以方便的定义一个单独的应用镜像和容器,然而在日常开发中,我们经常会碰到需要多个容器来配合完成某项任务的情况。例如要实现Web服务,需要Nginx、PHP、数据库等多个容器协作,本文就给大家介绍使用Docker Compose来编排一个LNMP环境。
1.准备环境
系统环境CentOS7.7,Docker版本19.03.6-rc1,docker的搭建过程请参照这篇文章:CentOS Docker安装。
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,我们可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Docker-compose安装安装很简单,从 Github 上下载它的二进制包来使用,最新发行的版本地址:https://github.com/docker/compose/releases。
然后执行以下命令,并查看版本,compose就安装好了。
mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose //设置可执行权限
使用命令docker-compose --version
查看版本,回显版本号是1.25.0。
[root@localhost ~]# docker-compose --versiondocker-compose version 1.25.0, build 0a186604
2.创建项目目录
进入/data目录,创建/lnmp项目目录,然后在lnmp项目目录下创建如下项目结构:
[root@localhost lnmp]# tree.├── docker-compose.yml //编排配置文件├── mariadb //MariaDB配置相关目录│ ├── conf.d│ │ └── my.cnf│ └── logs├── nginx //Nginx配置相关目录│ ├── conf.d│ │ └── default.conf│ ├── logs│ └── nginx.conf├── php //PHP配置相关目录│ ├── logs│ ├── php.ini│ └── www.conf├── redis //Redis配置相关目录│ ├── logs│ └── redis.conf└── www //web访问目录 ├── index.php //测试phpinfo文件 ├── mysql.php //测试mariadb连接文件 ├── redis.php //测试redis连接文件 └── swoole.php //测试swoole服务文件
3.Docker-compose编排
前面我们讲过,通过Compose,我们可以使用一个YML文件来配置应用程序需要的所有服务。在项目lnmp目录下新建docker-compose.yml文件,内容如下:
version: '3'networks: lnmp-net: driver: bridgeservices: mariadb: container_name: mariadb image: mariadb:10.4 ports: - 3307:3306 environment: MYSQL_ROOT_PASSWORD: 123456 volumes: - /data/lnmp/mariadb/db:/var/lib/mysql - /data/lnmp/mariadb/conf.d:/etc/my.cnf.d - /data/lnmp/mariadb/logs:/var/log/mariadb restart: always networks: - lnmp-net nginx: container_name: nginx image: nginx:1.16.1 ports: - 80:80 - 443:443 volumes: - /data/lnmp/www:/usr/share/nginx/html - /data/lnmp/nginx/nginx.conf:/etc/nginx/nginx.conf - /data/lnmp/nginx/conf.d:/etc/nginx/conf.d - /data/lnmp/nginx/logs:/var/log/nginx depends_on: - mariadb - redis - php restart: always networks: - lnmp-net php: container_name: php image: hwphp:7.4-fpm //自定义镜像,基于php7.4-fpm,支持Swoole和Redis volumes: - /data/lnmp/www:/usr/share/nginx/html - /data/lnmp/php/php.ini:/usr/local/etc/php/php.ini - /data/lnmp/php/logs:/usr/local/var/log - /data/lnmp/php/www.conf:/usr/local/etc/php-fpm.d/www.conf restart: always networks: - lnmp-net redis: container_name: redis image: redis:5.0.7 ports: - 6380:6379 volumes: - /data/lnmp/redis/db:/var/lib/redis - /data/lnmp/redis/logs:/var/log/redis restart: always networks: - lnmp-net
docker-compose.yml是一个配置文件,该文件是主配置文件,主要包含version、services、network,其中version、services为必要元素。该配置文件涉及到的指令关键字也比较多,不过不要担心,我们了解几个常用的指令就可以了。
version
:版本,当前版本定义为“3”即可,在文件docker-compose.yml的第一行必须指定networks
:定义网络连接,如果是在services下的networks则是指定容器的网络连接配置services
:各容器服务container_name
:指定容器名称image
:指定镜像,如果镜像在本地不存在,Compose 将会尝试拉取这个镜像build
:指定构建自定义镜像位置,对应的是docerfile文件。本文的PHP镜像采用的是自定义hwphp镜像ports
:暴露端口信息,使用宿主端口:容器端口 (HOST:CONTAINER) 格式volumes
:数据卷映射,数据卷所挂载路径设置,格式为宿主机路径:容器路径restart
:自动重启容器,容器挂掉之后自动重启机制depends_on
:指定容器启动顺序的依赖关系,此选项在 v3 版本中 使用 swarm 部署时将忽略该选项environment
:设置环境变量, environment 的值可以覆盖 env_file 的值 (等同于 docker run -e 的作用
注意,本文中使用的PHP镜像是作者自定义构建的镜像image: hwphp:7.4-fpm
,其中包含了对Swoole和Redis的支持,详细构建方法请参照本站文站:使用Docker构建PHP7.4 + Swoole + Redis镜像。在services php模块也可以使用build
指定的dockerfile自行构建镜像。格式为:build: ./php
,然后在项目/php目录下建立dockerfile文件,内容就是本站上篇文章中的dockerfile文件内容。
4.配置Nginx
我们要让web服务跑起来,并且支持PHP,需要先定义好Nginx站点配置。
在项目目录/nginx/conf.d/下新建default.conf文件,内容如下:
server { listen 80; server_name ""; index index.html index.htm index.php; root /usr/share/nginx/html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { fastcgi_pass php:9000; #容器名:端口 fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } access_log /var/log/nginx/test.log main; }
我们还可以在该目录下配置多个.conf文件,以支持多域名站点。
5.启动服务
现在我们可以启动服务了,在项目lnmp目录下(docker-compose.yml所在的目录)只需一条命令:
docker-compose up -d
执行完毕后会回显以下信息:
再执行docker-compose ps
查看服务运行情况:
看到如上图中各容器的state全部为Up时,我们的Docker服务就通过一键启动全部启动起来了。
6.验证结果
现在我们要进行测试,验证lnmp服务是否正常。
6.1 验证PHP服务
在项目目录的www目录下,建立index.php文件,编辑:
<?phpphpinfo();
然后,在浏览器上输入地址访问:http://192.168.0.100/index.php,192.168.0.100是宿主机IP。如果正常则会显示:
6.2 验证Mariadb服务
在项目目录的www目录下,建立mysql.php文件,编辑:
<?php$dbhost = 'mariadb'; //数据库服务器,容器名称$dbport = 3306; //端口$dbname = 'hello'; //数据库名称$dbuser = 'root'; //用户名$dbpass = '123456'; //密码// 连接try { $db = new PDO('mysql:host='.$dbhost.';port='.$dbport.';dbname='.$dbname, $dbuser, $dbpass); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //设置错误模式 $db->query('SET NAMES utf8;'); echo 'The connection is successfu.';} catch(PDOException $e) { echo '{ "result":"failed", "msg":"连接数据库失败!"}'; exit;}
注意,连接mariadb时,host设置为docker的容器名称,端口为容器内部端口号3306,并事先建立名为hello的数据库,否则会报错:
Fatal error: Uncaught PDOException: SQLSTATE[HY000] [2002] Connection refused in /usr/share/nginx/html/mysql.php:14
浏览器访问:http://192.168.0.100/mysql.php,显示:
提示:如果使用其他机器的PHP远程访问mysql,请修改配置,使用IP地址和暴露外网的3307端口访问.
$dbhost = '192.168.0.100'; //数据库服务器,docker宿主机IP$dbport = 3307; //端口
6.3 验证Redis服务
在项目目录的www目录下,建立redis.php文件,编辑:
<?php//连接本地的 Redis 服务$redis = new Redis();$redis->connect('redis', 6379);$redis->auth('123456');echo "The connection is successfu.
";//查看服务是否运行echo "Server is running: " . $redis->ping();
连接本地的redis,使用redis容器名和6379端口,redis密码在项目目录/lnmp/redis/redis.conf文件中设置。
浏览器访问:http://192.168.0.100/mysql.php,显示:
注意,如果是远程连接redis,则使用IP和6380端口访问。
$redis->connect('192.168.0.100', 6380);
6.4 验证swoole
在项目目录的www目录下,建立swoole.php文件,编辑:
<?phpSwoole\Timer::tick(2000, function () { echo 'after 2000ms.' . PHP_EOL; echo date('Y-m-d H:i:s') . PHP_EOL;});
以上代码调用了swoole定时器的功能,每2秒中打印一次信息。在宿主机上,使用Cli命令行模式执行以下命令:
docker exec -it php php /usr/share/nginx/html/swoole.php
回显如下信息,则swoole服务也正常:
7.附:常用的docker-compose命令
启动服务:docker-compose up -d --build
停止并卸载服务:docker-compose down
查看容器:docker-compose ps
进入容器:docekr-compose exec $1 $2
$1 docker-compose.yml
文件services
中定义的服务名称
$2 根据基础镜像服务器决定,一般apline为/bin/sh
,其他为/bin/bash