docker学习笔记4-dockerfile

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了docker学习笔记4-dockerfile相关的知识,希望对你有一定的参考价值。



dockerfile​

自制镜像:

基于容器,

解决1,如nginx,若环境有m个(开发|测试|生产),功能不同即配置文件不同(web|静态资源|反向代理),这就需要m*n个镜像,不妥当;

解决2,使用模板方式,启动容器时传递到容器中的变量;

用dockerfile;


dockerfile format,2种:

# Comment #1注释

INSTRUCTION arguments #2指令,the instruction is not case-sensitive,however,convention is for them to be UPPERCASE to distingush them from arguments more easily,docker runs instructions in a dockerfile in order; the first instruction must be FROM in order to specify the base image from which you are building


#echo $NAME:-tom #NAME变量若没设置,显示此处默认值

#NAME=jerry

#echo $NAME:-tom

#echo $NAME:+tom #用于判断变量是否设置了,如果设置显示tom,没设置显示空


dockerfile instruction

FROM #是最重要的一个且必须为dockerfile文件的第一行,第一个非注释行,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境;实践中,基准镜像可以是任何可用镜像文件,默认docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从docker hub registry上拉取所需的镜像文件,如果找不到镜像文件docker build会返回错误信息


语法:

FROM <repository>[:<tag>]或

FROM <repository>@<digest> #repository指定base image;tag为base image的标签,可选,省略时默认为latest;digest为自己指定的hash码,对应不上则不会用,更安全


MAINTAINER "<authors detail>" #deprecated,用于让docker制作者提供本人的详细信息,dockerfile并不限制此指令出现的位置,建议在FROM指令后;authors detail可以是任何文本信息,但约定使用作者名称及邮件地址


LABEL <key1>=<value1> <key2>=<value2>... #同MAINTAINER


COPY <src>... <dest>或

COPY ["<src>",..."<dest>"] #src要复制的源文件或目录,支持通配符;dest,目标路径,即正在创建的Image的文件系统路径,建议dest使用绝对路径,否则COPY指定规则以WORKDIR为起始路径;若在路径中有空白字符时使用第2种格式;

文件复制准则:

src必须是build上下文中的路径(相对路径),不能是其父目录中的文件;

如果src是目录,则其内部文件或子目录会被递归复制,但src目录自身不会被复制;

如果指定了多个src,或在src中使用了通配符,则dest必须是一个目录,且必须以/结尾;

如果dest事先不存在,它将会被自动创建,这包括其父目录路径;


ADD <src>...<dest>或

ADD ["<src>",..."<dest>"] #类似COPY,ADD支持使用tar文件和url路径;

准则:

如果src为url且dest不以/结尾,则src指定的文件将被下载并直接被创建了dest;如果dest以/结尾,则文件名url指定的文件将被直接下载并保存为dest/filename;

如果src是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于tar -xf,而通过url获取到的tar文件将不会自动展开;

如果src有多个,或间接或直接使用了通配符,则dest必须是一个以/结尾的目录路径,如果dest不以/结尾,则被视作一个普通文件,src的内容将直接写入到dest;


WORKDIR <dirpath> #用于为Dockfile中所有的RUN|CMD|ENTRYPOINT|COPY|ADD指定设定工作目录;在Dockfile文件中,WORKDIR指令可出现多次,其路径也可为相对路径,不过其是相对此前一个WORKDIR指令指定的路径;另外WORKDIR也可调用由ENV指定定义的变量

WORKDIR /var/log

WORKDIR $STATEPATH


VOLUME <mountpoint>或

VOLUME ["<mountpoint>"] #用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷;如果挂载点目录路径下此前的文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中


EXPOSE <port>[/<protocol>][<port>][/<protocol>]... #protocol用于指定传输层协议,可为tcp或udp,默认为tcp;此项并不是真暴露,要暴露出去在启动容器时加-P

EXPOSE 11211/udp 11211/tcp #EXPOSE指令可一次指定多个端口


ENV <key> <value>或 #这种格式,key之后的所有内容均被视作value的组成部分,因此只能设置1个变量

ENV <key>=<value>... #用于镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令,如ENV|ADD|COPY等所调用,调用格式为$variable_name或$variable_name;这种格式可一次设置多个变量,如果value中包含空格,可用\\转义,也可通过对value加引号进行标识,\\也可用于续行;建议使用此种格式,以便在同一层中完成所有功能

docker run --name tinyweb1 --rm -P -e WEB_SERVER_PACKAGE="nginx-1.15.1" tinyhttpd:v0.1-7 printenv

docker run --name tinyweb1 --rm -P tinyhttpd:v0.1-7 printenv #输出环境变量,

