文章目录
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个机制
-
分层
以FROM的镜像为基准,在基准镜像的基础上,一层一层地添东西 -
系统快照
系统快照以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
命令时,被传入的参数给覆盖。
示例:
可以看到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
看一下准备好的文件目录
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