暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Docker(3)-Dockerfile文件

技术白小白 2019-11-27
334

Docker(3)-Dockerfile文件

Docker(3)-Dockerfile文件    Dockerfile文件        Dockerfile文件格式        通过Dockerfile构建镜像        .dockerignore 文件    Dockerfile指令        COPY        ADD        CMD 容器启动命令        ENTRYPOINT 入口点             场景一:让镜像变成像命令一样使用            场景二:应用运行前的准备工作        ENV 环境变量        ARG 构建参数        VOLUME 定义匿名卷        EXPOSE 声明端口        WORKDIR 指定工作目录        USER        ONBUILD    参考文档


Dockerfile文件

Dockerfile是一个文本文件,包含一条条的指令,每一条指令构建一层,因此在Dockerfile添加或修改指令,重新生成image,就可以定制自己的需求。

Dockerfile文件格式

Dockerfile文件格式如下

 ##  Dockerfile文件格式
 
 # This dockerfile uses the ubuntu image
 # VERSION 2 - EDITION 1
 # Author: docker_user
 # Command format: Instruction [arguments / command] ..
 
 # 1、第一行必须指定 基础镜像信息,必须为FROM开始
 FROM ubuntu
 
 # 2、维护者信息
 LABEL version="1.0"
 # MAAINAINER已弃用
 LABEL maintainer="docker_user<docker_user@163.com>"
 LABEL description="描述"
 
 # 3、镜像操作指令
 RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
 RUN apt-get update && apt-get install -y nginx
 RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
 
 # 4、容器启动执行指令
 CMD /usr/sbin/nginx

Dockerfile文件分为四部分,基础镜像信息,维护者信息,镜像操作有指令,容器启动指令

通过Dockerfile构建镜像

构建镜像使用docker build
命令,docker build
会根据Dockerfile文件及上下文构建新的Docker镜像, 因此需要在Dockerfile的当前目录下运行docker build
命令,例如

 $ mkdir mynginx
 $ cd mynginx
 $ vim Dockerfile
 
 #Dockerfile文件内容
 FROM nginx
 
 LABEL version="1.0"
 LABEL maintainer="baymux<baymux@163.com>"
 LABEL description="build my nginx image"
 
 RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 
 $ pwd
 # 当前目录/home/test/mynginx
 $ docker build -t nginx:v1 .

在构建的时候,可以通过 .dockerignore
文件排除不需要的文件和目录。

构建时,可以使用-t
参数添加镜像标签

更多参数,参考

