构建Docker镜像有两种方式
1.使用 docker commit命令
2.使用docker build命令&Dockerfile文件
一.使用docker commit命令构建镜像
docker commit 容器名称/容器ID 镜像仓库名/镜像名称[:TAG]
-a "作者信息"
-m "提交信息"
步骤:
1.选取一个基础镜像创建一个容器
2.对容器进行相关修改
3.使用docker commit命令提交修改
example:基于ubuntu基础镜像制作包含apache2的镜像
1.运行一个基于ubuntu基础镜像的交互式容器:docker run -i -t ubuntu /bin/bash
2.进入容器中利用apt-get包管理工具安装apache:
apt-get update
apt-get install apache2
exit
3.退出容器后提交
docker commit
使用 docker inspect 镜像名 查看详情
可以看到:Parent字段存储了父镜像ubuntu的imageId,container:保存了docker commit 提交时容器的id
二.使用dockerfile构建镜像
对比使用docker commit构建镜像,dockerfile提供了镜像构建的可重复性,透明性,幂等性。
核心步骤:
1.创建Dockerfile文件,在Dockerfile中使用DLS(Domain Specific Language)领域专用语言来定义每一步操作。
2.使用Docker build命令基于Dockerfile中的指令构建一个新的镜像。
后续描述会基于一下形式描述
一些基本概念->镜像构建实例->docker build指令&dockerfile详细语法详解
1.一些基本概念
构建环境:保存Dockerfile文件的目录,也称构建上下文,在该目录中可以存放在构建镜像中需要使用的代码文件配置文件等,Docker在构建镜像时将上下文和上下文中的目录文件上传至Docker守护进程,这样守护进行就可以直接访问用户想在镜像中存储的任何代码,文件,数据。请为每个需要构建的镜像创建单独的上下文目录。
Dockerfile文件:用来存储如何构建镜像的语句的文件,存储于构建上下文的根目录下。
.dockerignore:在构建上下文的根目录下,如果存在该文件,该文件内容会被按行切割,每行都是一条文件过滤匹配模式,其作用类似于git系统的.gitignore,该文件用来防止构建上下文中不属于构建需要的文件被上传至Docker守护进程
2.一个简单的镜像构建实例
创建上下文环境:nginx_image
创建Dockfile文件
编辑Dockfile并保存
在上下文环境下运行docker build -t "freesnow1992/nginx" . 构建镜像
此时一个可用的镜像就已经构建好了,相关Dockfile指令&docker build命令含义参照下面的说明
三.docker build指令&dockerfile详细语法详解
Docker build
构建缓存:
Docker会为Dockerfile中的每一条语句新建一个镜像,每个镜像都是一个可复用模块,后续其他构建流程中可使用已经构建过的镜像层来加速构建流程。
任何事情都有两面
好的一面:构建缓存加速了构建过程,同时也减少了存储,因为Docker使用 “写时复制” 使用同一镜像层构建的新镜像,增加的存储只是本条命令产生的新文件。
坏的一面:对于一些非幂等的语句由于使用了构建缓存导致结果不符合预期,例如:RUN apt-get update 指令,如果使用了构建缓存,此时的更新还是使用构建缓存镜像的更新。为了避免这个情况的发生可以使用--no-cache来强制不使用构建缓存。
Docker build用于通过dockerfile定义的指令来构建镜像
格式:Docker build 额外参数 构建上下文
构建上下文:用于指明构建上下文目录的路径,其可以是git仓库源地址,必须保证dockerfile存在于构建上下文的根目录下
额外参数
-t 仓库/镜像:TAG 用于指定构建后镜像的镜像名&Tag
-no-cache 不使用构建缓存,
查看镜像构建过程&镜像层
docker history 镜像ID
Dockerfile的指令
FROM
形式:FROM 基础镜像名
含义:指定一个构建过程的基础镜像,后续构建过程将基于此镜像展开。所以每个Dockerfile的第一条指令必须是FROM
例子:FROM ubuntu:14.04 制定构建基础镜像为ubuntu 14.04
MAINTAINER
形式:MAINTAINER 作者相关信息
含义:用于说明本次构建镜像的作者信息(作者姓名 联系方式)
例子:MAINTAINER linghu linghu@example.com
RUN
形式: RUN 命令 参数
RUN ["命令","参数”,..]
含义:RUN指令会在当前镜像创建的容器中运行制定指令,默认情况下RUN指令会在shell中使用命令包装器/bin/sh -c 来执行
如果运行的镜像不支持shell平台,或不希望在shell中运行可使用exec格式的RUN指令 RUN ["指令","参数"]
例子:
RUN apt-get update && apt-get install -y nginx 使用shell包装器来执行,apt-get包管理器更新&安装nginx
RUN ["apt-get","update"] 使用exec格式制定指令
RUN ["apt-get","install","-y","nginx"]
EXPORT
形式:EXPORT [端口/协议(默认tcp,可指定tpc/udp):通知Docker容器在运行时侦听指定的端口
含义:EXPOSE 指令实际上并未发布端口。它充当构建镜像的人员和运行容器的人员之间的一种文档类型,有关打算发布哪些端口的信息。要在运行容器时实际发布端口,请在 docker run 上使用 -p 标志来发布和映射一个或多个端口,或使用 -P 标志来发布所有公开的端口并将它们映射为高阶端口。
注意:如果将 -P 和 docker run 一起使用,将公开EXPORT指定的端口,但是-P 在主机上使用临时的高阶主机端口,因此该端口对于 TCP 和 UDP 将是不同的。论使用哪种 EXPOSE 设置,都可以在运行时使用 -p 标志覆盖它们
例子:
EXPORT 80/tcp
CMD
形式: CMD ["命令","参数",".."]
CMD 命令 参数 使用该形式Docker会在指定的命令前加上 /bin/sh -c ,不建议使用
含义: CMD用于指定容器启动时要运行的命令,效果同docker run 中指定的命令
注意:CMD命令可以被docker run 中的命令覆盖
Dockerfile 中只能存在一条CMD指令,如果存在多条也只有最后一条会被执行
如果容器想运行多个进程,可以使用类似supervisor的服务管理工具
例子:
CMD ["nginx","-g","daemon off;"]
CMD nginx -g "daemon off;"
ENTRYPOINT
形式:ENTRYPOINT ["命令“,"参数",..]
ENTRYPOINT 命令 参数 使用该形式Docker会在指定的命令前加上 /bin/sh -c ,不建议使用
含义:ENTRYPOINT用于指定容器启动时要运行的命令,效果同docker run 中指定的命令,但是不会被docker run中的参数覆盖,此时如果docker run 存在指令参数,将被作为ENTRYPOINT 指定的命令的参数 传递进来,如果docker run 中没有指定参数,但此时dockerfile文件中存在CMD指令,则cmd指令的参数将作为ENTRYPOINT指定的命令的参数传递进来
注意:如果要强制覆盖ENTRYPOINT的命令,可使用 docker run --entrypoint 进行覆盖
例子:
Dokerfile文件中相关内容如下
----------------------------------
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
----------------------------------
docker run -d -P freesnow1992/nginx :相当于容器启动是的命令为 nginx -g “daemon off;"
docker run -d - P freesnow1992/nginx -h :相当于容器启动时的命令为 nginx -h,此时覆盖了CMD中指定的参数
WORKDIR
形式: WORKDIR 路径名
含义:用来从镜像创建一个新容器时,在容器内部设置一个工作目录,CMD,ENTRYPOINT指定的程序会在这个目录下执。同时可以 使用该指令为Dockerfile中的后续一系列指令设置工作目录
注意:在运行Docker run时可以通过-w参数予以覆盖
例子:
WORKDIR /usr/local 切换当前工作目录为/usr/local
ENV
形式:ENV 变量名 变量值 (只可以设置单个环境变量)
ENV 变量名1=变量值 变量名2=变量值
含义:用来在镜像构建过程中设置环境变量。新的环境变量可以在后续的任何RUN指令中使用,同时环境变量也将在后续由该镜像创建的任何容器中生效。
注意:在运行Docker run时 可以通过 -e 来传递环境变量此时只对该容器的运行时有效
例子:
ENV WDPATH = /usr/local
WORKDIR $WDPATH
USER
形式: USER user/uid:group/gid(用户名必须已经存在,可使用镜像中存在的,或在之前使用RUN useradd 进行新增)
含义:用来指定该镜像会以什么样的用户运行,默认会以root用户运行
注意:在运行Docker run 时,可以通过 -u 来更改用户
例子:
USER 0 使用root用户运行容器
VOLUME
形式:VOLUME ["挂载点",...]
含义:用于向基于镜像创建的容器添加卷。
注意:1.卷可以在容器间共享&重用
2.卷的挂载点会绕过联合文件系统
3.对卷的修改会立即生效,但不会对更新镜像产生影响
4.卷会一直存在知道没有任何容器使用它
例子:
VOLUME ["/opt/test"]
ADD
形式:ADD 构建上下文的文件目录/url地址 镜像中的目的地址
含义:用来将构建上线文中的文件目录复制到镜像中
注意:
ADD 指令通过目的地址的末尾字符来判定文件源时目录还是文件,如果以/结尾,那么Docker认为源位置指向一个目录,否则认 为指向一个文件
不能将构建上下文之外的文件进行ADD操作
如果源文件是归档格式,ADD命令会自动进行unpakc操作
如果目的路径不存在,ADD会自动进行创建,形如使用了mkdir -p
例子:
ADD main.go /usr/local/src/main.go
COPY
形式:ADD 构建上下文的文件目录 镜像中的位置
含义:同ADD命令,但是不会针对归档文件进行unpack操作
例子:
COPY main.go /usr/local/src/main.go
LABLE
形式:LABEL 键="值" 键="值"
含义:使用LABEL为镜像添加元数据
例子:
LABEL version="1.0" location="Shanghai" role="Register Center"
STOPSIGNAL
形式:STOPSIGNAL 信号值/信号名称
含义:用于指定在执行docker stop执行停止容器时,会发给容器的信号,默认情况下会发出SIGTERM,其目的是为了让容器能够优雅的退出,但是如果容器在接受相应指令后(10s)内还是没有停止,此时Docker会帮它退出,此时会发送SIGKILL信号将容器杀死。
例子:
STOPSIGNAL 9
STOPSIGNAL SIGKILL
ARG
形式: ARG 变量名
ARG 变量名=默认值
含义:设置构建过程中使用的变量,和ENV不同,其在镜像生成的容器中并不会存在。
特点:1.ARG存在两个作用域,在FROM命令前定义的变量仅对FROM命令有效,对后续命令无效,在FROM后设置的ARG变量对后续命令有效
例子:
ARG base_image
ARG tag="latest"
FROM ${base_image}:${tag}
Docker build --build-arg base_image=ubuntu
此时效果为
FROM ubuntu:latest
ONBUILD
形式:ONBUILD Dockerfile内部其他指令
含义:用于为镜像构建创建触发器。当以该镜像作为基础镜像的子镜像在构建时,ONBUILD指令会执行。
特点:ONBUILD指令只能被继承一次,即只会在子镜像中执行,而不会在孙子镜像中执行。ONBUILD常用于创建模版镜像
ONBUILD内的指令不会在构建本镜像时执行
例子:
创建nginx镜像模版 freesnow1992/nginx_tpl
FROM ubuntu
MAINTAINER linghu "linghu@example.com"
RUN apt-get update && apt-get install -y nginx
RUN rm /usr/share/nginx/html/index.html
ONBUILD ADD /www /usr/share/nginx/html/
EXPOSE 80
LABEL role="nginx server"
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
在后续以 freesnow1992/nginx_tpl 为基础镜像的子镜像构建过程中,ONBUILD指令会在FROM之后执行