一、Docker存储
1、Docker存储驱动
1、Docker存储驱动与联合文件系统
• 联合文件系统(UnionFS)是一种为Linux、FreeBSD和NetBSD操作系统设计的,将其他文件系统合并到一个联合挂载点的文件系统。
• Docker引擎可以使用联合文件系统的多种变体
◇ AUFS
◇ OverlayFS
◇ Btrfs
◇ BFS
◇ DeviceMapper
• 联合文件系统实际上是由存储驱动实现的,相应的存储驱动有aufs、overlay、overlay2、devicemapper、btrfs、zfs、vfs等。
2、选择Docker存储驱动的总体原则(了解即可)
• 在最常用的场合使用具有最佳整体性能和稳定性的存储驱动。
• 如果内核支持多个存储驱动,则Docker会提供要使用的存储驱动的优先级列表。
• 优先使用Linux发行版默认的存储驱动。
• 一些存储驱动要求使用特定格式的底层文件系统,这可能会限制选择。
• 选择存储驱动还要取决于工作负载的特征和所需的稳定性级别。
3、主流的Docker存储驱动
• 对于所有当前支持的Linux发行版,overlay2存储驱动是首选。 CentOS和RHEL的最新版本现在已经支持overlay2存储驱动,并将overlay2作为推荐的存储驱动。
• 对于Docker 18.06或更早的版本,aufs存储驱动是首选。
• devicemapper存储驱动用于生产环境时需要配置为direct-lvm模式。
• btrfs和zfs存储驱动对底层文件系统(backing filesystem)有用。
• vfs存储驱动用于测试,适合那些没有“写时拷贝”的文件系统。
• 存储驱动的选择可能受到Docker版本、操作系统内核和发行版本的限制。
4、Docker版本所支持的存储驱动
• Docker引擎企业版和Docker EE
◇ 对于Docker引擎企业版和Docker EE来说,支持存储驱动的决定性资源是产品兼容性矩阵。建议用户迁移到overlay2存储驱动。
• Docker CE
◇ 对于Docker CE来说,只有部分配置被测试过,并且操作系统的内核不可能支持每个存储驱动。
◇ 最佳配置是使用带有支持overlay2存储驱动的内核的现代Linux发行版,并且对于大量的工作负载要使用Docker卷写入,而不是将数据写入容器的可写层。
• Docker for Mac和Docker for Windows
◇ 这两个版本的Docker仅用于开发,而不能用于生产环境,不支持定义存储驱动。
5、Docker存储驱动所支持的底层文件系统
6、选择存储驱动需考虑的其他事项
• 适合工作负载
◇ aufs、overlay和overlay2存储驱动的所有操作都在文件级而不是块级,能更有效地使用内存,但容器的可写层可能在写入繁重的工作负载中变得相当大。
◇ 块级存储驱动(如devicemapper、btrfs和zfs存储驱动)在写入繁重的工作负载时表现得更好。
◇ 写入大量的小数据,或有很多层的容器,或深层文件系统,overlay存储驱动比overlay2存储驱动性能更好。
◇ btrfs和zfs存储驱动需要更多内存。
◇ zfs存储驱动是高密度工作负载(如PaaS)的理想选择。
• 共享存储系统
◇ 多数情况下Docker可以在SAN、NAS、硬件RAID或其他共享存储系统上工作,但Docker并没有与它们紧密集成。
◇ 每个Docker存储驱动都基于Linux文件系统或卷管理器。
• 稳定性
◇ overlay2、aufs、overlay和devicemapper存储驱动的稳定性更高。
• 测试工作负载
◇ 在不同的存储驱动上运行工作负载时,可以测试Docker的性能。
2、Docker存储的挂载类型
1、Docker卷与存储驱动
• 默认在容器中创建的所有文件保存在可写的容器层中,这类存储的问题如下。
◇ 此类存储只在容器的生命周期内存在,会随着容器的删除而被删除。
◇ 如果主机上的其他进程需要访问容器中的数据,则很难从容器中获取数据。
◇ 容器的可写层与运行容器的主机紧密耦合,无法轻松地将数据转移到其他地方。
▪ 耦合:紧密切合,不可分割
▪ 解耦:降低耦合度,更容易移植
▪ 模块化:自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。
▪ 微服务:将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。
◇ 写入容器的可写层需要Docker存储驱动来管理文件系统。
• 卷有助于解决这些问题。
◇ 卷本质上是Docker主机文件系统中的目录或文件,能够直接被挂载到容器的文件系统中。
◇ 对卷的读写操作会绕过存储驱动,并以本地主机的速度运行。
2、 Docker卷与存储驱动的关系
3、选择合适的挂载类型
4、卷
• 卷存储在主机文件系统中,在Linux主机上默认就是/var/lib/docker/volumes目录。
• 可以以命名或匿名方式挂载卷。
• 卷由Docker创建并管理。
• 作为Docker容器或服务中持久化数据的首选方式,卷适合以下应用场合。
◇ 在多个正在运行的容器之间共享数据。
◇ 当Docker主机不能保证具有特定的目录结构时,卷有助于将Docker主机的配置与容器运行时解耦。
◇ 当需要将容器的数据存储到远程主机或云时。
◇ 当需要在两个Docker主机之间备份、恢复或迁移数据时,卷是更好的选择。
3、使用Docker卷
1、卷的优势(相比绑定挂载)
• 卷比绑定挂载更容易备份和迁移。
• 可以通过Docker命令行或Docker API对卷进行管理。
• 卷在Linux容器和Windows容器中都可以工作。
• 在多个容器之间共享时,卷更为安全。
• 卷驱动支持在远程主机或云端存储卷,加密卷内容,以及增加其他功能。
• 新卷的内容可以由容器预填充。
2、-v选项(本章重点)
• 作用:将主机的卷挂载到容器中。
• 语法:docker run -v [host-src:]container-dest[:<options>]
◇ 对于命名卷,第1个字段是卷的名称,并且在指定主机上是唯一的;对于匿名卷,第1个字段被省略。
◇ 第2个字段container-dest是容器中被挂载的文件或目录的路径,必须采用绝对路径的形式。
◇ 第3个字段是可选的,是一个逗号分隔的选项列表。
◇ 可将同一卷挂载到多个容器上,以实现容器间的数据共享。
• 示例:将卷myvol2挂载到容器中的/app目录。
docker run -d --name devtest -v myvol2:/app nginx:latest
3、创建和管理卷:docker volume
通过docker volume命令在任何容器之外单独创建和管理卷
示例: 创建卷: docker volume create my-vol
列出当前的卷: docker volume ls
查看卷的详细信息: docker volume inspect my-vol
删除卷: docker volume rm my-vol
二、DockerFile
1、YAML文件 语法特点(语法结构)
• YAML大小写敏感。
• 使用缩进表示层级关系。
• 缩进只能使用空格,不能使用TAB,不要求空格个数,但相同层级应当左对齐。
• 使用符号“#”表示注释,YAML中只有行注释。
• 字符串可以不用引号标注。
• 每个“:”与它后面所跟的参数之间都需要有一个空格。
• YAML文件可以由一或多个文档组成,并用“---”符号分隔。
• 部分关键字有驼峰式写法
2、DockerFile相关基本知识
1、DockerFile简要
• Dockerfile是由一系列指令和参数构成的脚本文件,每一条指令构建一层。
• 镜像的定制实际上就是定制每一层所要添加的配置和文件。
• Dockerfile的格式:
◇ # Comment
◇ INSTRUCTION arguments
• INSTRUCTION表示指令,不区分大小写,建议大写。arguments表示指令的参数。
• Dockerfile文件必须以FROM指令开头,定义构建镜像的基础镜像。
• 以“#”符号开头的行都将被视为注释。
• Docker可使用解析器指令escape设置转义字符。
2、通过DockerFile构建镜像
• 构建上下文:docker build
◇ 上下文是由文件路径(本地文件系统上的目录)或一个URL(Git仓库位置)定义的一组文件。
◇ 构建上下文以递归方式处理,本地路径包括其中的任何子目录,URL包括仓库及其子模块。
• 镜像构建过程
◇ 构建过程中一开始将整个上下文递归地发送给守护进程。
◇ 要使用构建上下文中的文件,Dockerfile引用由指令(如COPY)指定的文件。
◇ 使用-f选项显式指定Dockerfile文件的具体位置:
▪ docker build -f /path/to/a/Dockerfile .
◇ 可以指定构建成功之后要保存的新镜像的仓库名和标签:
◇ docker build -t shykes/myapp .
◇ Docker守护进程逐一运行Dockerfile中的指令,每条指令被独立执行并创建一个新镜像。
◇ 只要有可能,Docker将重用过程中的中间镜像(缓存),以加速构建过程。
• 构建上下文示例
(1)为构建上下文创建一个目录并切换到该目录。
mkdir myproject && cd myproject
(2)将内容“hello”写入一个名为hello的文本文件。
echo "hello" > hello
(3)创建一个Dockerfile并在其中运行cat命令。
echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > Dockerfile
(4)从构建上下文(.)构建镜像。
docker build -t helloapp:v1 .
3、DockerFile常用指令
1、 FROM指令——设置基础镜像
◇ FROM指令的用法有以下3种格式:
▪ FROM <image> [AS <name>]
▪ FROM <image>[:<tag>] [AS <name>]
▪ FROM <image>[@<digest>] [AS <name>]
◇ FROM指令为后续指令设置基础镜像,可以在同一个Dockerfile文件中多次出现,以创建多个镜像层。
◇ image参数指定任何有效的镜像,特别是可以从公有仓库拉取的镜像。
◇ FROM指令AS <name>是可选的,可以用来对此构建阶段指定一个名称。
◇ tag或digest的值是可选的。如果省略其中任何一个,构建器将默认使用latest。
2、 RUN指令——运行命令
◇ RUN指令的用法有以下两种格式:
▪ RUN <command>
▪ RUN ["executable", "param1", "param2"]
◇ 第1种是shell格式,命令在shell环境中运行。
◇ 第2种是exec格式,不会启动shell环境。
◇ RUN指令将在当前镜像顶部的新层中执行命令,并提交结果。
◇ exec格式可以避免shell字符串转换。
◇ shell格式中的默认shell可以使用SHELL命令来更改。
◇ 第一个字段为命令,后面为参数或选项
3、 CMD指令——指定容器启动时默认执行的命令
◇ CMD指令的用法有以下3种格式:
▪ CMD ["executable","param1","param2"]
▪ CMD ["param1","param2"]
▪ CMD command param1 param2
◇ 第1种是首选的exec格式。
◇ 第2种提供给ENTRYPOINT指令的默认参数。
◇ 第3种是shell格式。
◇ 一个Dockerfile文件中若有多个CMD指令,则只有最后一个CMD有效。
◇ CMD指令的主要目的是为运行中的容器提供默认值。
4、 LABEL指令——向镜像添加标记(元数据)
◇ LABEL指令的语法格式如下:
▪ LABEL <key>=<value> <key>=<value> <key>=<value> ...
◇ 每个标记(元数据)以键值对的形式表示。要在其中包含空格,应使用引号和反斜杠。
◇ 一个镜像可以有多个标记。可以将多个标记合并到单个LABEL指令中以减少层数。
◇ 基础镜像或父镜像中包含的标记会被镜像继承。
◇ 类似inode,不存储镜像实际内容,常用于多容器管理。
5、EXPOSE指令——声明容器运行时侦听的网络端口
◇ EXPOSE指令的语法格式如下:
▪ EXPOSE <port> [<port>...]
◇ EXPOSE指令通知Docker容器在运行时侦听指定的网络端口。
◇ EXPOSE指令不会发布该端口,只是起到声明作用。
6、ENV指令——指定环境变量
◇ ENV指令的用法有以下两种格式:
▪ ENV <key> <value>
▪ ENV <key>=<value> ...
◇ ENV指令以键值对的形式定义环境变量。
◇ 第1种格式将单个变量设置为一个值。
◇ 第2种格式允许一次设置多个变量,可以使用等号(=),而第1种形式不使用。
7、COPY指令——将源文件复制到容器
◇ COPY指令的用法有以下两种格式:
▪ COPY [--chown=<user>:<group>] <src>... <dest>
▪ COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
◇ --chown选项只能用于构建Linux容器,不能在Windows容器上工作。
◇ COPY指令将指定的源路径(由<src>参数指定)的文件或目录复制到容器文件系统中指定的目的路径(由<dest>参数指定)。
◇ 可以指定多个源路径,但文件和目录的路径将被视为相对于构建上下文的源路径。
◇ 目的路径是绝对路径,或者是相对于工作目录(由WORKDIR指令指定)路径。
8、 ADD指令——将源文件复制到容器
◇ ADD指令的用法有以下两种格式:
▪ ADD [--chown=<user>:<group>] <src>... <dest>
▪ ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
◇ 它与COPY指令的功能基本相同,不同之处有两点:
▪ 源可以使用URL指定。
▪ 归档文件在复制过程中能够被自动解压缩。
◇ 如果源是具有可识别的压缩格式的本地Tar归档文件,则将其解包为目录。来自远程URL的资源不会被解压缩。
9、ENTRYPOINT指令——配置容器的默认入口
◇ ENTRYPOINT指令的用法有以下两种格式:
▪ ENTRYPOINT ["executable", "param1", "param2"]
▪ ENTRYPOINT command param1 param2
◇ 第1种是首选的exec格式。
◇ 第2种是shell格式。
◇ ENTRYPOINT指令用于配置容器运行的可执行文件。
◇ 在Dockerfile中只有最后一个ENTRYPOINT指令会起作用。
10、 VOLUME指令——创建挂载点
◇ VOLUME指令的语法格式如下:
▪ VOLUME ["/data"]
◇ VOLUME指令创建具有指定名称的挂载点,并将其标记为从本机主机或其他容器保留外部挂载的卷。
11、 WORKDIR指令——配置工作目录
◇ WORKDIR指令的语法格式如下:
▪ WORKDIR /path/to/workdir
◇ WORKDIR指令为Dockerfile中的任何RUN、CMD、ENTRYPOINT、COPY和ADD指令设置工作目录。
◇ 可以在一个Dockerfile文件中多次使用该指令。
12、 USER指令——设置运行镜像时使用的用户名
◇ USER指令的用法有以下两种格式:
▪ USER <user>[:<group>] or
▪ USER <UID>[:<GID>]
◇ USER指令设置运行镜像时使用的用户名(或UID)和可选的用户组(或GID)。
◇ 用户没有主要组时,镜像(或下一条指令)将以root组的身份运行。
13、 ARG指令——定义变量
◇ ARG指令的语法格式如下:
▪ ARG <name>[=<default value>]
◇ ARG指令定义一个变量(可称为构建时变量。
◇ 一个Dockerfile文件可以包括一个或多个ARG指令。
14、 SHELL指令——指定命令的shell格式
◇ SHELL指令的语法格式如下:
▪ SHELL ["executable", "parameters"]
◇ SHELL指令用于指定命令的shell格式以覆盖默认的shell。
◇ SHELL指令可以多次出现。每个SHELL指令覆盖所有先前的SHELL指令,并影响所有后续指令。
15、 Dockerfile指令的exec和shell格式
◇ RUN、CMD和ENTRYPOINT指令都会用到这两种格式。
◇ exec格式的一般用法如下:
▪ <指令> ["executable", "param1", "param2", ...]
◇ 采用exec格式要使用环境变量。
◇ shell 格式一般用法如下:
▪ <指令> <command>
◇ 指令执行时shell格式底层会调用/bin/sh -c 来执行命令。
◇ CMD和ENTRYPOINT指令首选exec格式。RUN指令则选择两种格式都可以。
◇ exec格式作为JSON数组解析,必须在单词之外使用双引号而不是单引号。
16、 RUN、CMD和ENTRYPOINT指令的区别和联系
◇ RUN指令执行命令并创建新的镜像层,经常用于安装应用程序和软件包。
◇ Dockerfile应该至少为CMD或ENTRYPOINT指令指定一个命令。
◇ CMD指令的主要目的是为运行容器提供默认值,即默认执行的命令及其参数,但当运行带有替代参数的容器时,CMD指令将被覆盖。
◇ 当使用容器作为可执行文件时,应该定义ENTRYPOINT指令。
◇ 可以考虑使用ENTRYPOINT指令的exec格式设置默认命令和参数,然后使用CMD指令的任何格式设置额外的默认值。
◇ ENTRYPOINT指令中的参数始终会被使用,而CMD指令的额外参数可以在容器启动时被动态替换掉。
4、构建使用DockerFile实例
实例:基于couchbase/centos7-systemd创建dockerfile,要求能使用nginx访问自己创建的测试网站。
下面是构建流程:
1、建立一个目录用作DockerFile的上下文并准备所需文件:
[root@goodwood ~]# mkdir nginx-dockerfile && cd nginx-dockerfile [root@goodwood nginx-dockerfile]# vim index.html test
2、编写DockerFile:
[root@goodwood nginx-dockerfile]# vim Dockerfile FROM couchbase/centos7-systemd RUN yum install -y nginx EXPOSE 80 COPY index.html /usr/share/nginx/html/ ENTRYPOINT ["nginx","-g","daemon off;"]
3、使用Docker build命令构建镜像
[root@goodwood nginx-dockerfile]# docker build -t nginx-on-centos . [+] Building 70.9s (8/8) FINISHED => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 431B 0.0s => [internal] load metadata for docker.io/couchbase/centos7-systemd:latest 0.0s => CACHED [1/3] FROM docker.io/couchbase/centos7-systemd 0.0s => [internal] load build context 0.0s => => transferring context: 102B 0.0s => [2/3] RUN yum install -y nginx 70.0s => [3/3] COPY index.html /usr/share/nginx/html/ 0.0s => exporting to image 0.9s => => exporting layers 0.9s => => writing image sha256:d44ad31867249c63c136b038aaef7af69c29f8f86bab5c3412f6010c173 0.0s => => naming to docker.io/library/nginx-on-centos 0.0s [root@goodwood nginx-dockerfile]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx-on-centos latest d44ad3186724 7 seconds ago 688MB
4、基于该镜像启动容器并进行测试
[root@goodwood nginx-dockerfile]# docker run -itd -P nginx-on-centos 22d4b5c1d6a2759eb45bd0e3441071a541e1cdd4b30713f2741645b491d34641 [root@goodwood nginx-dockerfile]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 22d4b5c1d6a2 nginx-on-centos "nginx -g 'daemon of…" 3 seconds ago Up 2 seconds 0.0.0.0:32768->80/tcp, :::32768->80/tcp angry_sammet
5、尝试访问对应ip地址
三、相关面试题
1、简述Linux文件系统和Docker文件系统?
Linux 文件系统: 由 bootfs 和 rootfs 组成, bootfs 主要包含 bootloader 和 kernel , bootloader 主要是引 导加载kernel ,当 kernel 被加载到内存之后 bootfs 就被卸载掉了。 rootfs 包含的就是典型 linux 系统 中/dev,/proc,/bin,/etc 等标准目录。Docker 文件系统: Docker 容器是建立在 Aufs 分层文件系统基础上的, Aufs 支持将不同的目录挂载到同 一个虚拟文件系统下,并实现一种layer 的概念。 Aufs 将挂载到同一虚拟文件系统下的多个目录分别设置 成read-only , read-write 以及 whiteout-able 权限。 docker 镜像中每一层文件系统都是 read-only 。
2、 简述 Docker 网络模式?Docker使用 Linux 的 Namespaces 技术来进行资源隔离,其中 Network Namespace 实现隔离网络。一个Network Namespace 提供了一份独立隔离的网络环境,包括网卡、路由、 Iptable 规则等, Docker网络有如下四种模式:host 模式: host 模式下容器将不会获得独立的 Network Namespace ,该模式下与宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,不会配置独有的 IP 等,而是使用宿主机的 IP和端口。container 模式: Container 网络模式是 Docker 中一种较为特别的网络的模式,处于 container 模 式下的 Docker 容器会共享其他容器的网络环境,因此,两个或以上的容器之间不存在网络隔离, 而配置container 模式的容器又与宿主机以及除此之外其他的容器存在网络隔离。none 模式: none 模式下, Docker 容器拥有自己的 Network Namespace ,但是,并不为 Docker 容 器进行任何网络配置和构造任何网络环境。Docker 容器采用了 none 网络模式,那么容器内部就只 能使用loopback 网络设备,不会再有其他的网络资源。 Docker Container 的 none 网络模式意味着 不给该容器创建任何网络环境,容器只能使用127.0.0.1 的本机网络。bridge 模式: bridge 模式是 Docker 默认的网络设置,此模式会为每一个容器分配 NetworkNamespace 、设置 IP 等,并将该宿主机上的 Docker 容器连接到一个虚拟网桥上。
3、 简述 Docker 跨主机通信的网络实现方式?docker 跨主机通信按原理可通过以下三种方式实现:· 直接路由方式:直接在不同宿主机之间添加静态路由;· 桥接方式(如pipework ): 通过静态指定容器 IP 为宿主机 IP 同一个网络的形式,即可实现。· Overlay 隧道方式: 使用 overlay 网络实现, Overlay 网络指在现有网络层之上叠加的虚拟化技术, 实现应用在网络上的承载,并能与其他网络业务分离,并且以基于IP 的网络技术为主,如 flannel 、 ovs+gre。