首页 > 其他 > 详细

6. Dockerfile详解

时间:2020-05-31 10:32:07      阅读:46      评论:0      收藏:0      [点我收藏+]

一、Dockerfile 概念

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。

1.1. Dockerfile的体系结构

先来看一下我们最常用的centos的Dockerfile

在hub.docker.com中所有centos

FROM scratch
MAINTAINER The CentOS Project <cloud-ops@centos.org>
ADD c68-docker.tar.xz /
LABEL name="CentOS Base Image"     vendor="CentOS"     license="GPLv2"     build-date="2016-06-02"

# Default command
CMD ["/bin/bash"]

含义:

FROM scratch
这里引用了一个父镜像. 我们通常在使用tomcat或者jdk的时候, 他的父类镜像是centos. 而centos的父类镜像是scratch, scratch是所有镜像的基础镜像


MAINTAINER The CentOS Project <cloud-ops@centos.org>
MAINTAINER是备注的意思, 这是哪个团队,哪个人写的


ADD c68-docker.tar.xz /
这个参数后面讲解

LABEL name="CentOS Base Image"     vendor="CentOS"     license="GPLv2"     build-date="2016-06-02"
LABEL顾名思义,就是描述的含义


# Default command
CMD ["/bin/bash"]
表示运行/bin/bash. 
我们通常在运行docker run -it lxl/centos的时候, 有时候加/bin/bash,有时候不加. 那么什么时候加, 什么时候不加呢? 
其实加和不加都是可以的....因为这里已经给我们自动加了/bin/bash, 如果不加就是用默认的, 如果加了, 就相当于有两个/bin/bash, 他只会执行一个

 

 1.2. dockerfile的编写规则

1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数

2. 指令按照顺序, 从上到下, 一条指令就是一层

3. #表示注释

4. 每条指令都会创建一个新的镜像层, 并对镜像进行提交

 

1.3 docker执行dockerfile的流程

1. docker从基础镜像运行一个容器

2. 执行一条指令并对容器修改

3. 执行类似docker commit的操作提交一个新的镜像层

4. docker在基于刚提交的镜像运行一个新容器

5. 执行dockerfile中的下一条指令直到所指令都执行完成

 

1.4 dockerfile的保留字指令

  1. FROM: 

    基础镜像, 当前镜像是基于哪一个镜像

     

  2. MAINTAINER:

    镜像维护者的姓名, 邮箱地址

     

  3. RUN:

    容器构建时需要运行的命令

     

  4. EXPOSE:

    当前容器对外暴露的端口号

     

  5. WORKDIR:

    指定在创建容器后, 终端默认登录进来的工作目录, 一个落脚点
    没有指定, 进入到容器的根目录

     

  6. ENV:

    用来在构建镜像的过程中设置环境变量
    这个环境你变量可以在后续的任务Run指令中使用, 这就如同在命令前面指定了环境变量前缀一样, 也可以在其他指令中直接使用这些环境变量.

    举个例子:
    ENV MY_PATH /usr/home
    WORKDIR $MY_PATH

    这就是说, 进入到容器以后, 直接进入的工作目录不是根目录, 而是/usr/home

     

  7. ADD & COPY

    ADD 和 COPY一起说
    他俩都有将宿主机指定目录下的文件拷贝到到镜像中的含义.
    ADD比COPY更强大. 
    ADD有拷贝并解压的含义

    例如:
    ADD c68-docker.tar.xz /
    这个含义就是, 拷贝到根目录, 并进行解压

     

  8. VOLUME:

    容器数据卷, 用于数据保存和持久化

     

  9. CMD:

    指定一个容器启动时需要运行的命令, 
    Dockerfile中可以有多个CMD命令, 但只有最后一个生效, CMD会被docker run之后的参数替代

     

  10. ENTRYPOINT:

    和CMD有相同之处
    指定一个容器启动时要运行的命令
    
    ENTRYPOINT的目的和CMD一样, 都是在绑定容器启动程序及参数.
    不同之处是, ENTRYPOINT 不会被docker run后面的参数代替, 而是追加

     

  11. ONBUILD:

    子镜像继承自父类镜像以后, 父镜像的onbuild就会被触发, 
    这就相当于一个触发器, 满足一定条件的时候触发



