docker搭建php开发环境

2020年11月11日 0 作者 y1nhui

前言

最近在折腾开发环境。虽然brew是一个很好用的东西,但是web开发相关还是想试试docker来构建,同时部分程序brew似乎无法指定版本。所以写了这篇文章。

希望在结尾时,共有三个目的完成。

  • 构建php开发环境
  • 编写dockerfile
  • 构建docker-compose.yml

开始

一点点命令行下的基础知识

使用docker的话,除去基础的docker pull docker run。我们还需要细说一些参数。

-it

这是两个指令,不过经常在一起。一个是-i ,代表交互式操作。一个是-t,代表分配伪终端。

比如 docker run -it nginx bash这样代表其内使用bash终端。不过我一般不写bash,需要自己进入日期交互时我再指明终端。

-d

代表后台运行。可以和it放一起,-itd这样写。

--name

run时的参数。给容器命名

docker run -it --name test nginx

cp

复制,将对应容器内文件复制到指定的路径。

docker cp test:/etc ~ /etc就是将日期test内的/etc下文件复制到本机的~/etc下。

exec

容器运行后如果需要进入容器进行操作,一般用这个指令进入。其实还有另一个指令attach,但是该指令进入容器后再退出会把容器一起关了,所以一般使用exec。

一般用法

docker exec -it container bash
BXAqln.png

这里我们运行nginx,并将它命名为nginx,然后使用exec进入。使用-it参数再指定bash之后,可以看到上图。使用exit退出,同时与前文对应一下,如果我们试试不用-t
BXAxTU.png

可见,标识符没了。

-v

挂载数据卷。数据卷可绕过utfs,有三个特性:

  • 数据卷可以在容器间共享和共用
  • 对数据卷的修改可以立刻生效
  • 对数据卷更新,不影响镜像

或许可以当作共享吧,但是好像并不会将其内的文件主动到出到主机上,所以一般需要先cp,把文件导出,不过之后如果出现了文件变动,主机内的文件也会更着同步,不用担心。

一个例子 -v ~/www/mysql/:/var/lib/mysql

将本机的~/www/mysql/挂载到容器内的/var/lib/mysql。

--link

容器互联,通过这个使不同的容器间可以进行网络通信。

写个例子 docker run -it --name test --link test_mysql:mysql nginx

前面的参数都说过了,这里说link,test_mysql是容器名称,mysql则是对应该容器在nginx这个容器内的网络名称。

-p

端口映射,将日期内的端口映射到本机端口。

依旧nginx举例 docker run -itd -p 8080:80 nginx 将nginx端口内的80端口映射到本机的8080端口。

-e

设置容器内的环境变量。这里用mysql举例

docker run -itd -p 3306:3306 --name test_mysql -e MYSQL_ROOT_PASSWORD=password mysql

将mysql的root密码设为password

logs

查看日志,一般如果我容器启动失败就用这个看日志。

docker logs container

开始我们的基础容器搭建之路

├── WWW
│   ├── mysql
├── etc
│   ├── mysql
│   ├── nginx
│   └── php

这是现在这种情况下打算用的一个文件结构。

WWW存放网站内容,我把mysql储存文件放在了WWW/mysql下

ETC存放配置文件。

mysql

我们首先生成一个tmp,把mysql的配置文件给他导出

docker run -d --name tmp mysql
docker cp tmp:/etc/mysql ~/WorkSpace/etc
docker rm -f tmp

然后正式启动。

docker run -itd --name test_mysql -p 3306:3306 -v ~/WorkSpace/WWW/mysql/:/var/lib/mysql -v ~/WorkSpace/etc/mysql/:/etc/mysql/ -e MYSQL_ROOT_PASSWORD=password mysql

这里有个小问题,我的www/mysql其实并没有导出。但是我后来发现我的www/mysql下已经生成了一堆文件,我现在无法确定这是其实-v是可以自动导出文件到对应目录下,还是我在之前的一系列测试中更新了数据,使文件被同步出来。

