Docker容器技术(四)——Dockerfile详解

1. 编写一个简单的Dockerfile

创建一个Dockerfile

创建Dockerfile尽量不要在根目录,因为默认在构建的时候会把当前目录所有数据发送到docker引擎,如果在根目录,会把跟目录所有数据发送给docker引擎进行构建。

mkdir docker
cd docker/
echo hello > testfile
vim Dockerfile
FROM busybox
COPY testfile /

COPY参数要求要拷贝的文件必须在当前目录,不能写绝对路径,只能是相对路径。拷贝的目的地可以是目录或文件
在这里插入图片描述

构建镜像

docker build -t demo:v1 .

在这里插入图片描述

查看镜像的分层结构

docker history demo:v1

在这里插入图片描述

通过Dockerfile来构建镜像,可以清除的看到每一层都干了什么,有安全审计的功能。而通过docker commit 构建新镜像的方式则无法知晓具体在镜像内做了什么操作,无法对镜像进行审计,存在安全隐患。

镜像的缓存特性

构建镜像中有相同的镜像层时,会使用缓存来加速构建。

vim Dockerfile
FROM busybox
COPY testfile /
RUN echo helloword > file1
docker build -t demo:v2 .
docker history demo:v1
docker history demo:v2

在这里插入图片描述

vim Dockerfile
FROM busybox
COPY testfile /
RUN echo helloword > file1
RUN echo haha > file2
docker build -t demo:v2 .
docker history demo:v1
docker history demo:v2

在这里插入图片描述

在这里插入图片描述

docker run -it --rm demo:v1
docker run -it --rm demo:v2
docker run -it --rm demo:v3

在这里插入图片描述
Dockerfile最佳实践

在这里插入图片描述
通过Dockerfile构建镜像,有很好的审计功能,比较安全,推荐使用,不推荐使用docker commit 来直接构建

2. Dockerfile详解

2.1 dockerfile常用指令

  • FROM:指定base镜像,如果本地不存在会从远程仓库下载。
  • MAINTAINER:设置镜像的作者,比如用户邮箱等。
  • COPY:把文件从build context复制到镜像
    支持两种形式:COPY src dest 和 COPY [“src”, “dest”]
    src必须指定build context中的文件或目录
  • ADD:用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
    ADD html.tar /var/www
    ADD http://ip/html.tar /var/www
  • ENV:设置环境变量,变量可以被后续的指令使用:
    ENV HOSTNAME server1.example.com
  • EXPOSE:如果容器中运行应用服务,可以把服务端口暴露出去:
    EXPOSE 80
  • VOLUME:申明数据卷,通常指定的是应用的数据挂载点:
    VOLUME ["/var/www/html"]
  • WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
  • RUN:在容器中运行命令并创建新的镜像层,常用于安装软件包:
    RUN yum install -y vim
  • CMD 与 ENTRYPOINT
    这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
    docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
    Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。

2.2 dockerfile使用案例

ADD自动解压文件

ADD:用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www

step1 放一个nginx的压缩包在/root/docker下
在这里插入图片描述

step2 修改Dockerfile:

vim Dockerfile 
FROM busybox
ADD nginx-1.16.1.tar.gz /

在这里插入图片描述

step3 构建镜像:

docker build -t demo:v4 .

在这里插入图片描述

ADD的用法与COPY类似,但不同的是它可以将文件自动解压到dest

step4 测试:

docker run -it -rm demo:v4

在这里插入图片描述

ENV定义环境变量

ENV:设置环境变量,变量可以被后续的指令使用:
ENV HOSTNAME sevrer1.example.com

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV hostname server1		#定义环境变量hostname为server1
ADD nginx-1.16.1.tar.gz /	

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v5 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v5

env查看到环境变量信息:

在这里插入图片描述

VOLUME声明数据卷,在封装应用容器时常用

VOLUME:申明数据卷,通常指定的是应用的数据挂载点:
VOLUME ["/var/www/html"]

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
ADD nginx-1.16.1.tar.gz /
VOLUME ["/data"]

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v6 .

在这里插入图片描述

step3 查看镜像的创建历史:

docker history demo:v6

在这里插入图片描述

step4 进入容器,创建文件:

docker run -it demo:v6

cd /data/
touch file1

按ctrl+p+q退出

在这里插入图片描述

step5 查看demov6的挂载信息:

docker ps						#找出对应的容器ID
docker inspect 5231e1ce76fe

在这里插入图片描述

在这里插入图片描述

docker引擎在启动容器时发现定义了卷,会自动生成一个卷。而docker引擎在启动容器时,自动在本地为它创建了这个目录,并且挂载在容器内,可以让容器读取到本地的数据目录。

step6 进入目录,查看到刚刚创建的文件file:

cd /var/lib/docker/volumes/ebe2016c773e0ae350be1f6dc9c6463bb71009bcb6a8b8355e58509c8741f2fe/_data
ls

在这里插入图片描述

step7 在此目录下修改文件,容器中的文件同样会被修改:

echo hello > file1
echo hello >> file1
echo hello >> file1
echo hello >> file1
echo hello >> file1
echo hello >> file1
cat file1
docker ps
docker attach 5231e1ce76fe

/data # ls
/data # cat file1 
/data # rm -f file1 
按ctrl+p+q退出

在这里插入图片描述

step8 释放数据卷:

docker ps
docker rm -f 52			#删除容器(此处使用容器ID的简写,因为只有一个52开头的ID)
docker volume ls		#显示所有数据卷
docker volume prune		#释放数据卷(删除没有被容器使用的卷)

在这里插入图片描述

在这里插入图片描述

WORKDIR设置镜像中的当前工作目录

WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v7 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v7

在这里插入图片描述

我们可以发现,进入容器时就默认在/nginx这个目录下,而将nginx的包解压在了这个目录中。
这个目录之前并不存在,是WORKDIR自动创建的

CMD与ENTRYPOINT

这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。

CMD:

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
CMD echo helloword

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v8 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v8
docker run -it --rm demo:v8 sh	#命令被覆盖

在这里插入图片描述

ENTRYPOINT:

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
ENTRYPOINT echo helloword

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v9 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v9
docker run -it --rm demo:v9 sh	#命令没有被覆盖

在这里插入图片描述

2.3 shell和exec格式的区别

区别一

shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而exec格式不会

shell格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV name redhat
ENTRYPOINT echo $hostname

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v10 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v10

在这里插入图片描述

可以看到变量$hostname的值被输出了

exec格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV name redhat
ENTRYPOINT ["/bin/echo","$hostname"]

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v11 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v11

在这里插入图片描述

可以看到变量$hostname没有被解析,而是直接输出了$hostname

所以exec格式需要改写:

vim Dockerfile 

FROM busybox
ENV name redhat
ENTRYPOINT ["/bin/sh","-c","echo $hostname"]

在这里插入图片描述

再次测试,变量就被解析了

在这里插入图片描述

区别二

exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时,ENTRYPOINT会忽略任何CMD或者docker run提供的参数

exec格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v12 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v12
docker run -it --rm demo:v12 linux		#输出的world变为linux
docker run -it --rm demo:v12 redhat		#输出的world变为redhat

在这里插入图片描述

shell格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENTRYPOINT echo hello
CMD echo world

在这里插入图片描述

step2 构建镜像:

docker build -t demo:v13 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v13
docker run -it --rm demo:v13 linux		#输出的world变为linux
docker run -it --rm demo:v13 redhat		#输出的world变为redhat

在这里插入图片描述
可以看到,在shell格式时,ENTRYPOINT会忽略任何CMD提供的参数

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值