Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
Dockerfile 示例
#基础镜像 FROM ubuntu #添加文件到镜像 COPY ./GatewayWorkerNew /www/server/GatewayWorker COPY start.sh /home/start.sh COPY php.ini /www/server/php/74/etc/php.ini #构架镜像时运行命理 RUN chmod +x /home/start.sh && \ rm -f /install.sh #为镜像添加匿名卷 VOLUME ["/www/server/mysqlData","/www/backup","/www/wwwlogs","/www/wwwroot"] #暴露端口 EXPOSE 80 443 9706 888 #容器启动命令 CMD ["sh","/home/start.sh"]
FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。
这里我使用 ubuntu 作为基础镜像,你可以指定版本号比如 FROM ubuntu:20.04 不指定时默认使用 latest 版本,基础镜像是必须指定的。而 FROM 就是指定 基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。
COPY 的文件/目录复制到镜像内
格式 COPY [–chown=<user>:<group>] <源路径>… <目标路径>
拷贝文件到指定目录
COPY start.sh /home/start.sh
拷贝目录
COPY ./GatewayWorkerNew /www/server/GatewayWorker
在使用该指令的时候还可以加上 –chown=<user>:<group> 选项来改变文件的所属用户及所属组。
COPY –chown=55:mygroup files* /mydir/
COPY –chown=bin files* /mydir/
COPY –chown=1 files* /mydir/
COPY –chown=10:11 files* /mydir/
RUN 在定制镜像时是执行的命令行
在使用RUN命理时应该把命令整合为一条,Dockerfile 中每一个指令都会建立一层镜像,所以应该把命令使用 && 链接为一条命令。
RUN chmod +x /home/start.sh && \
rm -f /install.sh
VOLUME 定义匿名卷
容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中了,防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
VOLUME [“/www/server/mysqlData”,”/www/backup”,”/www/wwwlogs”,”/www/wwwroot”]
VOLUME /www/server/mysqlData
以上两种写法都是可以的
EXPOSE 暴露端口
格式为:EXPOSE <端口1> [<端口2>…]
EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。
在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
CMD 容器启动命令
Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。
提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念。
一些初学者将 CMD 写为:
CMD service nginx start
然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。
这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ “sh”, “-c”, “service nginx start”],因此主进程实际上是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:
CMD [“nginx”, “-g”, “daemon off;”]
使用dockerfile文件构造镜像
docker build –pull –rm -f dockerfile -t ubuntu:20220809
build参数说明
–build-arg=[] :设置镜像创建时的变量;
–cpu-shares :设置 cpu 使用权重;
–cpu-period :限制 CPU CFS周期;
–cpu-quota :限制 CPU CFS配额;
–cpuset-cpus :指定使用的CPU id;
–cpuset-mems :指定使用的内存 id;
–disable-content-trust :忽略校验,默认开启;
-f :指定要使用的Dockerfile路径;
–force-rm :设置镜像过程中删除中间容器;
–isolation :使用容器隔离技术;
–label=[] :设置镜像使用的元数据;
-m :设置内存最大值;
–memory-swap :设置Swap的最大值为内存+swap,”-1″表示不限swap;
–no-cache :创建镜像的过程不使用缓存;
–pull :尝试去更新镜像的新版本;
–quiet, -q :安静模式,成功后只输出镜像 ID;
–rm :设置镜像成功后删除中间容器;
–shm-size :设置/dev/shm的大小,默认值是64M;
–ulimit :Ulimit配置。
–squash :将 Dockerfile 中所有的操作压缩为一层。
–tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
–network: 默认 default。在构建期间设置RUN指令的网络模式
Dockerfile 指令表
指令 | 使用方法 | 描述 |
FROM | FROM ubuntu | 指定基础镜像 |
RUN | RUN apt update -y | 构架镜像时执行的命令 |
COPY | COPY /dir /mydir/ COPY –chown=www:nginx /dir /mydir/ | 文件/目录复制到镜像内 可指定文件的所属用户及所属组 |
ADD | ADD mydata.tar.gz /data COPY /dir /mydir/ COPY –chown=www:nginx /dir /mydir/ | ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。 |
ENV | ENV VERSION=1.0 DEBUG=on \ NAME=”Happy Feet” |
ENV 设置环境变量 |
ARG | ARG DOCKER_USERNAME=ubuntu
FROM ${DOCKER_USERNAME}/22.04 上面使用过以后就失效了,如果后面还需要使用需要再次指定 |
ARG 构建参数 构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的 |
VOLUME | VOLUME [“/data1″,”/data2”] | 容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据 |
EXPOSE | EXPOSE 80 443 | EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。 要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。 |
WORKDIR | WORKDIR /home | 指定工作目录,以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。 |
USER | USER redis | 指定当前用户,改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。 |
LABEL | LABEL org.opencontainers.image.authors=”chunblog” | LABEL 指令用来给镜像以键值对的形式添加一些元数据(metadata) |
SHELL | SHELL [“/bin/sh”, “-c”] | SHELL 指令可以指定 RUN ENTRYPOINT CMD 指令的 shell |
ONBUILD | ONBUILD RUN [ “npm”, “install” ] | ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。 |
HEALTHCHECK | HEALTHCHECK [选项] CMD <命令> | 健康检查 |
ENTRYPOINT | ENTRYPOINT [ “ping”, “114.114.114.114” ] | ENTRYPOINT 入口点,ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 –entrypoint 来指定。 |
CMD | CMD [“bash”] | 容器启动命令 |