Docker笔记 —— Dockerfile

Dockerfile

Dockerfile是包含一些命令的文本文档,这些命令可以用来描述自定义镜像的信息,并通过docker build命令来构建自定义的镜像

Docker通过读取Dockerfile中的指令,按步自动生成镜像

docker build -t 机构/镜像名<:tags> dockerfile目录
# 命令后面有3部分
# 一是机构id,或者个人id,指明这个dockerfile是由谁维护的
# 二是镜像名
# 三是dockerfile目录,指定docker build对哪个目录下的dockerfile进行构建

例子:

# dockerfile 中的内容
FROM tomcat # 设定基准镜像,随后在该镜像中进行扩展
MAINTAINER yogurtzzz # 说明该镜像的拥有者
WORKDIR /usr/local/tomcat/webapps #本质相当于cd ,切换工作目录
# 即该镜像用来生成容器后,默认工作目录改为上面指定的路径
# WORKDIR 还有个特性,若指定的目录不存在,则会自动创建之
ADD docker-web ./docker-web 
# 第一个docker-web指的是在dockerfile同级目录下的docker-web文件夹
# 第二个docker-web指的是容器里webapps/下的docker-web目录
# ADD是复制的意思,会复制宿主机目录下所有文件到容器目录

下面是学习dockerfile的目录

在这里插入图片描述

其中dockerfile文件的内容就是上面的内容

index.html中是

<h1>Hello,Docker File</h1>

下面开始构建镜像

# 指定个人名称yogurtzz
# 指定自定义镜像名称my_tomcat:1.0
# 指定dockerfile目录,使用相对路径,用.指定为当前目录
docker build -t yogurtzzz/my_tomcat:1.0 .

在这里插入图片描述

可以看到,每一个Step都对应dockerfile中的一个命令。但是每个Step下面的字符串是什么意思呢?这涉及到镜像中的分层。在用dockerfile构建镜像时,会创建临时容器,用于镜像构建。在每一个Step时,docker会创建一个临时容器。这可以根据上面的日志看出来Running in xxxxx . Removing intermediate container xxx

构建完成后,查看一下本地的docker镜像

在这里插入图片描述

可见成功构建了自定义的镜像

然后用该镜像创建并启动一个容器

在这里插入图片描述

放行7000端口后,在本机电脑访问

在这里插入图片描述

镜像分层

对于一个镜像来说,镜像构建完成后,镜像文件就是只读的,无法再被修改。

而容器内部的文件是可读可写的

dockerfile构建镜像时,采用2个机制

  1. 分层
    以FROM的镜像为基准,在基准镜像的基础上,一层一层地添东西

  2. 系统快照

    系统快照以docker临时容器的方式进行,每进行一步,都会创建一个docker临时容器,对当前状态进行存档

    => 这样做的好处,临时容器是可以复用的

示例
先创建一个dockerfile

FROM centos
RUN ["echo","yogurt1"]
RUN ["echo","yogurt2"]
RUN ["echo","yogurt3"]
RUN ["echo","yogurt4"]

开始构建
在这里插入图片描述

修改dockerfile,只改动最后一行,然后docker build

FROM centos
RUN ["echo","yogurt1"]
RUN ["echo","yogurt2"]
RUN ["echo","yogurt3"]
RUN ["echo","yogurt777"]

在这里插入图片描述

第二次构建镜像时,会发现没做改动的前几步命令,都是using cache,表明复用了先前构建镜像时生成的临时容器,只有最后一步,做了改动的命令,是新起了一个临时容器去做的处理。

Dockerfile基础命令

FROM

基于基准镜像来进行构建

FROM centos # 基于centos:latest
FROM scratch # 不依赖于任何基准镜像,从0构建。此种情况比较罕见
FROM tomcat:8
MAINTAINER

说明性信息,该dockerfile是由哪个个人或机构维护的

MAINTAINER yogurtzzz
LABEL

描述性信息

# 方便阅读和维护
LABEL version="1.0"
LABEL description="yogurtLearning"
WORKDIR

设置工作目录

若目录不存在,会自动创建目录,相当于linux的cd命令

尽量使用绝对路径

ADD

从宿主机复制文件到docker容器中,ADD支持解压缩

# 意思是,把宿主机的hello文件,复制到容器根目录
ADD hello /
# 会把test.tar.gz压缩包添加到根目录,并解压
ADD test.tar.gz /
# ADD还可以用来抓取远程文件,类似于linux的wget,会将远程url的资源文件,下载到容器的指定位置
ENV

