docker-dockerfile书写

前言

ARG

功能

○ ARG指令类似ENV,定义了一个变量;区别于ENV:用户可以在构建时

docker build --build-arg = 进行对变量的修改;ENV不可以;

○ 如果用户指定了未在Dockerfile中定义的构建参数,那么构建输出警告。

• 语法

Shell

ARG [=]

• 注意事项
○ Dockerfile可以包含一个或多个ARG指令
○ ARG支持指定默认值

○ 使用范围:定义之后才能使用,定义之前为空,如下面的案例,执行命令

docker build --build-arg username=what_user .第二行计算结果为

some_user ,不是我们指定的build-arg中的参数值what_user

Shell

FROM busybox

USER ${username:-some_user}

ARG username

USER $username
○ ENV和ARG同时存在,ENV会覆盖ARG

Shell

FROM ubuntu

ARG CONT_IMG_VER

ENV CONT_IMG_VER=v1.0.0

RUN echo C O N T I M G V E R 执行下面指令输出 v 1.0.0 P l a i n t e x t d o c k e r b u i l d − − b u i l d − a r g C O N T I M G V E R = v 2.0.1. 我们可以优化写法为 S h e l l F R O M u b u n t u A R G C O N T I M G V E R E N V C O N T I M G V E R = CONT_IMG_VER 执行下面指令输出v1.0.0 Plaintext docker build --build-arg CONT_IMG_VER=v2.0.1 . 我们可以优化写法为 Shell FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER= CONTIMGVER执行下面指令输出v1.0.0Plaintextdockerbuild−−build−argCONTIMGVER=v2.0.1.我们可以优化写法为ShellFROMubuntuARGCONTIMGVERENVCONTIMGVER={CONT_IMG_VER:-v1.0.0}

RUN echo $CONT_IMG_VER

○ 系统内置了一些ARG变量

▪ HTTP_PROXY ▪ http_proxy

▪ HTTPS_PROXY ▪ https_proxy

▪ FTP_PROXY ▪ ftp_proxy

▪ NO_PROXY ▪ no_proxy

▪ ALL_PROXY ▪ all_proxy

• 样例

Shell

FROM busybox

ARG user1=someuser

ARG buildno=1

ARG就是在dockerfile中生效,ENV在镜像启动容器之后仍然生效

bash 复制代码
ARG SYSVERSION=22.04
FROM ubuntu:${SYSVERSION} as buildstage1
MAINTAINRR bit [email protected]
LABEL version="1.0" desc="create by bit"
ENV MYROOTDIR=/data/web/html/
COPY --chown=news:news ./index.html ${MYROOTDIR}
ENV MYTEST=1
WROKDIR /data/src
ADD https://nginx.org/download/nginx-1.24.0.tar.gz .
WORKDIR /data/src2
ADD ./nginx-1.24.0.tar.gz .
RUN cd /data/src && tar zxvf nginx-1.24.0.tar.gz
RUN ["sh","-c","mkdir -p /data/src3 && cd /data/src3/ && touch new.txt"]
RUN apt-get update -y && apt install -y build-essential libpcre3 libpcre3-dev zlib1g-dev 
RUN cd /data/src/nginx-1.24.0 \ 
&& ./configure  \ 
&& make && make install 
COPY ./nginx.conf /usr/local/nginx/conf/
EXPOSE 80/tcp
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

docker build -t myweb:v2.1 .

docker images myweb

docker inspect myweb:v2.1

docker build -t myweb:v2.2 --build-arg SYSVERSION=22.10 .

docker run -d --name myweb2.2test myweb:v2.2

我们看出,ARG是可以在build的时候修改的

docker exec -it myweb2.2test bash

cat /etc/release

VOLUME

• 功能

○ 用于在image中创建一个挂载点目录 ,生成的是匿名的存储卷

○ 通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成

的。

• 语法

Shell

VOLUME

VOLUME [""]

• 参数

○ mountpoint:挂载点目录

○ 注意事项

▪ 如果挂载点目录路径下此前有文件存在,docker run命令会在卷挂载完

成后将此前的所有文件复制到新挂载的卷中

其实VOLUME指令只是起到了声明了容器中的目录作为匿名卷,但是并

没有将匿名卷绑定到宿主机指定目录的功能。

volume 只是指定了一个目录,用以在用户忘记启动时指定**-v参数**也可以

保证容器的正常运行。比如mysql,你不能说用户启动时没有指定-v,然后