技术分享图片

 

 

 二. 手动编写Dockerfile

1. 新建文件, 创建一个DockerFile

文件名叫Dockerfile. 固定叫法

文件内容如下

From ubuntu
MAINTAINER lxl
CMD echo hello docker

 

2. 构建Dockerfile

docker build -t demo-docker .

domo-docker: 是生成的新的docker镜像的名字. 

. 表示的是文件生成在当前目录

 

构建的时候, 首先会判断基础镜像是否存在, 如果不存在, 则下载

技术分享图片

 

 

3. 查看构建好的镜像

docker image demo-docker

技术分享图片

 

 我们看到生产了一个64.2M的镜像. 版本定义了一个最新版本

4. 运行镜像

docker run demo-docker

技术分享图片

 运行镜像, 打印输出hello docker

 

以上我们就自己定义了一个dockerfile,并运行起来了.

 三. 第二个简单的Dockerfile

FROM ubuntu
MAINTAINER lxl
RUN apt-get update
RUN apt-get install -y nginx
COPY index.html /var/www/html
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
EXPOSE 80

这是一个比较复杂的dockerfile, 那么每句话的含义是什么呢?

  • FROM ubuntu: 新镜像依赖的基础镜像是ubuntu
  • MAINTAINER xbf: 作者是lxl
  • RUN apt-get update : 表示先更新基础镜像
  • RUN apt-get install -y nginx: 表示运行并安装nginx镜像,
    • -y参数的含义, 不要询问我是否安装nginx
  • COPY index.html /var/www/html: 表示复制一个镜像index.html 到容器的/var/www/html目录下
    • ["/usr/sbin/nginx", "-g", "daemon off;"] 这个数组表示, 最终将这个数组一空格分隔, 作为一个命令执行. daemon off, 表示让nginx不要再后台执行
  • ENTRYPOINT 数组: 这是一个启动命令. 容器如何启动? 和第一个demo中的CMD作用是类似的. 不同的是, 这里的参数是一个数组
  • EXPOSE 80: 指定服务启动时占用容器的端口号是80

 

1. 创建一个文件, 并写入上面的内容

2. 创建一个文件index.html 在里面写入简单的内容

3. 构建一个镜像

docker build -t demo-docker2 .

运行结果

技术分享图片

 

 

4. 运行构建好的镜像

docker run -d -p 80:80 demo-docker2

技术分享图片

 

 容器就启动起来了

 

5. 使用curl来测试一下网页

curl http://localhost:80/

技术分享图片

 四. Dockerfile语法总结

命令 用途
FROM 依赖的基础镜像
RUN  执行命令, 比如运行应用
ADD/COPY 都是添加文件, COPY可以添加文件或目录,ADD还可以添加远程文件
CMD/ENTRYPOINT 执行命令, 容器的启动入口
EXPOSE     暴露端口, 如果是一个web服务器,可以是用EXPOSE来暴露端口
WORKDIR  指定路径
MAINTAINER   维护者, 当前dockerfile由谁来维护
EVN 设定环境变量
USER 指定用户
VOLUME   mount point挂载点

 

 四. dockerfile镜像分层

dockerfile中每一行都产生一个新层

技术分享图片

 

 每一层都会有一个对应的编号. 

 

已经存在image中的层, 这些层都是只读的. 他已经被创建好了. 

当容器运行image以后, 会生成一个新层, 这一层叫容器层, 这一层是可读可写的. 保证容器是可以改变的 

 

分层的好处: 层在不同的镜像中是可以复用的. 这样就避免了重复造轮子 

五. Volume 

提供独立于容器之外的持久化存储 

我们之前有过操作, 修改nginx的文件index.html. 这个修改是不会被容器保存的, 需要docker commit生成一个新的镜像. 修改才能生效. 

volume提供了一个方便的可持久化存储的方式. 比如我们的数据库数据. 应该是被持久化的. Volume可以做这件事, 并且Volume可以提供给容器和容器之间共享数据

 volume的使用方式:

