[Docker实践系列-02]利用DockerCompose编排完整的PHP开发环境

Docker 重要性不用多作解释,咱们每天吵着云原生,最重要的一门技术,你是否掌握了呢?从今天,一块儿来Docker吧!php

1. 目标

一、利用 docker-compose 编排一个PHP开发环境;
二、PHP 常见扩展安装;
三、Nginx php-fpm Mysql Redis等容器互联;
四、PHP 程序可以操做 Mysql Redis
二、搜集相关日志便于排查;html


2. 工具

一、操做系统:Ubuntu
二、编辑器:VSCode
三、Docker
四、Docker Compose 官方文档
五、Compose 中文手册
六、若是Docker镜像拉取慢,能够尝试这个 www.daocloud.io/mirrormysql


3. 步骤

3.1 检查软件

确保 Docker 和 Docker Compose 已安装好
好比linux

docker -v Docker version 19.03.1, build 74b1e89nginx

docker-compose -v docker-compose version 1.17.1, build 6d101fbgit

3.2 建立 docker-compose.yml 文件

在你的文件夹中新增这个文件,这是咱们编排的模板文件,格式以下github

version: '3'
services:
  php-workspace:
    image: php:7.3-fpm-alpine
  nginx:
    image: nginx:alpine
复制代码

注意点:
一、模板中定义的 version 字段声明了模板的格式和支持声明字段,3 是目前比较推荐也用的比较多的的版本
二、注意 key 的层级和空格,咱们可使用命令 docker-compose config 命令检查格式是否正确
三、使用 VSCode方便的一点是能够看到能够代码能够根据层级折叠
redis

image.png

四、alpine是一种小型轻量的Linux,咱们使用基于 alpine 的镜像是由于作出的镜像体积比较小,关于后期容器构建的优化,这个是另一个话题,这里不展开阐述。

3.3 “让子弹飞起来”

docker-compose up --build 构建镜像并启动容器sql

这时能看到有两个已经在运行的容器和镜像
docker

image.png

3.4 让 Nginx 工做起来

刚刚启动的容器可使用 docker-compose down 来关闭项目,还会自动删除容器。
如今,咱们要指定端口让 Nginx 能处理请求,能够参考 Compose 中文手册的模板文件的语法。

image.png

3.4.1 增长 ports 参数

指定宿主机端口和容器端口的映射关系,以下;

version: '3'
services:
  php-workspace:
    image: php:7.3-fpm-alpine
  nginx:
    image: nginx:alpine
    ports:
      - "8080:8080"
复制代码

3.4.2 执行 docker-compose up

去浏览器请求 localhost:8080

image.png

3.5 PHP文件交给 PHP-FPM 处理

image.png


其实选中容器右键能管理容器, Attach Shell 就能快速进入容器,咱们进入容器就能看到内部状况,好比,nginx 的www目录和配置目录,php-fpm 的默认配置等等。

3.5.1 增长 nginx 的站点配置

新增文件 nginx/conf.d/site.conf文件,内容以下,下面的思路也能够参考上篇《利用Docker搭建PHP开发环境》作法。

image.png

