-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Dockerfile
虽然我们确实能快速搭建了一个 lnmp 的环境,但是每次切换宿主机时,都要执行多个步骤:
- 启动 mysql 服务器
- 启动 php 服务器
- 进入 php 容器修改配置
- 启动 nginx 服务器
怎么说都还是麻烦。如果能一键启动的话,那就更好了。
Dockerfile 就可以解决这样的问题。
要使用 Dockerfile ,先要了解一下这到底是个什么东西。
什么是 Dockerfile?
A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession.
Dockerfile是一个文本文档,其中包含用户可以在命令行上调用以组合镜像的所有命令。使用docker构建用户可以创建一个自动构建,连续执行几个命令行指令。
Dockerfile 常用命令
FROM
语法: FROM <image> [AS <name>]
or FROM <image>[:<tag>][AS ]
or FROM <image>[@<digest>][AS ]
注意:FROM 命令必须是 Dockerfile 的首个命令,但可以在一个 Dockerfile 中出现多次。
说明: 该命令定义了使用哪个基础镜像启动构建流程。基础镜像可以为任意镜像。
MAINTAINER
语法: MAINTAINER <NAME>
说明: 设置生成镜像的作者名字。
RUN
语法:
RUN <command>
(shell形式,/bin/sh -c
或者是 Windows 的cmd /S /C
)RUN ["<executable>", "<param1>", "<param2>"]
(exec 形式)
说明:
RUN命令将在当前image中执行任意合法命令并提交执行结果。
RUN 指令缓存不会在下个命令执行时自动失效。
RUN命令用于创建镜像(在之前commit的层之上形成新的层)。
ADD
语法:
ADD <src> [<src> ...] <dest>
ADD ["<src>", ... "<dest>"]
(路径中包含空格的必须使用该形式)
注意:ADD只有在build镜像的时候运行一次,后面运行container的时候不会再重新加载了。
说明: 从 src
拷贝新的文件或文件夹或远程文件 URL 到镜像的文件系统的路径 dest
中。
- 所有拷贝到 container 中的文件和文件夹权限为 0755 , uid 和 gid 为0。
- 如果文件是可识别的压缩格式,则 docker 会自动解压缩。
- 如果
src
为本地文件或文件夹,则必须相对于docker build <PATH>
中的<PATH>
目录中。 dest
是一个绝对路径,或者相对于WORKDIR
,如果<dest>
不存在则会自动创建。
COPY
COPY <src> [<src> ...] <dest>
COPY ["<src>", ... "<dest>"]
(路径中包含空格的必须使用该形式)
COPY 的语法和使用说明和 ADD 基本一致,但是在遇见压缩包时, COPY 很直接的拷贝到容器当中,而不会解压。 Docker 团队建议大多数情况下使用 COPY。
CMD
语法:
CMD ["<executable>","<param1>","<param2>"]
exec 形式,比较好的形式。CMD ["<param1>","<param2>"]
作为 ENTRYPOINT 的默认参数。CMD <command> <param1> <param2>
shell 形式。
注意:Dockerfile 中只能有一个 CMD 指令,如果有多个则只有最后一个生效。
说明:
CMD 命令最主要的目的是提供一个默认的执行容器。
和RUN命令相似,CMD可以用于执行特定的命令。和RUN不同的是,这些命令不是在镜像构建的过程中执行的,而是在用镜像构建容器后被调用。
如果 CMD 用于为 ENTRYPOINT 提供默认参数时, CMD 和 ENTRYPOINT 指令应该规定为 JSON 数组格式。
当 docker run command
的命令匹配到 CMD command
时,会替换CMD执行的命令,即 docker run命令如果指定了参数会把CMD里的参数覆盖: (这里说明一下,如:docker run -it ubuntu /bin/bash 命令的参数是指/bin/bash 而非 -it ,-it只是docker 的参数,而不是容器的参数,以下所说参数均如此。)
ENTERYPOINT
语法:
ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
(exec 形式,推荐)ENTRYPOINT <command> <param1> <param2>
(shell 形式)
注意:Dockerfile 中只能有一个 ENTRYPOINT 指令,如果有多个则只有最后一个生效。
说明:
配置容器启动后执行的命令,并且参数不可被 docker run
提供的参数覆盖。
如果结合 CMD 使用时,要使用 exec 的形式,即:
ENTRYPOINT ["echo"]
CMD ["HELLO_WORLD"]
这是 CMD 命令的内容则不是一个完整的指令,而是为 ENTRYPOINT 命令提供默认参数,该参数可以被 docker run
后的参数所覆盖。
EXPOSE
语法: EXPOSE <port> [<port> ...]
说明: 通知 Docker 在运行时监听指定的端口。主机上要用还得在启动container时,做host-container的端口映射。
ENV
语法:
ENV <key> <value>
ENV <key>=<value> [<key>=<value> ...]
说明:
该指令将环境变量的 key
设置为 value
,这些值都可以在 Dockerfile 后续的命令中用上,并可以被修改。
VOLUME
语法:
VOLUME ["<path>", ...]
VOLUME <path> [<path> ...]
说明: 创建一个有具体名称的挂载点,并将其标记为从本机或者其他容器外部的挂载卷。
USER
语法: USER <username | UID>
说明: 指定某个用户运行容器。
WORKDIR
语法: WORKDIR </path/to/workdir>
说明: 设定指令 CMD
, RUN
, ENTRYPOINT
, COPY
和 ADD
的工作目录。可以在一个 Dockerfile 中出现多次,如果提供了一个相对路径,那么它将相对于前一个 WORKDIR 指令的路径。
ARG
语法: ARG <name>[=default value>]
说明:
- 定义一个变量,用户可以在建立的时候通过
docker build
命令使用—build-arg <varname>=<value>
指定。 - 多条 ARG 指令可以定义指定的变量,但是在构建成功后取消。
- 相同名字的环境变量会被 ENV 指令的覆盖。
- Docker 有一组预定义的 ARG 变量,可以在 Dockerfile 中使用而不需要 ARG 指令。
ONBUILD
语法: ONBUILD <Dockerfile INSTRUCTION>
说明:
- 当镜像作为另一个镜像构建的基础时,添加一个被延时执行的触发指令。就类似于在子镜像的 Dockerfile 的 FROM 指令下插入了一条命令。
- ONBUILD 指定的命令在构建镜像时不执行,只在它的子镜像中执行。
- 任何构建指令都可以被注册为触发器,但
ONBUILD
指令不一定触发FROM
,MAINTAINER
或者ONBUILD
指令。
Dockerfile 构建镜像
现在将先前搭建 lnmp 的具体步骤一步步写进 Dockerfile 中。
MySQL
FROM mysql
MAINTAINER LeungJZ
ENV MYSQL_ROOT_PASSWORD 123456
EXPOSE 3306
没啥太多的配置,就是简单的配置ROOT密码和暴露3306端口。
构建镜像:
leung@ubuntu:~/docker$ docker build ./mysql/ -t test-mysql
Sending build context to Docker daemon 2.56kB
Step 1/4 : FROM mysql
---> 141d24fea983
Step 2/4 : MAINTAINER LeungJZ
---> Using cache
---> aa6665261e02
Step 3/4 : ENV MYSQL_ROOT_PASSWORD 123456
---> Using cache
---> 4d482f48a09d
Step 4/4 : EXPOSE 3306
---> Using cache
---> 385bb10cd49a
Successfully built 385bb10cd49a
Successfully tagged test-mysql:latest
瞬间构建成功。再启动一个容器 docker run --name mysql -p 3306:3306 -d test-mysql
,和以前基本一致。
Php7.1-fpm
FROM php:7.1-fpm
MAINTAINER LeungJZ
COPY php.ini /usr/local/etc/php/conf.d/php.ini
RUN /usr/local/bin/docker-php-ext-install pdo_mysql
EXPOSE 9000
CMD ["php-fpm"]
指定了 php-fpm 的版本为 7.1,并覆盖了我们自定义的 php.ini ,并且安装 pdo_mysql 拓展。
leung@ubuntu:~/docker$ docker build ./php/ -t test-php7
Sending build context to Docker daemon 70.14kB
Step 1/6 : FROM php:7.1-fpm
---> 9b44e8b4c8b6
Step 2/6 : MAINTAINER LeungJZ
---> Using cache
---> 1038ce686af9
Step 3/6 : COPY php.ini /usr/local/etc/php/conf.d/php.ini
---> Using cache
---> cdbdece75628
Step 4/6 : RUN /usr/local/bin/docker-php-ext-install pdo_mysql
---> Using cache
---> 8a8cbd9c8ac9
Step 5/6 : EXPOSE 9000
---> Using cache
---> 1fd3881b6769
Step 6/6 : CMD php-fpm
---> Using cache
---> 00d178a9351b
Successfully built 00d178a9351b
Successfully tagged test-php7:latest
因为之前构建过一次,所以全都是从缓存中获取,直接就构建完成。
启动: docker run --name php7-fpm --link mysql:mysql -p 9000:9000 -v $PWD/project:/usr/share/nginx/html -d test-php7
。
nginx
FROM nginx:1.13
MAINTAINER LeungJZ
COPY default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
配置就是基础镜像为 1.13 版本的 nginx ,覆盖自定义的 default.conf 配置文件,暴露80端口,并且不以守护进程模式启动。
leung@ubuntu:~/docker$ docker build ./nginx/ -t test-nginx
Sending build context to Docker daemon 4.608kB
Step 1/5 : FROM nginx:1.13
---> da5939581ac8
Step 2/5 : MAINTAINER LeungJZ
---> Using cache
---> 3076338acc32
Step 3/5 : COPY default.conf /etc/nginx/conf.d/default.conf
---> Using cache
---> bb7ab780e5d4
Step 4/5 : EXPOSE 80
---> Using cache
---> 38dda9a94ae6
Step 5/5 : ENTRYPOINT nginx -g daemon off;
---> Using cache
---> 7864bf277ac0
Successfully built 7864bf277ac0
Successfully tagged test-nginx:latest
启动: docker run --name nginx --link php7-fpm:php7-fpm -v $PWD/project:/usr/share/nginx/html -p 80:80 -d test-nginx
。
访问 http://10.211.55.9/i.php 依旧可以看到熟悉的 phpinfo 的界面。
小结
Dockerfile 可以帮我们减轻了很多配置方面的麻烦,但是启动时,依旧需要绑定很多变量,如挂载卷,映射端口等。虽然只需 run 一次,但是这也是麻烦的。
当然,肯定有解决的办法,就是接下来的 docker-compose 。