php

正常下应该是先nginx的,毕竟如果nginx不启动,我们php怎么证明成功了呢。不过为了一步到位,我这里先启动php。

先拖配置文件。

docker run --name test_php -d php:5.6-fpm
docker cp test_php:/usr/local/etc ~/WorkSpace/etc/php/
docker rm -f test_php

翻翻文件夹,把把php.ini-production 改成了 php.ini。

docker run -d --name docker_php -p 9000:9000 --link test_mysql:mysql -v ~/WorkSpace/WWW/:/var/www/html -v ~/WorkSpace/etc/php/etc:/usr/local/etc php:5.6-fpm

启动,挂载目录,端口映射。

ps:这里注意用的php是php:5.6-fpm,我试过直接使用5.6,不加载fpm,结果就是直接起不起来= =

nginx

导出配置文件。

docker run -d --name tmp_n nginx
docker cp tmp_n:/etc/nginx ~/Workspace/etc/
docker rm -f tmp_n

然后,改配置文件,让nginx可以和php连接。

看一下nginx下的conf.d的default.conf:
BXEPp9.png

把圈内段落,注释去了同时改一下:

location ~ \.php$ {
        root           html;
        fastcgi_pass   docker_php:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
        fastcgi_param  SCRIPT_NAME      $fastcgi_script_name;
        include        fastcgi_params;
    }

这里可以发现fastcgi_pass的参数我们改成了docker_php:9000,这是为容器连接准备的。

fastcgi_param后的/var/www/html$fastcgi_script_name。指的就是xxx.com/index.php指向/var/www/html/index.php

也加了一个fastcgi_param SCRIPT_NAME $fastcgi_script_name; 这个的作用为不知道。是配了上面两个很自信结果发现没能连上后查nginx+php的文档找到的,直接加上去的。

搞好了这个,启动。

docker run -itd -p 8080:80 --name test_nginx --link docker_php:docker_php -v ~/WorkSpace/etc/nginx/:/etc/nginx -v ~/WorkSpace/WWW/:/usr/share/nginx/html nginx

写个phpinfo。
BXEufH.png

很好,成功。

下一步。

dockerfile与php拓展安装

上面也发现了,我们的php只有部分拓展(官方的fpm自带,如果有多的那是因为这里的截图我用的我最后的compose直接搭建的截的)

docker的php安装拓展有两个方法。exec进容器后:

docker-php-ext-install xxx

pecl install xxx && docker-php-ext-enable xxx

第一种用于直接安装,但是有的它官方没得,就用第二种方法安装。而且有时候只是用第一种不行,还需要跟一个 docker-php-ext-enable xxx = =

好的,先不纠结这个。我们先说一下接下来要用到的dockerfile的语法吧。

一点点dockerfile的知识

Dockerfile文件名就叫Dockerfile,没有任何后缀。写这个名字在目录下可以直接build

docker build ./ -t "test"

这样,就是根据当前目录下的dockerfile创建了一个名为test的镜像

然后说点dockerfile内的关键字

FROM

文件开头,表示该dockerfile使用的源镜像是什么

RUN

运行指令,后面跟命令。

LABEL

元祖,加一点数据。我用来声明作者

LABEL Author="y1nhui"

有了这三个基础,我们可以说点东西了。

在run的情况下,我们可以使用

docker-php-ext-install xxx

pecl install xxx && docker-php-ext-enable xxx

的方法来安装php拓展,不过docker-php-ext-install xxx改为docker-php-ext-install -j$(nproc) xxx

-j$(nproc)的意义没搞懂,但是官方demo是直接给我了个这个。。。

但是考虑到网络问题,一般是需要换源的。

然后可以写dockerfile了。没错,关于开放端口啊,环境配置啥的我暂时不打算说,那些我们可以在docker-compose里面配置。