注:

2个阶段,docker build制作目标镜像(在基础镜像上操作),docker run启动镜像为容器;


RUN <COMMAND1>或

RUN ["<executable>","<param1>","<param2>"] #在docker build阶段执行的,常用于编译安装软件;RUN如果有多个会依次运行,而CMD只运行最后一个

第1种格式<command>通常是一个shell命令,且以/bin/sh -c来运行它,这意味着此进程在容器中的PID不为1,不能接收unix信号,因此当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号(15);

第2种格式中的参数是一个json格式的数组,其中executable为要运行的命令,后面的paramN为传递给命令的选项或参数,然而此种格式的命令不会以/bin/sh -c来发起,因此常见的shell操作(如变量替换及通配符替换不会进行),不过,如果要运行的命令依赖于shell特性的话,可将其替换为RUN ["/bin/bash","-c","<executable>","<param1>"]


CMD <command>或

CMD ["<executable>","<param1>","param2">]或

CMD ["<param1>","<param2>"] #类似RUN也可用于运行任何命令或应用程序,不过二者的运行时间点不同,RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动1个容器时;CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止,不过CMD中的命令可以被docker run的命令行选项覆盖;在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效;

前2种语法意义同RUN;

第3种用于为ENTRYPOINT指令提供默认参数,前提CMD和ENTRYPOINT都定义了;


注:

#command #占据当前shell终端,shell的子进程

#command & #依赖父进程(启动它的shell),若父进程退出此命令运行的程序也会退出

#nohup command & #直接推到init进程下

#exec command #exec会取代init,当前shell退出


ENTRYPOINT <command>或

ENTRYPOINT ["<executable","<param1>","<param2>"] #类似CMD,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序;与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,且这些命令行参数会被当作参数传递给ENTRYPOINT指定的程序,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序

docker run传入的命令参数会覆盖CMD指令的内容,且附加到ENTRYPOINT命令最后作为其参数使用;

Dockerfile文件中也可存在多个ENTRYPOINT指令,但仅有最后一个会生效;

json数组中要使用双引号;


USER <UID>|<UserName> #指定运行镜像时的或运行Dockerfile中任何RUN|CMD|ENTRYPOINT指定的程序时的用户名或UID,默认容器的运行身份是root,注意UID可以是任意数字,但实践中必须为/etc/passwd中某用户的有效UID,否则docker run命令将运行失败


HEALTHCHECK NONE #disable any healthcheck inherited from the base image

HEALTHCHECK [OPTIONS] CMD command #check container health by running a command inside the container

options:

--interval=DURATION #default:30s

--timeout=DURATION #default:30s

--start-period=DURATION #default:0s

--reties=N #default:3

0 #success

1 #unhealthy

2 #reserved

HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1


SHELL ["executable","parameters"] #the default shell on Linux is ["/bin/sh","-c"],仅在用的不是/bin/sh才需要改


STOPSIGNAL signal #默认15,可改为9


ARG <name>[=<default>] #在docker build时传变量;区别于ENV,ENV定义的变量在build时只能使用Dockerfile中定义的,不能在命令行下用build传入

docker build --build-arg author="" -t myweb1 ./


ONBUILD <INSTRUCTION> #用于在Dockerfile中定义一个触发器

Dockerfile用于build镜像文件,此镜像文件也可作为base image被另一个Dockerfile用作FROM指令的参数,并以之构建新的镜像文件;在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会触发创建其base image的Dockerfile文件中的ONBUILD指令定义的触发器;

尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令;

使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,如ruby:2.0-onbuild;

在ONBUILD指令中使用ADD或COPY(局域网中的文件或url中的文件)时应格外小心,因为新构建过程的上下文中在缺少指定的源文件时会失败;


例:

mkdir img1

cd img1

vim DockerFile #定义此文件要惜字如金,因为每1条命令都会有新的层次,层次太多影响性能

#Description: test image

FROM busybox:latest

MAINTAINER "Magedu <magedu@mageduc.om"

# LABEL maintainer=""

ENV DOC_ROOT=/data/web/html/ \\

WEB_SERVER_PACKAGE="nginx-1.15.2"

COPY index.html $DOC_ROOT:-/data/web/html/

COPY yum.repos.d /etc/yum.repos.d/

# ADD http://nginx.org/download/nginx-1.15.2.tar.gz /usr/local/src/

WORKDIR /usr/local/

#ADD nginx-1.15.2.tar.gz /usr/local/src/

ADD $WEB_SERVER_PACKAGE.tar.gz ./src/

#ADD nginx-1.15.2.tar.gz ./src/