server {
    listen 8080;
    root /usr/share/nginx/html;
    index index.php index.html;
    server_name localhost;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    location ~ \.php$ {
        root /var/www/html; # 这里指向的php容器的项目根目录
        fastcgi_pass php-workspace:9000; #php-workspace是模板文件中的php-fpm服务名
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
复制代码

3.5.2 修改 docker-compose.yml 文件

让 nginx 和 php-fpm 服务基于Dockerfile 构建

version: '3'
services:
  php-workspace:
    build: ./php # 这里php指咱们的建立的目录
  nginx:
    build: ./nginx # 这里nginx指咱们的建立的目录
    ports:
      - "8080:8080"
复制代码

3.5.3 新增 nginx/Dockerfile 文件

FROM nginx:alpine

COPY conf.d /etc/nginx/conf.d 复制代码

3.5.4 新增 php/Dockerfile 文件

FROM php:7.3-fpm-alpine

复制代码

3.5.5 增长code文件夹做为php项目,新增index.php文件

<?php

phpinfo();

复制代码

3.5.6 从新修改 docker-compose.yml 文件

让项目文件夹以挂载的形式,让php-fpm容器能够直接读取宿主机文件目录,这样咱们能够很方便的修改代码调试

version: '3'
services:
  php-workspace:
    build: ./php
    volumes: # 这里指定数据卷,能够指定多个, 中划线表明值为数组的一个成员
      - ./code:/var/www/html
  nginx:
    build: ./nginx #这里nginx指咱们的建立的目录
    ports:
      - "8080:8080"
复制代码

3.5.7 走一下

重启以前,再肯定下代码文件大概位置

image.png

docker-compose up --build 从新启动项目,咱们看到在前台控制器的一些日志

image.png


两个容器都构建好了,php也启动了。若是咱们如今请求 localhost:8080,还能看到nginx的请求日志
image.png

3.6 链接Mysql

用法咱们依然参考了镜像的介绍 >> hub.docker.com/_/mysql

3.6.1 添加 db 的服务

version: '3'
services:
  php-workspace:
    build: ./php
    volumes:
      - ./code:/var/www/html
  nginx:
    build: ./nginx
    ports:
      - "8080:8080"
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment: # 设定环境变量,只给定名称的变量会自动获取运行 Compose 主机上对应变量的值
      MYSQL_ROOT_PASSWORD: root
复制代码

3.6.2 从新构建

docker-compose up --build

image.png


VSCode 容器管理中右键链接shell中进入容器执行 mysql -u root -p,确认密码 root,肯定咱们的数据库可用
image.png

3.6.3 安装 pdo mysql

在操做以前咱们肯定下pdo是不支持mysql驱动的

image.png

修改 php 的 Dockerfile 文件以下
RUN 的第一条命令是修改了 alpine 系统的软件源,方便后续安装会更快点

FROM php:7.3-fpm-alpine

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \     && docker-php-ext-install pdo_mysql
复制代码


从新构建项目 docker-compose up --build

image.png

3.6.4 修改 index.php 文件,代码以下

<?php

$dsn = 'mysql:host=db;port=3306'; // host=db,这里的db实际上是mysql的服务名
$user = 'root';
$password = 'root';

try {
    $dbh = new PDO($dsn, $user, $password);
    print_r($dbh);
} catch (PDOException $e) {
    echo 'Connection failed: '.$e->getMessage();
}

复制代码

3.6.5 测试 Mysql

image.png

3.7 链接 Redis

3.7.1 容器安装PHP扩展的两种方式

在Docker Hub 中 php镜像文档中说的很清楚

  • 第一种是PHP核心的扩展能够经过 docker-php-ext-install ext_name 安装
  • 第二种是PECL
  • 第三种经过源码包编译

Redis的扩展,咱们用的是第二种。

3.7.2 修改 docker-compose.yml 文件,增长redis服务

version: '3'
services:
  php-workspace:
    build: ./php
    volumes:
      - ./code:/var/www/html
  nginx:
    build: ./nginx
    ports:
      - "8080:8080"
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
  redis:
    image: redis:5.0.5-alpine
复制代码

3.7.3 从新构建

docker-compose up --build
构建后,咱们一样能够进入容器,使用 redis-cli 命令肯定redis是否可用

image.png

3.7.4 修改 php Dockerfile

由于pecl在alpine容器中安装扩展会少一些东西,因此咱们先安装了一个phpize_deps,用后删除便可,保持镜像瘦小

FROM php:7.3-fpm-alpine

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \     && docker-php-ext-install pdo_mysql \
    && apk add ${PHPIZE_DEPS} \ && pecl install redis-4.0.1 \ && docker-php-ext-enable redis \ && apk del ${PHPIZE_DEPS} 
复制代码

从新构建,咱们修改index.php 代码 phpinfo();能看到 redis扩展已打开

image.png

3.7.5 链接 Redis

修改 index.php 文件内容以下测试

<?php

$redis = new Redis();
$redis->pconnect('redis', 6379);

$key = 'first';
$redis->incr($key);

echo '页面浏览了:'.$redis->get($key); die;
复制代码


image.png

3.8 日志搜集

咱们回顾一下 nginx/conf.d/site.conf 的配置

server {
    listen 8080;
    root /usr/share/nginx/html;
    index index.php index.html;
    server_name localhost;
    # 咱们已经把nginx相关日志写到这里了,如何放到宿主机呢?
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    # ... more something
}
复制代码


docker日志采集当然有不少方案,可是暂时不考虑集群管理工具的日志搜集方案,这里以数据挂载的形式,把 nginx 请求日志落地到宿主机。

3.8.1 修改 docker-compose.yml 文件以下

version: '3'
services:
  php-workspace:
    build: ./php
    volumes:
      - ./code:/var/www/html
  nginx:
    build: ./nginx
    volumes: # 新增这两行
      - ./log/nginx:/var/log/nginx/
    ports:
      - "8080:8080"
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
  redis:
    image: redis:5.0.5-alpine
复制代码

3.8.2 重启项目

docker-compose up 执行后,就能够看到咱们的文件夹多了两个目录,还有两个文件

image.png

3.9 优化

depends_on

能够指定依赖项,解决容器启动前后问题,好比一个应用若是依赖数据库,要让数据库容器先启动能够设置

depends_on:
      - db
      - redis
复制代码

环境变量

固然其实还有其余不少有用的参数设置,好比感敏数据读取,环境变量,配置host等等,后续均可以在开发中尝试使用。


4. 总结

以上思路能够解决本地开发中的不少问题了,若是项目中有使用 memcached 或者其余应用,作法均可以参考Docker Hub中的镜像文档说明中引入。
除此以外,在Laravel 开发中以前早就有一个开源项目叫作 Laradock 来搭建Docker化的PHP应用,不只如此,还有不少中间件均可以利用 docker-compose 启动,能够参看 >> laradock.io/ ,可是里边有不少不少东西,由于要知足大部分人的扩展性,加了不少环境变量,if else 判断,让本来的 Dockerfile 更为复杂,增长了不少逻辑。可是思路基本上是相同的。
另外还有几点要点出:
一、docker-compose.yml 定义的一个项目会以所在的文件夹名为项目名。
二、一个项目有一个默认网络,项目中的服务彼此能够互通,因此咱们刚刚在 site.conf 转发php请求能够直接用 php-workspace:9000 服务名来转发,链接 数据库也是能够用 db  redis 等他们的服务名来链接。

image.png


5. 完整代码

github.com/baiyutang/d…


6. 遗留问题

一、指定数据库挂载的数据卷,好比Mysql,咱们能够把其余环境的数据库直接以文件的形式拷贝,而后直接利用。这样比咱们手动导入sql会更快迁移数据。

二、Mysql 镜像如何瘦身,如今Mysql镜像文件最大,如图有445M

image.png


7. 下篇预告

其实PHP的Docker环境已经有一个开源项目 Laradock,使用方便 易于扩展,可是最大的问题是 感受臃肿 有时候安装特别慢,特别是要考虑太多扩展插件等等制做出来镜像特别大。因此下一篇的思路可能会围绕如何优化今天作的这个 demo-docker-compose,或者作 Laradock 本地化工做?
其余两个思路:
一、直接进入到 k8s 课题
二、Docker化后如何作CI/CD


8. 扩展