Docker实战(五)编写Dockerfile
一、创建Dockerfile文件
首先,需要创建一个目录来存放 Dockerfile 文件,目录名称可以任意,在目录里创建Dockerfile文件:
二、Dockerfile 基本框架
Dockerfile一般包含下面几个部分:
- 基础镜像:以哪个镜像作为基础进行制作,用法是
FROM 基础镜像名称
- 维护者信息:需要写下该Dockerfile编写人的姓名或邮箱,用法是
MANITAINER 名字/邮箱
- 镜像操作命令:对基础镜像要进行的改造命令,比如安装新的软件,进行哪些特殊配置等,常见的是
RUN 命令
- 容器启动命令:当基于该镜像的容器启动时需要执行哪些命令,常见的是
CMD 命令
或ENTRYPOINT
在本节实验中,我们依次先把这四项信息填入文档。Dockerfile中的#
标志后面为注释,可以不用写。
打开Dockerfile,依次输入下面的基本框架内容:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
# Version 0.1 # 基础镜像 FROM debian:latest # 维护者信息 MAINTAINER wl1524520@gmail.com # 镜像操作命令 RUN apt-get -yqq update && apt-get install -yqq apache2 && apt-get clean # 容器启动命令 CMD [ "/usr/sbin/apache2ctl" , "-D" , "FOREGROUND" ] |
上面的Dockerfile非常简单,创建了一个apache的镜像。包含了最基本的四项信息。
其中FROM
指定基础镜像,如果镜像名称中没有制定TAG,默认为latest
。RUN
命令默认使用/bin/sh
Shell执行,默认为root权限。如果命令过长需要换行,需要在行末尾加\
。CMD
命令也是默认在/bin/sh
中执行,并且默认只能有一条,如果是多条CMD
命令则只有最后一条执行。用户也可以在docker run
命令创建容器时指定新的CMD
命令来覆盖Dockerfile里的CMD
。
这个Dockerfile已经可以使用docker build
创建新镜像了,先构建一个版本dockertest:0.1:
1
2
|
# 在dockertest目录,即Dockerfile所在的目录执行 docker build -t dockertest:0.1 . |
构建需要安装apache2,会花几分钟,最后查看新创建的镜像:
使用该镜像创建容器site1,将容器中的端口8888映射到本地80端口:
1
|
docker run -d -p 8888:80 --name site1 dockertest:0.1 |
使用浏览器打开localhost:8888
进行测试,查看是否apache已运行:
三、Dockerfile 编写常用命令
在上述基本的架构下,我们根据需求可以增加新的内容到Dockerfile中。后续的扩展操作都需要放置在Dockerfile的镜像操作部分。
1)指定容器运行的用户
该用户将作为后续的RUN命令执行的用户。命令使用方式,例如使用nginx用户来执行后续命令:
1
|
USER nginx |
2)指定后续命令的执行目录
由于我们需要运行的是一个静态网站,将启动后的工作目录切换到/var/www/html
目录:
1
|
WORKDIR /var/www/html |
3)对外连接端口号
由于内部服务会启动Web服务,我们需要把对应的80端口暴露出来,可以提供给容器间互联使用,可以使用EXPOSE
命令。
在镜像操作部分增加下面一句:
1
|
EXPOSE 80 |
4)设置容器主机名
ENV
命令能够对容器内的环境变量进行设置,我们使用该命令设置由该镜像创建的容器的主机名为dockertest
,向Dockerfile中增加下面一句:
1
|
ENV HOSTNAME dockertest |
5)向镜像中增加文件
向镜像中添加文件有两种命令:COPY
和 ADD
。
COPY
命令可以复制本地文件夹到镜像中:
1
|
COPY site1 /var/www/html |
ADD
命令支持添加本地的tar压缩包到容器中指定目录,压缩包会被自动解压为目录,也可以自动下载URL并拷贝到镜像,例如:
1
2
|
ADD html. tar /var/www ADD http: //192 .168.1.200 /html . tar /var/www |
6)CMD 与 ENTRYPOINT
ENTRYPOINT
容器启动后执行的命令,让容器执行表现的像一个可执行程序一样,与CMD
的区别是不可以被docker run
覆盖,会把docker run
后面的参数当作传递给ENTRYPOINT
指令的参数。Dockerfile中只能指定一个ENTRYPOINT
,如果指定了很多,只有最后一个有效。docker run
命令的-entrypoint
参数可以把指定的参数继续传递给ENTRYPOINT
。
7)挂载数据卷
将apache访问的日志数据存储到宿主机可以访问的数据卷中:
1
|
VOLUME [ "/var/log/apche2" ] |
8)设置容器内的环境变量
使用ENV
设置一些apache启动的环境变量:
1
2
3
4
5
6
|
ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apche2 ENV APACHE_PID_FILE /var/run/apache2 .pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apche2 |
9)使用 Supervisord
CMD如果只有一个命令,那如果我们需要运行多个服务怎么办呢?最好的办法是分别在不同的容器中运行,通过link进行连接。如果一定要在一个容器中运行多个服务可以考虑用Supervisord
来进行进程管理,方式就是将多个启动命令放入到一个启动脚本中。
首先安装Supervisord
,添加下面内容到Dockerfile:
1
2
|
RUN apt-get install -yqq supervisor RUN mkdir -p /var/log/supervisor |
拷贝配置文件到指定的目录:
1
|
COPY supervisord.conf /etc/supervisor/conf .d /supervisord .conf |
其中supervisord.conf
文件需要放在dockertest目录下,文件内容如下:
1
2
3
4
5
|
[supervisord] nodaemon= true [program:apache2] command = /bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2ctl -D FOREGROUND" |
如果有多个服务需要启动可以在文件后继续添加[program:xxx]
,比如如果有ssh服务,可以增加[program:ssh]
。
修改CMD
命令,启动Supervisord
:
1
|
CMD [ "/usr/bin/supervisord" ] |
四、从 Dockerfile 创建镜像
在dockertest文件夹中有如下三个文件:
Dockerfile
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# debian apache2 php5 ssh vim # Version 0.2 # 基础镜像 FROM debian:latest # 维护者信息 MAINTAINER wl1524520@gmail.com # 设置debian的镜像,加快速度 RUN echo 'deb http://mirrors.aliyun.com/debian/ jessie main non-free contrib' > /etc/apt/sources .list \ && echo 'deb http://mirrors.aliyun.com/debian/ jessie-proposed-updates main non-free contrib' >> /etc/apt/sources .list \ && echo 'deb http://mirrors.aliyun.com/debian-security/ jessie/updates main non-free contrib' >> /etc/apt/sources .list # 镜像操作命令 RUN apt-get -yqq update \ && apt-get install -yqq supervisor openssh-server openssh-client vim \ && apt-get install -yqq apache2 php5 php5-mcrypt php5-mysql php5-imagick php5-json php5-curl \ && apt-get clean # 设置 ssh,root密码为 www.wanglu.info RUN echo 'root:www.wanglu.info' | chpasswd \ && mkdir /var/run/sshd \ && sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config # 设置 supervisor RUN mkdir -p /var/log/supervisor COPY supervisord.conf /etc/supervisor/conf .d /supervisord .conf # 拷贝phpinfo.php文件到容器的 /var/www/html COPY phpinfo.php /var/www/html ENV HOSTNAME docker- test ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ENV APACHE_PID_FILE /var/run/apache2 .pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 EXPOSE 22 80 # 启动容器命令 CMD [ "/usr/bin/supervisord" ] |
supervisord.conf
1
2
3
4
5
6
7
8
9
|
# supervisord configuration [supervisord] nodaemon= true [program: ssh ] command = /usr/sbin/sshd -D [program:apache] command = /bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2ctl -D FOREGROUND" |
phpinfo.php
1
2
|
<?php phpinfo(); |
在dockertest目录下使用 docker build
执行创建,-t
参数指定镜像名称:
1
|
docker build -t dockertest:0.2 . |
docker images
查看创建的新镜像已经出现在了镜像列表中:
由该镜像创建新的容器site2,并映射本地的8080端口到容器的80端口、8022端口到容器的22端口:
1
|
docker run -d -p 8080:80 -p 8022:22 --name site2 dockertest:0.2 |
五、运行测试
部分操作截图:
打开测试网页