基础部分
什么是 Docker ?
Go 语言开发,容器虚拟化技术,C/S 架构,具有隔离、快速、轻便的特点。
Docker结构如下:
- 服务端:接收命令或远程请求,操作镜像或容器
- 客户端:发送命令或者请求到Docker服务端
Docker通过虚拟化技术,解决了开发环境、测试环境、生产环境不一致的问题,让 App 及其运行环境达到“Build,Ship and Run Any APP,Anywhere”(在任何地方构建、发布和运行任何应用程序)的目的,方便做持续集成,并有助于整体发布和扩缩容的容器虚拟化技术。
如何检查 Docker Client 和 Docker Server 的版本?
我们可以使用命令 docker version [options]
来查看docker版本。
如果我们不提供任何选项,则 Docker 会提供有关客户端和服务器的所有版本相关信息。
例如,仅获取服务器版本,使用如下命令:docker version --format '{{.Server.Version}}'
。
Dockerfile、Image 、 Container 和 DockerHub 的关系
- Dockerfile : 用于描述镜像的生成规则。 Dockerfile中的每一条命令,都在Docker镜像中以一个独立镜像层的形式存在。
- Image : 由
Dockerfile
生成,呈现层级结构,每层镜像包含:镜像文件以及镜像json元数据信息。 - Container : Container 是 Image 的动态运行结果。概括而言,就是在 Docker 镜像之上,运行进程。
- DockerHub : 一个镜像托管的服务器,它是 Docker 提供的基于公共云的注册表,用于存储容器的公共镜像,同时提供查找和共享它们。可以通过
docker push
命令将镜像推送到 Docker Hub。类似的还有阿里云镜像服务,统称为 DockerRegistry。
Docker 核心技术
- 通过 Namespace 做环境隔离。
Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。这些资源包括:进程树、网络接口、挂载点以及进程间通信等资源。
在同一个 namespace 下的进程可以感知彼此的变化,而对外界的进程一无所知。这样就可以让容器中的进程产生错觉,认为自己置身于一个独立的系统中,从而达到隔离的目的。
2、通过 Cgroups 做资源限制。
命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离,但是命名空间并不能够为我们提供物理资源上的隔离。如果在同一台机器上运行了多个对彼此以及宿主机器一无所知的容器,这些容器却共同占用了宿主机器的物理资源。
而 Control Groups(简称 CGroups)就是能够隔离宿主机器上的物理资源,例如:CPU、内存、磁盘 I/O 和网络带宽。每一个 CGroup 都是一组被相同的标准和参数限制的进程,不同的 CGroup 之间是有层级关系的,也就是说它们之间可以从父类继承一些用于限制资源使用的标准和参数。
3、基于 rootfs 的文件系统。
Linux 的命名空间和控制组分别解决了不同资源隔离的问题,前者解决了进程、网络以及文件系统的隔离,后者实现了 CPU、内存等资源的隔离,但是在 Docker 中还有另一个非常重要的问题需要解决 - 也就是镜像。Docker 镜像其实本质就是一个压缩包。
联合文件系统(UnionFS)是 Docker 镜像的基础。UnionFS 其实是一种为 Linux 操作系统设计的用于把多个文件系统『联合』到同一个挂载点的文件系统服务。
而 AUFS(Advanced UnionFS)其实就是 UnionFS 的升级版,它能够提供更优秀的性能和效率。AUFS 作为联合文件系统,它能够将不同文件夹中的层联合(Union)到了同一个文件夹中,这些文件夹在 AUFS 中称作分支,整个『联合』的过程被称为联合挂载(Union Mount)。
Docker 安全么?
Docker 利用了 Linux 内核中很多安全特性来保证不同容器之间的隔离,并且通过签名机制来对镜像进行验证。
大量生产环境的部署证明,Docker 虽然隔离性无法与虚拟机相比,但仍然具有极高的安全性。
镜像相关
联合文件系统是什么?
联合文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加;同时,可以将不同目录挂载到同一个虚拟文件系统下。
Docker 镜像是什么?
镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
联合文件系统是 Docker 镜像的基础。Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs。 用到的技术就是联合文件系统(Union File System),也叫 UnionFS ,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下。
另外,不同 Docker 容器可以共享一些基础的文件系统层,同时,再加上自己独有的改动层,这样大大提高了存储的效率。
精简 Docker 镜像尺寸的好处
- 减少构建时间
- 减少磁盘使用量
- 提高安全性,减少攻击面积(越小的镜像表示无用的程序越少,可以大大的减少被攻击的目标,从而提高了安全性)
- 减少上传和下载时间
- 提高部署速度
虽然存储资源较为廉价,但是网络 IO 是有限的,在带宽有限的情况下,部署一个 1G 的镜像和 10M 的镜像带来的时间差距可能就是分钟级和秒级的差距。特别是在出现故障,服务被调度到其他节点时,这个时间尤为宝贵。
优化Docker镜像的方法
要保证镜像尽可能小,可以从以下五个方面着手:
- 优化基础镜像
- 串联Dockerfile指令,保证层级尽量少
- 去除不必要的内容(源码包、编译过程中产生的日志文件、添加的包管理仓库、包管理缓存)
- 复用镜像层
- 分阶段构建(将打包镜像分成两个阶段,一个阶段用于开发,打包,该阶段包含构建应用程序所需的所有内容;一个用于生产运行,该阶段只包含你的应用程序以及运行它所需的内容)
具体请参考:纯干货!如何优雅的精简Docker镜像?
本地的镜像文件都存放在哪里
与Docker相关的本地资源存放在/var/lib/docker/
目录下。其中,
- container目录存放容器信息
- graph目录存放镜像信息
- aufs目录下存放具体的镜像底层文件。早期 Docker 的默认文件系统是
AUFS
(后来是Overlay2
)
构建Docker镜像应该遵循哪些原则?
整体上,尽量保持镜像功能的明确和内容的精简,要点包括:
- 尽量选取满足需求但较小的基础系统镜像
- 清理编译生成的文件、安装包的缓存等临时文件
- 安装各个软件时候要指定准确的版本号,并避免引入不需要的依赖
- 从安全的角度考虑,应用尽量使用系统的库和依赖
- 使用Dockerfile创建镜像时候要添加
.dockerignore
文件或使用干净的工作目录
DockerFile常见指令
具体指令请参考:纯干货!Docker Dockerfile指令大全
ADD 和 COPY 指令的区别
两者功能类似,都是复制文件或者目录到容器里指定路径。
除此之外,ADD 还支持使用TAR文件和URL路径,并且会将tar压缩文件(gzip, bzip2以及 xz格式)解压缩。
如果指定的是url,会从指定的url下载文件放到目录中(如果url下载的文件为tar文件,则不会展开)
CMD 与 ENTRYPOINT 的异同点
这俩命令非常像,而且还可以配合使用。
相同点:
- 只能写一条,如果写了多条,那么只有最后一条生效。
- 容器启动时才运行,运行时机相同。
不同点:
- ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖。
如果我们在Dockerfile中同时写了 ENTRYPOINT 和 CMD ,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数。
ARG 和 ENV 指令
构建参数ARG和ENV指令一样,都是设置环境变量。不过作用域不一样。
ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build
的过程中有效,构建好的镜像内不存在此环境变量。
ENV无论是接下来的指令(如ENV、ADD、COPY等,其调用格式为$variable_name
或${variable_name}
),还是在容器中运行的程序,都可以使用这里定义的环境变量。