构建php的dockerfile

基于上面说的,我们直接写文件

FROM php:5.6-fpm

LABEL Author="y1nhui"

RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak \
    && echo 'deb http://mirrors.163.com/debian/ stretch main non-free contrib' > /etc/apt/sources.list \
    && echo 'deb http://mirrors.163.com/debian/ stretch-updates main non-free contrib' >> /etc/apt/sources.list \
    && echo 'deb http://mirrors.163.com/debian-security/ stretch/updates main non-free contrib' >> /etc/apt/sources.list \
    && apt-get update

RUN docker-php-ext-install -j$(nproc) mysqli && docker-php-ext-enable mysqli


RUN pecl install xdebug-2.5.2 && docker-php-ext-enable xdebug


第一个run是换源,后面两个是分别两种安装方法。

docker build ./ -t "test"

构建
BXEQ1A.png

看上去是完事了。看一看
BXEJ78.png
完事。写最终的docker-compose联动三个容器吧。

docker-compose联动

docker-compose.yml是标准文件名。

一般运行是载入到当前目录然后docker-compose up -d就完事了

停止和删除容器也就是

docker-compose stop

docker-compose rm

这里我们回顾一下运行三个程序需要的命令。(忽略拖出配置的情况)

docker build ./ -t "test"
docker run -itd -p 3306:3306 --name test_mysql -v ~/WorkSpace/WWW/mysql/:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password mysql
docker run -d --name docker_php -p 9000:9000 --link test_mysql:mysql -v ~/WorkSpace/WWW/:/var/www/html -v ~/WorkSpace/etc/php/etc:/usr/local/etc filephp
docker run -itd -p 8080:80 --name test_nginx --link docker_php:docker_php -v ~/WorkSpace/etc/nginx/:/etc/nginx -v ~/WorkSpace/WWW/:/usr/share/nginx/html nginx

根据这个,写yml文件,然后注释讲解。

version: "3.3"  # 这个指docker-compose的version,不是自己写的这个yml的版本
services:   # 服务配置
    mysql:   #这里是服务名
        image: mysql  #表示使用镜像,这里我没有注明版本,实际使用为了稳定性请注明版本(不要用laster)

        ports:  #端口映射
            - "3306:3306"
        environment:   #环境配置
            - MYSQL_ROOT_PASSWORD=password
        volumes:   #数据卷挂载
            - ~/WorkSpace/WWW/mysql/:/var/lib/mysql  

    docker_php:  

        build:  #使用dockerfile
            context: . #目录,这里我将Dockerfile与docker-compose.yml放在了同一目录
            dockerfile: Dockerfile
        volumes: 
            - ~/WorkSpace/WWW/:/var/www/html
            - ~/WorkSpace/etc/php/etc:/usr/local/etc
        ports: 
            - "9000:9000"
        depends_on:  #依赖mysql,这种情况下就会先启动mysql,再启动该容器
            - mysql

    nginx:
        image: nginx

        ports: 
            - "8080:80"
        volumes: 
            - ~/WorkSpace/etc/nginx/:/etc/nginx
            - ~/WorkSpace/WWW/:/usr/share/nginx/html
        depends_on: 
            - docker_php

这里我们发现,我们没有使用link。在docker-compose的文件关键字里其实是有links的,但是当前情况不需要使用。因为docker-compose.yml构建的容器是共享一个docker network的。在这种情况下,他们互相使用服务名互相通信,自然不需要link。

好,接下来就是收尾了。

docker-compose up -d

BXEtAS.png
大功告成。

结语

大概该说的都说清楚了,但是其实还是有个地方有点问题。

docker-php-ext-install这里,其他都能安装,但是mysqli我无法安装。我不知道是因为我没有安装什么前置拓展还是php版本问题。查了查其他人遇到这种情况最多加个enable就行了,我加了也不行。如果有大哥知道麻烦说一下orz