1.  启动的时候挂载容器目录到默认的本地docker目录

docker run -d --name nginx -v /usr/share/nginx/html nginx

-v /usr/share/nginx/html: 表示挂载的目录地址
-d: 表示在后台执行
--name nginx: 容器的名字叫nginx

什么意思呢? 就是说nginx对应文件会有一个经常变动的文件夹, 我们将这个文件夹挂载到本地. 

那么挂载到了本地的什么位置呢?

通过docker inspect nginx 可以查看. inspect是检查的意思

技术分享图片

 

 

 这里有很多容器启动的信息. 

其中有一个是和挂载目录有关的信息. 我们来看一下

技术分享图片

 

 

 就是这个. 

 "Source": "/var/lib/docker/volumes/1ef20c41a9fe15914ad240e968da9f3cf3998822a96ba6cdb8361fdd14b17052/_data",
 "Destination": "/usr/share/nginx/html",

Source: 表示的是本地目录

Destination: 表示容器中需要挂载的目录

我们进入目录修改文件的内容,试一试

执行命令: 

cd /var/lib/docker/volumes/1ef20c41a9fe15914ad240e968da9f3cf3998822a96ba6cdb8361fdd14b17052/_data

 

技术分享图片

 

 

 看到目录找不到. 为什么找不到呢? 因为我们是在mac上, mac上还有一层虚拟机, 在虚拟机里面运行的docker. 所以我们要进入到那个主机里面去. 

那么如何登录到docker虚拟机中呢?

  • 执行:screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
    • 注意:当你的docker version是18.06.0-ce-mac70 (26399)采用上面的指令,如果不是这个version请使用screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
  • 然后你会看到一个新的命令行,请按下enter,此时你就在docker虚拟机中了。
  • 此时cd /var/lib/docker/volumes/1ef20c41a9fe15914ad240e968da9f3cf3998822a96ba6cdb8361fdd14b17052/_data
    就是nginx这个volume的

 技术分享图片

 

 接下来, 修改index.html文件的内容

 技术分享图片

 

结果: 看一看nginx有没有变化

 

进入到docker容器里面查看,文件内容是否有改变 

 使用命令docker exec进入容器

 

docker exec -it nginx /bin/bash


docker exec : 表示进入到docker容器
nginx:表示的是容器的名字

技术分享图片

 

 查看挂载目录/usr/share/nginx/html下的index.html是否改成我们本地的内容

技术分享图片

 

 修改成功!

2. 本地制定目录挂载到容器目录

docker run -p 88:80 -d -v $PWD/html:/usr/share/nginx/html nginx
  • 这里的$PWD表示的是一个环境变量, 始终指向的是当前目录
  • $PWD/html:/usr/share/nginx/html  表示将当前目录下的html目录, 挂载到容器的/usr/share/nginx/html的目录下 

  此时你修改当前目录下的html/index.html文件, 对应的容器中的index.html目录也会修改 

  技术分享图片

3. 仅有数据的容器挂载, 实现容器间的数据共享 

这里有两步操作: 

第一步: 将一个仅有数据的容器挂载到本地的制定目录

docker create -v $PWD/data:/var/mydata --name data_container ubuntu

创建一个容器
$PWD/data:/var/mydata   将容器的/var/mydata目录挂载到$PWD/data目录下

--name data_container  给创建的容器起个名字

ubuntu 创建容器的镜像是ubuntu

技术分享图片

 

 这就创建好了一个容器

第二步: 新建一个容器, 让其目录挂载到上面创建的仅有数据的容器 

docker run -it --volumes-from data_container ununtu /bin/bash

运行容器,
--volumes-from data_container  表示从一个容器指定挂载的目录
-it  /bin/bash : 指打开容器运行

我们进入容器, 然后创建一个文件

技术分享图片

 

 我们创建了一个aaa.txt, 然后我们退出容器, 进入data目录, 看到也有一个aaa.txt

技术分享图片

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

文件

6. Dockerfile详解

原文:https://www.cnblogs.com/ITPower/p/12677533.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!