[docker build]:( https://docs.docker.com/engine/reference/commandline/build/ )

构建时,Docker守护进程会一条一条一次执行Dockerfile指令,每一步会提交并生成一个新的镜像,输出镜像id,生成完成或,Docker守护进程会自动清理上下文。Docker会重用已经生成的中间镜像,加上docker build的速度。

.dockerignore 文件

在Docker将上下文发送给守护基础之前,他会在.doclerignore
文件中查找上下文目录,并排除这些不需要的文件和目录。这有助于提高构建性能, 避免使用ADD
COPY
将它们添加到映像中。

Dockerfile指令

COPY

copy有两种格式,一种类似于命令行,一种类似于函数调用

 COPY [--chown=<user>:<group>] <src>... <dest>
 COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

COPY指令从源目录<src>
复制目录或者文件,并将他们添加到新的一层镜像的文件系统中的目标路径<dest>

<scr>
可以有多个,可以是通配符,<dest>
可以是容器内绝对路径,也可以是相对于工作目录(WORKDIR
指定)的相对路径。

 COPY hom* /mydir/
 COPY hom?.txt /mydir/

ADD

add有两种格式,一种类似于命令行,一种类似于函数调用

 ADD [--chown=<user>:<group>] <src>... <dest>
 ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

ADD
COPY
作用基本一致,但比COPY
强大,

源路径可以是url
,可以自动解压等。

 FROM scratch
 ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
 ...

CMD 容器启动命令

CMD
指令有两种格式,和RUN
相似

 CMD ["executable","param1","param2"] (exec form, this is the preferred form)
 CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
 CMD command param1 param2 (shell form)

Dockerfile
只能有一个CMD
指令,如果存在多个CMD
指令,则只有最后一个会生效。

CMD
指令就是用于指定默认的容器主进程的启动命令的

ENTRYPOINT 入口点

ENTRYPOINT
格式与RUN
类似

 ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
 ENTRYPOINT command param1 param2 (shell form)

ENTRYPOINT
CMD
一样,都是在指定容器启动程序和参数,ENTRYPOINT
也可以在运行时通过docker run
参数 --entrypoint
来指定,当指定了 ENTRYPOINT
后,CMD
的含义就发生了改变,不再是直接的运行其命令,而是将 CMD
的内容作为参数传给 ENTRYPOINT
指令,将变为:

 <ENTRYPOINT> "<CMD>"

场景一:让镜像变成像命令一样使用

比如我们有一个用CMD
实现的获取自己公网IP的镜像,

 FROM ubuntu:18.04
 RUN apt-get update \
    && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*
 CMD [ "curl", "-s", "https://ip.cn" ]

使用docker build -t myip .
构建镜像,我们查询自己公网IP时只需要执行:

 $ docker run myip
 {"ip": "111.232.89.200", "country": "上海市", "city": "腾讯"}

上面命令实际执行的是CMD
中的CMD [ "curl", "-s", "https://ip.cn" ]
,等价于curl -s https://ip.cn

虽然现在看起来可以把镜像当命令使用了,但是如果我们需要显示HTTP头信息的时候,问题就显而易见了,

 $ docker run myip -i
 container_linux.go:235: starting container process caused "exec: \"-i\": executable file not found in $PATH"
 /usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:235: starting container process caused "exec: \"-i\": executable file not found in $PATH".

我们可以在docker run myip
加入完整的命令来实现它

 $ docker run myip curl -s https://ip.cn -i
 HTTP/2 200
 date: Wed, 27 Nov 2019 03:02:30 GMT
 content-type: application/json; charset=UTF-8
 set-cookie: __cfduid=d9a22b8de6d700a6ebec8b6762b100a741574823750; expires=Fri, 27-Dec-19 03:02:30 GMT; path=/; domain=.ip.cn; HttpOnly
 cf-cache-status: DYNAMIC
 expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
 server: cloudflare
 cf-ray: 53c0dd1778317836-LAX
 
 {"ip": "111.331.89.200", "country": "上海市", "city": "腾讯"}

显然这种方式不太友好,我们可以使用ENTRYPOINT
解决这个问题

 FROM ubuntu:18.04
 RUN apt-get update \
    && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*
 ENTRYPOINT [ "curl", "-s", "https://ip.cn" ]

构建运行,

 $ docker build -t myip1 .
 $ docker run myip1
 {"ip": "111.231.89.210", "country": "上海市", "city": "腾讯"}
 $ docker run myip1 -i
 HTTP/2 200
 date: Wed, 27 Nov 2019 03:07:01 GMT
 content-type: application/json; charset=UTF-8
 set-cookie: __cfduid=db8ab208920bbb68fe9a0b8fd8d489efe1574824020; expires=Fri, 27-Dec-19 03:07:00 GMT; path=/; domain=.ip.cn; HttpOnly
 cf-cache-status: DYNAMIC
 expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
 server: cloudflare
 cf-ray: 53c0e3b2de02793a-LAX
 
 {"ip": "111.231.89.200", "country": "上海市", "city": "腾讯"}

上面的docker run myip1 -i
就相当于docker run myip1 -i
,在使用ENTRYPOINT
后,cmd
命令将作为参数传给 ENTRYPOINT

场景二:应用运行前的准备工作

启动容器就是启动主进程,但通常我们需要做一些准备工作,比如mysql,redis
等,需要在启动之前进行配置,那么可以使用ENTRYPOINT
来预处理。

我们可以将准备工作先写一个脚本,然后使用ENTRYPOINT ["xxx.sh"]
来运行处理准备工作。

ENV 环境变量

ENV
的格式有两种:

 ENV <key> <value>
 ENV <key>=<value> ...

ENV
指令将环境变量<key>
设置为<value>
,不管是后面的指令,还是运行时的应用,都可以使用ENV
设置的环境变量。

可以使用docker inspect
查看ENV
的值,也可以使用docker run --env <key>=<value>
更改它的值。

 ENV myName John Doe
 ENV myDog Rex The Dog
 ENV myCat fluffy

ARG 构建参数

格式:ARG <name>[=<default value>]

ARG
ENV
的效果是一样的,都是设置环境变量, 但ARG
所设置的环境变量,在将来容器运行时是不会存在这些环境变量的。虽然如此,但也不能因此使用ARG
保存密码,docker history
可以看到这些值。

也可以在docker build
使用--build-arg <参数名>=<值>
设定。

VOLUME 定义匿名卷

EXPOSE 声明端口

格式:

 EXPOSE <port> [<port>/<protocol>...]

EXPOSE
指令申明r容器在运行时监听指定的网络端口。默认为TCP
,虽然申明了服务端口,但并未开启该端口,相当于参考文档,当需要开启端口时,在docker run
添加 -p
参数来发布或映射一个或多个端口,或者使用docker run -P
随机映射端口时,,会自动映射到EXPOSE
的端口。

同时开启TCP、UDP

 EXPOSE 80/tcp
 EXPOSE 80/udp

docker run -p
将容器对应端口服务公开给外界使用。

 # -p <宿主端口>:<容器端口>
 $ docker run -p 80:80/tcp -p 80:80/udp ...

WORKDIR 指定工作目录

格式:

 WORKDIR /path/to/workdir

使用WORKDIR
指定工作目录或者当前目录

WORKDIR
指令的对RUN
CMD
ENTRYPOINT
COPY
ADD
都设定工作目录。如果WORKDIR
不存在,那么即使以后的任何Dockerfile
指令中都没有使用它,也将创建它。

 WORKDIR /a
 WORKDIR b
 WORKDIR c
 RUN pwd
 # /a/b/c
 ENV DIRPATH /path
 WORKDIR $DIRPATH/$DIRNAME
 RUN pwd
 # /path/$DIRNAME

USER

ONBUILD

参考文档

  • [Dockerfile reference]:  https://docs.docker.com/engine/reference/builder

  • [Dockerfile 指令详解]:  https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/


文章转载自技术白小白,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论