删了容器,就把mysql的数据文件都删了,那样生产上是会出大事故的,所

以mysql的dockerfile里面就需要配置volume,这样即使用户没有指定-v,

容器被删后也不会导致数据文件都不在了。还是可以恢复的。

volume 与-v 指令一样,容器被删除以后映射在主机上的文件不会被删除。

如果-v和volume指定了同一个位置,会以-v设定的目录为准,其实

volume 指令的设定的目的就是为了避免用户忘记指定-v的时候导致的数据丢

失,那么如果用户指定了-v,自然而然就不需要volume指定的位置了。

• 样例

Shell

VOLUME ["/data1","/data2"]

bash 复制代码
ARG SYSVERSION=22.04
FROM ubuntu:${SYSVERSION} as buildstage1
MAINTAINRR bit [email protected]
LABEL version="1.0" desc="create by bit"
ENV MYROOTDIR=/data/web/html/
COPY --chown=news:news ./index.html ${MYROOTDIR}
ENV MYTEST=1
WROKDIR /data/src
ADD https://nginx.org/download/nginx-1.24.0.tar.gz .
WORKDIR /data/src2
ADD ./nginx-1.24.0.tar.gz .
RUN cd /data/src && tar zxvf nginx-1.24.0.tar.gz
RUN ["sh","-c","mkdir -p /data/src3 && cd /data/src3/ && touch new.txt"]
RUN apt-get update -y && apt install -y build-essential libpcre3 libpcre3-dev zlib1g-dev 
RUN cd /data/src/nginx-1.24.0 \ 
&& ./configure  \ 
&& make && make install 
COPY ./nginx.conf /usr/local/nginx/conf/
EXPOSE 80/tcp
VOLUME ["/data/"]
#CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

VOLUME ["/data/"]

docker build -t myweb:v2.3 .

docker images myweb

docker run -d --name myweb2.3test myweb:v2.3

docker inspect myweb2.3test

可以看到这里有一个volume的存储卷

名称是随机生成的

source是宿主机的位置

destinaton是容器的位置

我们没有指定存储卷的话,这个就是默认生成的一个匿名存储卷,宿主机位置都是固定的,容器位置由dockerfile指定

docker run -d -v ./:/data1 --name myweb2.3test2 myweb:v2.3

这个就是把当前宿主机目录映射到容器/data1目录

我们来看一下我们的存储卷会不会发生覆盖

docker inspect myweb2.3test2

可以发现存储卷的类型就变为了绑定卷了

源目录就是刚刚run的宿主机目录

目标目录就是我们指定的目录

SHELL

• 功能

• 语法

SHELL指令允许覆盖用于shell命令形式的默认shell。