设置容器中的环境常量

ENV JAVA_HOME /usr/local/openjdk8
# 在dockerfile后面的命令中,可以用${JAVA_HOME}直接引用
RUN ${JAVA_HOME}/bin/java -jar test.jar

Dockerfile中的运行指令

RUN,ENTRYPOINT,CMD 3个命令都可以用来执行指令,但是他们执行的时机不同,并且CMD和ENTRYPOINT略有差别。

RUN

docker build,构建镜像时,执行命令。可以用RUN在构建镜像时对资源进行调整,一旦镜像构建完毕,这个镜像就是只读的了,不能再次被修改。所以涉及到对镜像的修改,只能用RUN命令。

# RUN语法
RUN yum install -y tree # Shell命令格式
RUN ["yum","install","-y","tree"] # Exec命令格式
# 推荐使用Exec格式来执行命令

Shell命令格式和Exec命令格式执行RUN的区别:主要在于是否创建子进程

在这里插入图片描述
在这里插入图片描述

ENTRYPOINT

docker run,容器启动时,执行命令

若在dockerfile中写了多行ENTRYPOINT,则只有最后一行ENTRYPOINT会被执行

CMD

CMD用于设置默认执行命令,与ENTRYPOINT非常相似。书写多行CMD,也只有最后一行会被执行

CMD和ENTRYPOINT的区别在于,ENTRYPOINT一定会被执行,而CMD不一定会被执行。什么意思呢?就是CMD命令可以在执行docker run命令时,被传入的参数给覆盖。

示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lTNzQfA7-1590076250606)(C:\Users\Vergi\AppData\Roaming\Typora\typora-user-images\1590071763188.png)]

可以看到RUN命令在构建时被执行了,image building....输出在了控制台,而CMD命令没有输出到控制台,说明RUN命令是在docker build,构建镜像时执行的。

现在用docker run启动容器,能看到CMD的echo,说明CMD命令是在启动容器时执行的。

在这里插入图片描述

但是,若在启动容器时,在最后添加了自定义的cmd命令参数,则dockerfile中编写的CMD的echo,会被覆盖。这就是前面说的,dockerfile中的CMD命令,不一定会被执行。

CMD可以从外界传参,外界不传参时,就用dockerfile中CMD的默认命令。
下面由于运行docker run时,传入了ls,则dockerfile中的CMD命令echo container starting...就会被ls覆盖掉
在这里插入图片描述
下面是ENTRYPOINT和CMD命令的结合使用

# dockerfile 内容
FROM centos
ENTRYPOINT ["ps"]
CMD ["-ef"]
# end
# 用这个dockerfile构建的镜像
# 在启动容器时,若直接用如下命令
docker run 镜像名
# 则会执行ps -ef

# 若使用如下命令
docker run 镜像名 -aux
# 则会执行ps -aux

CMD命令构建的镜像,可以在创建容器时,进行灵活配置

综合案例:用Redis源码编译并构建Redis镜像

下载redis源代码,并用c++进行编译安装

# dockerfile
FROM centos
RUN yum install -y gcc gcc-c++ net-tools make #安装一些组件
WORKDIR /usr/local #切换目录
ADD redis-4.0.14.tar.gz .#将redis源码压缩包复制到当前目录,并解压
WORKDIR /usr/local/redis-4.0.14/src # 切换目录
RUN make && make install # 执行编译
WORKDIR /usr/local/redis-4.0.14 # 切换目录
ADD redis-7000.conf . # 复制redis配置文件
EXPOSE 7000 # 将容器的7000端口对外暴露
CMD redis-server redis-7000.conf # 使用对应配置文件启动redis

先用wget拉取redis源码包

wget http://download.redis.io/releases/redis-4.0.14.tar.gz

再创建一个redis-7000.conf的配置文件

vi redis-7000.conf

配置文件中只有一行内容,指定了redis的端口为7000

port 7000

看一下准备好的文件目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Kr6B7G2-1590076250609)(C:\Users\Vergi\AppData\Roaming\Typora\typora-user-images\1590073512050.png)]

docker build -t yogurt/redis:1.0 .

# 构建完成后,运行容器
docker run -p 7000:7000 yogurt/redis:1.0

成功启动redis
在这里插入图片描述

实际使用时,redis官方已经提供了现成的docker镜像,可以直接使用,非常简单,只要下面的命令就能立马跑一个redis起来

docker pull redis
docker run redis

猜你喜欢

转载自blog.csdn.net/vcj1009784814/article/details/106270402