上一篇 docker镜像管理 中介绍了 使用docker commit 命令打包容器为镜像,本篇将介绍使用Dockerfile制作镜像

要点:需要一个专门的目录,存放Dockerfile文件,且Dockerfile文件首字母必须大写,如果有某些文件要打包到镜像中,需要把这些文件也放到该目录(和Dockerfile文件同一目录),如果要忽略某些文件,创建一个.dockeringore文件,该文件中包含的文件名在docker打包时不会被打包进docker镜像中,剩下就是Dockerfile文件中制作镜像的指令了,指令有很多需要大家自己多多练习使用,或看其他公司制作镜像的Dockerfile文件内容

使用 docker build 对Dockerfile制作镜像,详细可以使用 docker build --help 查看制作镜像时的所有参数

Dockerfile指令详解

Dockerfile中包括FROM、MAINTAINER、LABLE、COPY、ADD、WORKDIR、VOLUME、EXPOSE、ENV、RUN、CMD、ENTRYPOINT、USER、ARG、ONBUILD等多个指令。

  • 1.FROM,指定基础镜像,格式为FROM image或FROM image:tag,并且Dockerfile中第一条指令必须是FROM指令
  • 2.MAINTAINER(已过期),格式为MAINTAINER user_name user_email,指定维护者信息,可使用LABEL替换
  • 3.LABLE,格式为LABLE < key>=< value> < key>=< value>,用于替代MAINTAINER
  • 4.COPY,用于从宿主机复制src目录或文件到容器的desc目录,desc不存在时会自动创建,格式为 COPY < src> < dest> 或COPY [“< src>”,…,“< dest>”],src有多个,请使用第二种方式,且dest必须是目录
  • 5.ADD,与COPY很相似,但是ADD支持URL路径或一个tar文件,tar文件会自动解压为目录,能访问网络中的文件
  • 6.WORKDIR,定义工作目录,为后续的RUN CMD ENTRYPOINT指定配置工作目录,如 WORKDIR /usr/local/ ,ADD nginx ./ ,此时./ 表示 /usr/local
  • 7.VOLUME,用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其他容器上的卷,如VOLUME /data/mysql/
    镜像中定义存储卷,创建成镜像启动容器后会自动与宿主机进行绑定
  • 8.EXPOSE,用于为容器打开指定要监听的端口以实现与外部通信,状态为待暴露的端口,还不能访问,需与docker run xxx -P ,与大P配合使用,那么容器中的端口则真正绑定了宿主机的端口
  • 9.ENV,格式EVN key value 。用于指定环境变量,后续可以被RUN COPY等指令使用,容器运行起来之后,也可以在容器中获取这些环境变量,如ENV word hello,RUN echo ${word:-zhuyu} 赋默认值,如果没有word变量则输出zhuyu,docker run 容器时可传变量值覆盖word值,docker run --name b1 --rm -e word=“zhangsan” tinyhttpd:v0.1
  • 10.RUN,RUN 与 CMD 都是运行命令的,只是两者运行的时间点不一样,RUN是docker build时运行的,CMD是docker run 时运行的,格式为RUN command或 RUN [“EXECUTABLE”,“PARAM1”,“PARAM2”…],前者在shell终端中运行命令,/bin/sh -c command,例如:/bin/sh -c “echo hello”;后者使用exec执行,可指定其他运行终端使用RUN[“/bin/bash”,“-c”,“echo hello”]
  • 11.CMD,是镜像启动为容器时默认要运行的命令,如果有多个CMD指令,则只会执行最后一个CMD
    支持三种格式:
    CMD command param1 param2 在/bin/sh中执行。
    CMD [“executable”,“param1”,“param2”],使用exec执行。
    CMD [“param1”,“param2”] 提供给ENTERYPOINT的默认参数。
    前两种语法格式意义同RUN,CMD用于指定容器启动时执行的命令,每个Dockerfile只能有一个CMD命令,多个CMD命令只执行最后一个。若容器启动时指定了运行的命令,则会覆盖掉CMD中指定的命令
  • 12.ENTRYPOINT,格式有两种:
    ENTRYPOINT [“executable”,“param1”,“param2”]
    ENTRYPOINT command param1,param2 会在shell中执行。
    用于配置容器启动后执行的命令,这些命令不能被docker run提供的参数覆盖。和CMD一样,每个Dockerfile中只能有一个ENTRYPOINT,当有多个时最后一个生效。
  • 13.USER,格式为:USER username,指定容器运行时的用户名或UID,后续的RUN也会使用指定的用户。要临时使用管理员权限可以使用sudo。在USER命令之前可以使用RUN命令创建需要的用户。
    例如:RUN groupadd -r docker && useradd -r -g docker docker
  • 14.ARG,用于在 docker build 阶段时向Dockerfile文件传变量值,在Dockerfile文件中先定义,
    ARG author=“zhuyu645906265@qq.com
    LABEL maintainer=“${author}”
    通过 --build-arg传参, docker build --build-arg author=“zhangsan zhangsan@qq.com” -t xxx ./
  • 15.ONBUILD,类似于在Dockerfile中定义一个触发器,自己做镜像时ONBUILD不会执行,其他人使用这个为基础镜像时就会执行ONBUILD,如ONBUILD ADD http://xx.com/xx.json /usr/local/ ,其他人FORM你的镜像为基础镜像时会下载此文件

docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出

创建一个Dockerfile,制作镜像

还是以busybox为基础镜像,在Dockerfile目录中创建一个index.html,复制到镜像中,启动容器时执行 httpd 命令,指向该index.html所在目录,打包成镜像后启动为容器后,看能否访问 http 服务,返回index.html

#1.创建一个目录
mkdir -p image1_busybox

#2.进入该目录,创建Dockerfile文件
cd /root/docker_file/image1_busybox
vi Dockerfile

#3.编写Dockerfile,以busybox为基础镜像,定义开发者信息,定义index.html存放目录的环境变量,后面的指令使用该变量,
#  然后把index.html复制到镜像中,最后定义容器启动时执行CMD命令,启动一个httpd服务
FROM busybox:latest
LABEL maintainer="zhuyu <645906265@qq.com>"
ENV webpath /data/html/
COPY index.html ${webpath:-/data/html/}
CMD /bin/httpd -f -h ${webpath:-/data/web/html/}
#CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${webpath}"]

#4.使用docker build 命令制作镜像,./ 表示当前目录的Dockerfile文件
docker build -t webhttpd:v0.1 ./

如果是java应用

# 1.Dockerfile
  FROM java:8-jdk-alpine
  COPY app.jar /opt/
  ENTRYPOINT ["/bin/sh", "-c", "java $JAVA_OPTS -jar /opt/app.jar $0"]
# 2.打成镜像
 docker build -t xxx:v1.0 ./
# 3.运行镜像
 docker run -d --name app -e JAVA_OPTS="-Xms=300m -Xmx=300m -Dzipkin.url=localhost:9411" -p 10688:8080 zipkin-test:v1.0 

打包成功后如下所示,Successfully tagged webhttpd:v0.1
在这里插入图片描述
可使用 docker image ls 查看镜像
在这里插入图片描述
运行webhttpd:v0.1镜像,查看刚刚的index.html是否在容器的 /data/html/index.html 目录下了
docker run --name web1 --rm webhttpd:v0.1 cat /data/html/index.html
在这里插入图片描述
启动webhttpd:v0.1镜像为容器,docker run -d --name web1 --rm webhttpd:v0.1
使用 docker inspect web1,查看容器内部IP,再 curl 该IP ,返回index.html中的内容
在这里插入图片描述

Ok,镜像就做好了,可配合之前的镜像管理把镜像上传到共有registry或私有registry

再看一个Dockerfile文件
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

由于Dockerfile中每条指令都会生成一层新的镜像,所以以上指令,生成了七层镜像,联合挂载时会影响性能,可改写成下面这种方式:

FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

还有mysql的Dockerfile内容:https://github.com/docker-library/mysql/blob/master/5.7/Dockerfile

docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出,如果你的启动命令是 sh -c java xxx -jar xxx.jar & ,代表后台启动,则docker容器会自行退出,需要去掉&符号

Dockerfile制作镜像主要是熟悉里面的相关指令,好的建议是,看一些顶级镜像的Dockerfile文件,里面有很多指令的用法,我也在学习中,共勉

下一篇,云原生应用5:搭建私有Docker Registry仓库

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