Linux 上的默认shell是["/bin/sh","-c"],在 Windows上是["cmd","/S",

SHELL指令必须以JSON格式写入Dockerfile。

Shell

SHELL ["executable", "parameters"]

• 参数

○ executable:shell可执行文件的位置

○ parameters:shell执行的参数

○ 注意事项

▪ SHELL指令可以多次出现。

▪ 每个SHELL指令都会覆盖所有先前的SHELL指令,并影响所有后续指

令。

▪ 该SHELL指令在 Windows 上特别有用,因为windows行有两种不同的

shell:cmd 和 powershell

就是把我们docker默认运行的shell覆盖,比如windows的cmd和powershell就是不同的shell,就是更改这个东西,linux上就是bash和sh

mkdir shell

cd shell

vi dockerfile

bash 复制代码
FROM ubuntu:20.04
RUN ls -l / > /test1.txt
SHELL ["/bin/bash","-cvx"]
RUN ls -l / > /test2.txt

SHELL ["/bin/bash","-cvx"]这个是打印bash执行命令时的详细信息

docker build -t shell:v0.1 --no-cache --progress=plain .

--no-cache就是不要使用原来镜像制作的缓存,从第一层开始做镜像,因为缓存中有原来镜像的层

--progress=plain这个是打印构建的动作

我们发现两个RUN ls -l / > /test2.txt显示的内容不一样

说明我们就发生了shell的切换,因为-cvx会把命令的执行过程打印出来,SHELL ["/bin/bash","-cvx"]就是这样的,所以打印的东西要多一点

Linux的两个shell没有什么区别

USER

• 功能

○ 用于指定运行image时的或运行Dockerfile中任何RUN、CMD或

ENTRYPOINT指令定的程序时的用户名或UID

默认情况下,container的运行身份为root用户

• 语法

Shell

USER [:]

USER [:]

• 参数

○ user:用户

○ group:用户组

○ uid:用户id

○ gid:组id

○ 注意事项

▪ 可以为任意数字,但实践中其必须为/etc/passwd中某用户的有效

UID,否则将运行失败

• 样例

Shell

USER docker:docker

mkdir user

cd user

vi dockerfile

bash 复制代码
FROM ubuntu:22.04 as buildbase 
RUN groupadd nginx 
RUN useradd nginx -g nginx 
USER nginx:nginx 
RUN whoami > /tmp/user1.txt 
USER root:root 
RUN groupadd mysql 
RUN useradd mysql -g mysql 
USER mysql:mysql 
RUN whoami > /tmp/user2.txt

RUN groupadd nginx 这个是·添加了一个nginx的用户组

RUN useradd nginx -g nginx 是添加了一个nginx的用户,然后指定这个用户的组为nginx组

USER nginx:nginx 就是切换到nginx的用户,和nginxx的组上

RUN whoami > /tmp/user1.txt 这个就是打印你是谁

USER root:root 切换到root账号

因为nginx并没有添加用户的权限,所以我们要切到root ,再来添加一个mysql的用户,和mysql的用户组

然后又切换到mysql的用户与用户组

docker build -t user:v0.1 .

docker run -it --rm user:v0.1 bash

cat /tmp/user1.txt

cat /tmp/user2.txt

我们来可以看出文件的属性也是属于对应的用户与用户组了

HEALTHCHECK

功能
○ HEALTHCHECK指令告诉Docker如何测试容器以检查它是否仍在工作。
○ 即使服务器进程仍在运行,这也可以检测出陷入无限循环且无法处理新连接
的Web服务器等情况。 所以健康与运行不是一个东西

• 语法

Shell

HEALTHCHECK [OPTIONS] CMD command (check container health by

running a command inside the container)

HEALTHCHECK NONE (disable any healthcheck inherited from the base

image)

• 参数

○ OPTIONS 选项有:

▪ --interval=DURATION (default: 30s):每隔多长时间探测一次,默认30-- timeout= DURATION (default: 30s):服务响应超时时长,默认30秒 --start-period= DURATION (default: 0s):服务启动多久后开始探测,默

认0秒

▪ --retries=N (default: 3):认为检测失败几次为宕机,默认3次

○ 返回值

▪ 0:容器成功是健康的,随时可以使用

▪ 1:不健康的容器无法正常工作

▪ 2:保留不使用此退出代码

mkdir healthcheck

cd healthcheck

vi Dockerfile

bash 复制代码
FROM nginx:1.24.0
HEALTHCHECK --interval=5m --timeout=3s \ 
CMD curl -f http://localhost/ || exit 1 

CMD curl -f http://localhost/ || exit 1 就是curl一下我们的本机,看健不健康,不健康的话,就退出,检测周期是五秒钟,

docker build -t hc:v1.0 .

docker run -d --name hc1 hc:v1.0

docker ps

docker ps

可以看出一开始在检查,然后就检查OK了

bash 复制代码
FROM nginx:1.24.0
HEALTHCHECK --interval=5m --timeout=3s \ 
CMD curl -f http://localhost:8989/ || exit 1 

docker build -t hc:v2.0 .

docker run -d --name hc2 hc:v2.0

docker ps

docker ps

我们发现它会进行多次检查,如果多次检查都不健康,就结束了

ONBUILD

• 功能

○ 用于在Dockerfile中定义一个触发器

○ 以该Dockerfile中的作为基础镜像由FROM指令在build过程中被执行时,

将会"触发"创建其base image的Dockerfile文件中的ONBUILD指令定义的触

发器

• 语法

Shell

ONBUILD

• 参数:

○ INSTRUCTION:dockerfile的一条指令

• 样例

Shell

ONBUILD ADD . /app/src

就是以当前镜像作为基础镜像,然后去构造其他镜像时触发dockerfile中的一些指令

vi dockerfile

bash 复制代码
ARG SYSVERSION=22.04
FROM ubuntu:${SYSVERSION} as buildstage1
MAINTAINRR bit [email protected]
LABEL version="1.0" desc="create by bit"
ENV MYROOTDIR=/data/web/html/
COPY --chown=news:news ./index.html ${MYROOTDIR}
ENV MYTEST=1
WROKDIR /data/src
ADD https://nginx.org/download/nginx-1.24.0.tar.gz .
WORKDIR /data/src2
ADD ./nginx-1.24.0.tar.gz .
RUN cd /data/src && tar zxvf nginx-1.24.0.tar.gz
RUN ["sh","-c","mkdir -p /data/src3 && cd /data/src3/ && touch new.txt"]
RUN apt-get update -y && apt install -y build-essential libpcre3 libpcre3-dev zlib1g-dev 
RUN cd /data/src/nginx-1.24.0 \ 
&& ./configure  \ 
&& make && make install 
COPY ./nginx.conf /usr/local/nginx/conf/
EXPOSE 80/tcp
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
ONBUILD RUN echo "create by bit version" > /tmp/version/txt
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

docker build -t myweb:v2.4 .

mkdir ob

cd ob/

vi Dockerfile

bash 复制代码
FROM myweb:v2.4
RUN echo "hello" > /test.txt

docker build -t ob:v0.1 .

本来我们的dockerfile只有两步,但是出现了多的一步,就是ONBUILD,就是触发了ONBUILD

docker run -d --name ob1 ob:v0.1

docker exec -it ob1 bash

cd /tmp

cat version.txt

STOPSIGNAL

• 功能
○ STOPSIGNAL指令设置将发送到容器的系统调用信号。

此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,

或者SIGNAME格式的信号名,例如SIGKILL。

• 语法

Shell

STOPSIGNAL signal

• 参数

○ STOPSIGNAL指令设置将发送到容器出口的系统调用信号。 此信号可以是与

内核的系统调用表中的位置匹配的有效无符号数,例如9,或者SIGNAME格式

的信号名,例如SIGKILL。常见的信号如下:

代号

名称

1

SIGHUP

内容

启动被终止的程序,可让该进程重新读取自己的配置文

件,类似重新启动。

2

SIGINT

相当于用键盘输入 [ctrl]-c 来中断一个程序的进行。

9

SIGKILL

代表强制中断一个程序的进行,如果该程序进行到一半,

那么尚未完成的部分可能会有"半产品"产生,类似 vim会

有 .filename.swp 保留下来。

15

SIGTERM

以正常的方式来终止该程序。由于是正常的终止,所以后

续的动作会将他完成。不过,如果该程序已经发生问题,

就是无法使用正常的方法终止时,输入这个 signal 也是没

有用的。

19 SIGSTOP 相当于用键盘输入 [ctrl]-z 来暂停一个程序的进行。

mkdir stopsig

cd stopsig

vi Dockerfile

bash 复制代码
FROM nginx:1.24.0
STOPSIGNAL 9

docker build -t stopsig:v1.0

docker images stopsig

docker run -d --name stopsig1 stopsig:v1.0

docker logs -f stopsig1

这个设置了STOPSIGNAL的

用来监控日志信息

然后就是再来一个shell

docker run -d --name nostopsig nginx:1.24.0

docker logs -f nostopsig

这个是正常的,没有设置STOPSIGNAL

再开一个shell

docker stop nostopsig

这个就是优雅的退出了

docker stop stopsig1

这个就是在运行的时候,什么都不打印就退出了,因为它的信号变成了9,9就是这样的

docker build

功能

docker build 命令用于使用 Dockerfile 创建镜像。

• 语法

Shell

docker build [OPTIONS] PATH | URL | -

-指的是标准流,url指的是远端的地址, path指的是本地的路径,就是本地的上下文,就是构建镜像的dockerfile地址

• 关键参数

○ --build-arg=[] :设置镜像创建时的变量;

○ -f :指定要使用的Dockerfile路径; ---》默认找dockerfile,这个可以找非dockerfile名字的文件了

○ --label=[] :设置镜像使用的元数据;

○ --no-cache :创建镜像的过程不使用缓存; 、、发现前几层一样,就可以使用缓存了

○ --pull :尝试去更新镜像的新版本;、、就算本地有,也会去拉取

○ --quiet, -q :安静模式,成功后只输出镜像 ID; 不会打印日志了

○ --tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构

建中为一个镜像设置多个标签。

○ --network: 默认 default。在构建期间设置RUN指令的网络模式 ,可以指定走host网络

bash 复制代码
FROM ubuntu 22.04
ARG AGINX_VERSION=1.24.0
ADD http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz .
RUN echo "v1.0" > ./version.txt

docker build -t build:v0.5 .

这个我们下的nginx是1.24.0

docker build -t build:v0.6 --build-arg NGINX_VERSION=1.23.4 .

--build-arg就是用来替换dockerfile中ARG的

这个就是动态的制作镜像

mv Dockerfile Dockerfile2

docker build -t build:v0.7 .

不指定文件的话,这个默认找的就是本目录下的名字叫做Dockerfile的文件

所以改名就找不到了

docker build -t build:v0.7 -f ./Dockerfile2 .

-f 就是指定文件了

docker build -t build:v0.8 --label MYTEST=1 -f ./Dockerfile2 .

这个就是添加镜像要使用的源数据

docker inspect build:v0.8

之前运行的时候我们可以ADD的时候看到左边有CACHED,就是使用了缓存的

docker build -t build:v0.9 -f ./Dockerfile2 --no-cache .

这次ADD的时候就没有使用cache了

docker build -t build:v1.0 -f ./Dockerfile2 --no-cache --pull .

这个--pull就是每次都要去镜像源新下载 ubuntu这个镜像

所有很慢,--no-cache --pull 这两个就很慢

docker build -t build:v1.0 -f ./Dockerfile2 -q .

-q就是不打印那些日志了

-t就是给镜像取名和tag

docker build -t build:v1.3 -f ./Dockerfile2 --network host .

这个就是构建网络使用本机的网络,只要本机能上网,那么就没事

为了防止使用缓存我们这样

docker build -t build:v1.3 -f ./Dockerfile2 --no-cache --network host .

因为我们主机能上网,所以我们构建的过程中也能上网,而且不是使用的缓存

Dockerfile 编写优秀实践

善用.dockerignore 文件

使用它可以标记在执行docker build时忽略的路径和文件,避免发送不必要的数据内

容,从而加快整个镜像创建过程。 相当于.gitignore

镜像的多阶段构建

通过多步骤创建,可以将编译和运行等过程分开,保证最终生成的镜像只包括运行应

用所需要的最小化环境。当然,用户也可以通过分别构造编译镜像和运行镜像来达到

类似的结果,但这种方式需要维护多个Dockerfile。

合理使用缓存

如合理使用cache,减少内容目录下的文件,内容不变的指令尽量放在前面,这样可

以尽量复用;

基础镜像尽量使用官方镜像,并选择体积较小镜像

容器的核心是应用,大的平台微服务可能几十上百个。选择过大的父镜像(如Ubuntu

系统镜像)会造成最终生成应用镜像的臃肿,推荐选用瘦身过的应用镜像(如

node:slim),或者较为小巧的系统镜像(如alpine、busybox或debian);

减少镜像层数

如果希望所生成镜像的层数尽量少,则要尽量合并RUN、ADD和COPY指令。通常

情况下,多个RUN指令可以合并为一条RUN指令;如apt get update&&apt install尽

量写到一行

精简镜像用途

尽量让每个镜像的用途都比较集中单一,避免构造大而复杂、多功能的镜像;

减少外部源的干扰

如果确实要从外部引入数据,需要指定持久的地址,并带版本信息等,让他人可以复

用而不出错。

减少不必要的包安装

只安装需要的包,不要安装无用的包,减少镜像体积。

总结

相关推荐
老狼孩111228 分钟前
全分辨率免ROOT懒人精灵-自动化编程思维-设计思路-实战训练
运维·自动化·lua·脚本开发·懒人精灵·全分辨率免root
Forget_855026 分钟前
Linux的例行性工作
linux·运维·服务器
浪遏1 小时前
我的远程实习(四)| Ailln叫我docker部署项目,我顺便填了以前的坑
前端·docker·容器
hellotutu1 小时前
SSH项目负载均衡中的Session一致性解决方案‌
运维·ssh·负载均衡
m0_745364241 小时前
LVS-DR模式配置脚本
linux·运维·服务器·github·lvs
是垚不是土1 小时前
何为DevOps理念?
运维·devops
不知名。。。。。。。。1 小时前
Linux--命令行操作
linux·运维·服务器
爱喝酸奶的桃酥2 小时前
基于网启PXE服务器的批量定制系统平台
运维
老年DBA2 小时前
Linux Namespace(网络命名空间)系列三 --- 使用 Open vSwitch 和 VLAN 标签实现网络隔离
linux·运维·服务器·网络
liyongjun63163 小时前
使用 Docker 18 安装 Eureka:解决新版本 Docker 不支持的问题
docker·容器·eureka·docker compose