上一篇简单介绍了下Docker的常用指令和给出了nginx、PHP、Mysql镜像通过docker run启动容器的实例。
首先Dockerfile并不能代替docker run,Dockerfile主要是用来预执行部分命令并构建镜像。
然后使用 docker run 命令指定该镜像让运行容器时达到简化命令的目的。
然后通过docker build命令构建一个新的镜像,最后还是要用到docker run命令,配置参数,指定新构建的镜像运行容器。
为什么不能直接代替 docker run ? 我初步推测是因为如果使用了像-v,--network,--ip这些参数如果用来构建镜像,将毫无扩展性。
当然Dockerfile还有更多的高阶用法,之后自己挖掘...

Dockerfile长啥样

Mysql镜像为例,创建一个名为Dockerfile的文件并写入以下内容

FROM mysql:5.7 AS stage-mysql

USER mysql:mysql

ENV MYSQL_ROOT_PASSWORD 123456

更多Dockerfile指令推荐阅读 官方文档《Docker —— 从入门到实践》 了解。
后者有详细介绍十几个常用Dockerfile命令并附上实战案例。

Mysql示例

因为nginx没啥能写,PHP的又太长,所以先用Mysql的。
我们继续拿上面Mysql的Dockerfile做示例,首先将之前只使用docker run构建的mysql-t容器停止并删除:

[root@VM_0_13_centos docker]# docker stop mysql-t
mysql-t
[root@VM_0_13_centos docker]# docker rm mysql-t
mysql-t

使用 docker build 命令构建镜像
以上面的Mysql Dockerfile为例,我们切换到Dockerfile所在目录然后:

[root@VM_0_13_centos mysql]# docker build -t mysql-t .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM mysql:5.7 AS stage-mysql
 ---> e1e1680ac726
Step 2/3 : USER mysql:mysql
 ---> Using cache
 ---> 90ddaaafe262
Step 3/3 : ENV MYSQL_ROOT_PASSWORD 123456
 ---> Using cache
 ---> ca4fec9a3d81
Successfully built ca4fec9a3d81
Successfully tagged my-mysql:latest
[root@VM_0_13_centos mysql]# 

-t参数打上标签
此时可以通过docker image ls 看到多出来一个名为mysql-t的镜像。

接下来使用构建好的镜像通过docker run 运行容器:

[root@VM_0_13_centos mysql]# docker network create --driver=bridge --subnet=172.18.0.0/24 net-t
bc9d6864c53c883ced12cc62afb3fe1ed06909842f64d68b67728373ce665d83
[root@VM_0_13_centos mysql]# docker run \
>          -p 3306:3306 \
>          --network=net-t \
>          --ip=172.18.0.4 \
>          --name mysql-t \
>          -v /var/www/mysql/conf:/etc/mysql/conf.d \
>          -v /var/www/mysql/data:/var/lib/mysql \
>          -d \
>          mysql-t
7e87c66e881a38c0bd1d94e79c3218b5ebbfe070713e6b953e171fa469f1bc59

其实对比上一篇文章给出的Mysql镜像的docker run命令也就少了
--user mysql:mysql
-e MYSQL_ROOT_PASSWORD=123456
这两个参数而已,但如果是像PHP要安装扩展的话,将省了不少命令,后面会放出。

PHP和Nginx的Dockerfile

首先Nginx的Dockerfile没啥好写,因为我做法是将配置文件、项目文件目录都通过-v挂载到容器里面,方便日后更改。
当然各有各的用法,有些会将配置文件和项目文件复制到镜像里,所以会写Dockerfile

PHP的话就比较复杂了,因为PHP镜像你直接运行的话是几乎啥扩展都没的,所以基本都需要Dockerfile去写RUN,然后将多个命令通过&&串起来执行。
这里 Dockerhub的PHP主页 给了一个非常好的开头示范,里面也提到了除通过docker-php-ext-install脚本来安装外,还能通过pecl脚本来安装,两者同样在/usr/local/bin目录下的。
下面直接贴出PHP的Dockerfile,然后挑一些命令来讲解。
那些stop、rm原有容器,或者一些小问题不过多讲解,自己搞定。

FROM php:7.1-fpm AS stage-php

WORKDIR /usr/local/bin

COPY composer .

RUN cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini \
    && apt-get update \
    && apt update ; yes "" |apt install git \
    && apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
        libxslt1-dev \
    && rm -r /var/lib/apt/lists/* \
    && ./docker-php-ext-install pdo_mysql \
    && ./docker-php-ext-install mysqli \
    && ./docker-php-ext-install bcmath \
    && ./docker-php-ext-install mbstring \
    && ./docker-php-ext-install opcache \
    && ./docker-php-ext-install xsl \
    && ./docker-php-ext-install pcntl \
    && ./docker-php-ext-install -j$(nproc) iconv \
    && ./docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && ./docker-php-ext-install -j$(nproc) gd \
    && pecl install igbinary \
    && docker-php-ext-enable igbinary \
    && yes "" |pecl install lzf \
    && docker-php-ext-enable lzf \
    && yes "" |pecl install redis-4.0.1 \
    && docker-php-ext-enable redis

COPY composer .
意思是将你运行docker build时的当前目录的composer文件复制到镜像的当前目录上。
这个镜像的当前目录默认好像是/ ,但经上一行WORKDIR指定后是/usr/local/bin

yes "" | pecl install lzf
基本所有pcel安装会需要输入yes,有些可能是多次。
进入到PHP的Dockerfile目录,根目录放上composer执行文件。

然后执行:

[root@centos ~]# docker build -t php-t .

运行后执行命令较多,而且根据网络情况决定执行时长,中间过程就不贴出来了。

运行容器:

[root@centos ~]# docker run -d \
> --network=net-t \
> --ip=172.18.0.3 \
> -p 9000:9000 \
> --name php-t \
> -v /var/www/html:/var/www/html \
> php-t
3e289cf2175a8cf0fddeec41bf5d975730adc71f87df56cd3d987b0fb3c8231c

尝试通过Mysql和PHP的两个Dockerfile构建镜像后运行容器,测试下:

  1. Nginx能否成功通过9000端口反代到PHP容器;
  2. 项目目录的index.php也建议写一个phpinfo()看看扩展是否都已经成功安装并开启;
  3. 再写一段简单的PDO/Mysqli代码链接数据库试试。

连接数据库这里有个需要注意的,因为Mysqli默认情况下host如果写的是localhost的话会以unix domain socket的方式连接Mysql,一般都会报类似无法找到mysql.sock文件的错误。
解决方法:

  • 与Nginx的配置文件一样,使用网关+端口的形式(host=172.18.0.1,port=3306 )
  • 在宿主机增加一个目录专门存放mysql.sock,然后Mysql和PHP容器在运行时都挂载该目录,那挂载时PHP和Mysql容器那边的目录分别是php.ini中PDO/Mysqli的默认socket路径和my.cnf默认的mysql.sock路径。但可能需要后期在宿主机的目录手动创建一个mysql.sock文件。

当然,你挂载目录和手动创建了mysql.sock后在PHP代码里使用socket方式连接时可以额外指定sock文件目录而使用php.ini的,看你哪个方便来咯。

下一篇文章会介绍docker-compose,让你把剩余的docker run 命令也写进去,直接一条命令就可以搭好整个环境。

标签: none

添加新评论