title: Dockerfile实践
date: 2018-09-27 15:58:51
tags: Dockerfile
categories: Docker
catalog: true
Dockerfile是用于构建Dcoker镜像的文件。在前面我们使用docker commit
时也创建了一个新镜像,但使用Dockerfile构建新镜像是常用的方式。在编写好Dockerfile文件后,使用docker build
命令即可构建一个新的镜像。Dockerfile文件的编写需要遵循一些规范。
Dockerfile的编写与脚本文件类似,注释使用#
。
一般Dockerfile文件分成四个部分:基础镜像信息、维护者信息、镜像操作命令、容器启动时执行的命令
基本格式如下,分别对应上面的四个部分:
FROM ...
MAINTAINER ...
RUN ...
CMD ...
第一条指令必须是
FROM
,如果在同一个Dockerfile文件中创建多个镜像时,可以使用多个FROM
(每个镜像一次)
下面总结一些Dockerfile文件中常用的语法:
命令 | 用途 |
---|---|
FROM | base image(基础镜像) |
RUN | 执行命令 |
ADD | 添加文件 |
ARG | 设置构建参数 |
COPY | 复制文件 |
CMD | 执行命令 |
EXPOSE | 暴露端口 |
WORKDIR | 指定路径 |
MAINTAINER | 维护者 |
ENV | 设定环境变量 |
ENTRYPOINT | 容器入口 |
USER | 指定用户 |
VOLUME | mount point 指定挂载点 |
下面写一些小实例,通过编写Dockerfile来构建我们自己的镜像。
在一个新目录下创建如下内容的Dockerfile:
# 基础镜像
FROM ubuntu
# 维护者
MAINTAINER hjw
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
# 执行更新命令
RUN apt-get update
# 安装nginx
RUN apt-get install -y nginx
# 将index.html复制到指定目录
COPY index.html /var/www/html
# 容器入口命令
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
# 暴露端口
EXPOSE 80
上面文件中
sed
命令主要是为了加速。替换apt-get的源地址,使用国内的镜像
Dockerfile中写的命令作用可以看上面的注释。
ENTRYPOINT
的作用主要是指定容器入口即启动时执行的命令,后面为一个数组形式,展开后则是一条命令行。执行这条命令行的主要作用是将nginx在前台执行而不是作为守护进程执行。
另外再创建index.html文件,内容自定。
最终文件夹中的内容如下:
[root@HJWDEV ubuntu-nginx]# ll
总用量 4
-rw-r--r--. 1 root root 0 9月 26 16:06 Dockerfile
-rw-r--r--. 1 root root 54 9月 26 10:53 index.html
使用docker build
命令来构建新的镜像,build 时Docker会在指定的目录中读取Dockerfile文件,并将该目录下的所有内容发送给Docker 服务端,由服务端来构建镜像。也可以通过.dockerignore
文件(每一行添加一条匹配模式)来让 Docker 忽略路径下的目录和文件。镜像构建命令如下:
[root@HJWDEV docker]# docker build -t ubuntu-nginx ubuntu-nginx/.
-t
指定image标签,即镜像名称
最后为构建目录的路径,如果是在ubuntu-nginx
目录下执行构建命令直接使用.
即可。执行后Docker会按Dockerfile中的命令去构建我们的镜像。
执行成功后可以查看镜像是否生成:
[root@HJWDEV docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-nginx latest f6538f6564f6 15 minutes ago 186MB
hello-docker latest be221a20a4d7 3 hours ago 4.41MB
运行ubuntu-nginx
镜像
[root@HJWDEV docker]# docker run -d -p 80:80 ubuntu-nginx
-p
表示端口映射,把nginx的 80 端口映射到宿主机的 80 端口
-d
表示允许该Container作为守护进程来执行
运行成功后访问 宿主机+80 端口,会显示index.html的内容。
因为镜像包含操作系统完整的 root
文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
这种分层的方式可以让有相同内容的镜像共享某一层,可以减少存储压力。
上图中下面的三层是只读层,Docker会把Dockerfile中的每一行都生成一层镜像,在image运行成一个容器时会生成一个容器层,即最上层,它是一个可读可写层。如果下面的层在容器运行中是需要被改动的,则该层会被复制到顶层,所以的改动都会在顶层进行。