云原生应用4:Dockerfile制作镜像
上一篇 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文件,里面有很多指令的用法,我也在学习中,共勉
更多推荐
所有评论(0)