VOLUME /data/mysql/

EXPOSE 80/tcp

RUN cd /usr/local/src && \\

tar xf nginx-1.15.2.tar.gz


docker build -t tinyhttpd:v0.1-1 ./ #docker build -t tinyhttpd:v0.1-2 ./

docker image ls

docker run --name tinyweb1 --rm tinyhttpd:v0.1-1 cat /data/web/html/index.html #验证,执行完后会退出并删除容器;

ls /etc/yum.repos.d/;

ls /usr/local/src/;

mount;sleep 60;docker inspect tinyweb1查看Mounts ;


cp -r /etc/yum.repos.d/ ./ #当前目录在img1/


docker run --name tinyweb1 --rm -P tinyhttpd:v0.1-6 /bin/httpd -f -h /data/web/html/ #不加-P不会暴露端口给宿主机

docker port tinyweb1


例:

mkdir img2

cd img2/

vim Dockerfile

FROM busybox

LABEL maintainer="Magedu <magedu@magedu.com>" app="httpd"

ENV WEB_DOC_ROOT="/data/web/html/"

RUN mkdir $WEB_DOC_ROOT && \\

echo busybox httpd server > $WEB_DIOC_ROOT/index.html

#CMD /bin/httpd -f -h $WEB_DOC_ROOT

#CMD ["/bin/httpd","-f","-h $WEB_DOC_ROOT"]

#CMD [“/bin/bash”,"-c","/bin/httpd","-f","-h $WEB_DOC_ROOT"]

#CMD [“/bin/bash”,"-c","/bin/httpd","-f","-h /data/web/html/"]

#ENTRYPOINT /bin/httpd -f -h $WEB_DOC_ROOT #docker run中的ls /data/web/html被当作参数放到/bin/httpd -f -h $WEB_DOC_ROOT的后面

CMD ["/bin/httpd","-f","-h $WEB_DOC_ROOT"]

ENTRYPOINT ["/bin/sh","-c"] #docker run中的"ls /data"会覆盖CMD中的


docker build -t tinyhttpd:v0.2-1 ./ #v0.2-2|v0.2-3

docker image inspect tinyhttpd:v0.2-1 #Cmd段

docker run --name tinyweb2 --it --rm -P tinyhttpd:v0.2-1 #加-it没用,默认运行的是httpd -f -h

docker exec -it tinyweb2 /bin/sh #httpd的PID为1,可接收unix信号,可用docker stop停掉

printenv


例:

docker image ls

cd img3

vim Dockerfile

FROM nginx:1.14-alpine

ARG author="magedu <magedu@magedu.com>"

LABEL maintainer=$author

ENV NGX_DOC_ROOT="/data/web/html"

ADD index.html $NGX_DOC_ROOT #vim index.html

ADD entrypoint.sh /bin/

EXPOSE 80/tcp

HEALTHCHECK --start-period=5s CMD wget -O - -q http://IP:-0.0.0.0:$PORT:-80

ONBUILD ADD http://test.com/index.html /usr/local/src/

CMD ["/usr/sbin/nginx","-g","daemon off;"] #-g表示global,docker run --name nginx1 -it --rm nginx:1.14-alpine /bin/sh,which nginx

ENTRYPOINT ["/bin/entrypoint.sh"]


vim entrypoint.sh #chmod +x entrypoint.sh

#!/bin/sh

#

cat > /etc/nginx/conf.d/www.conf << EOF

server

server_name $HOSTNAME;

listen $IP:-0.0.0.0:$PORT:-80

root $NGX_DOC_ROOT:-/usr/share/nginx/html;

EOF

exec "$@" #$@表示脚本的所有参数,exec表示替换当前进程为init


docker build -t myweb:v0.3-1 ./

docker run --name myweb1 --rm -P myweb:v0.3-1

docker exec -it myweb1 /bin/sh

cat /etc/nginx/conf.d/www.conf

netstat -tnl

wget -O - -q 89443f2d6adf

docker run --name myweb1 --rm -P -e "PORT=8080" myweb:v0.3-6


docker build --build-arg author="pony pony@qq.com" -t myweb:v0.3-10 ./

docker image inspect myweb:v0.3-10 #查看Label

以上是关于docker学习笔记4-dockerfile的主要内容,如果未能解决你的问题,请参考以下文章

docker-4-Dockerfile配置文件详解

docker-4 Dockerfile的使用

Docker容器高级篇

docker的数据管理镜像dockerfile创建

公司要新招美女跟我学docker,你来吗?

Docker 学习笔记 Docker 基础操作实,Docker仓库数据卷,网络基础学习