一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
基础部分
什么是 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}),还是在容器中运行的程序,都可以使用这里定义的环境变量。
如何查看镜像支持的环境变量?
sudo docker run IMAGE env
如何批量清理临时镜像文件?
sudo docker rmi $(sudo docker images -q -f danging=true)
其中,dangling=true表示虚悬镜像。
虚悬镜像(dangling image): 镜像没有仓库名或没有标签
查询显示虚悬镜像:docker images -f dangling=true
谈谈 Docker Storage Driver(存储驱动)
每个 Docker 容器都有一个本地存储空间,用于保存层叠的镜像层(Image Layer)以及挂载的容器文件系统。
默认情况下,容器的所有读写操作都发生在其镜像层上或挂载的文件系统中,所以存储是每个容器的性能和稳定性不可或缺的一个环节。
以往,本地存储是通过存储驱动(Storage Driver)进行管理的,有时候也被称为 Graph Driver。
虽然存储驱动在上层抽象设计中都采用了栈式镜像层存储和写时复制(Copy-on-Write)的设计思想,但是 Docker 在 Linux 底层支持几种不同的存储驱动的具体实现,每一种实现方式都采用不同方法实现了镜像层和写时复制。
虽然底层实现的差异不影响用户与 Docker 之间的交互,但是对 Docker 的性能和稳定性至关重要。
- 在 Linux 上,Docker 可选择的一些存储驱动包括 AUFS(最原始也是最老的)、Overlay2(可能是未来的最佳选择)。
- Docker 在 Windows 操作系统上只支持一种存储驱动,即 Windows Filter。
存储驱动的选择是节点级别的。这意味着每个 Docker 主机只能选择一种存储驱动,而不能为每个容器选择不同的存储驱动。
在 Linux 上,可以通过修改 /etc/docker/daemon.json 文件来修改存储引擎配置,修改完成之后需要重启 Docker 才能够生效。
下面的片段展示了如何将存储驱动设置为 Overlay2:
{ "storage-driver": "overlay2" }
容器相关
Docker容器是什么?
Docker容器是一个具体的镜像实例,Docker容器包括应用程序及所有的依赖项,作为操作系统的独立进程运行。
解释容器编排以及我们为什么需要使用它?
容器编排有助于管理大型环境中运行的容器。
容器编排可以控制和自动化以下任务:
- 容器的供应和部署
- 负载均衡
- 容器之间的资源分配
- 监控容器和主机的健康状况
- 容器的缩放
Docker容器有几种状态?
- created:已经被创建(使用
docker ps -a命令可以列出)但是还没有被启动 (使用docker ps命令无法列出) - running:运行中
- paused:容器的进程被暂停了
- restarting:容器的进程正在重启过程中
- exited:表示容器之前运行过但是现在处于停止状态(要区别于 created 状态,它是指一个新创建出的尚未运行过的容器),可以通过
start命令使其重新进入 running 状态 - destroyed:容器被删除了,再也不存在了
容器与主机之间的数据拷贝命令?
docker cp命令用于容器与主机之间的数据拷贝
- 主机到容器:
docker cp /www 96f7f14e99ab:/www/ - 容器到主机:
docker cp 96f7f14e99ab:/www /tmp
如何监控运行的Docker容器?
Docker提供docker stats和docker events等工具来监控生产中的docker。我们可以使用这些命令获取重要统计数据的报告。
docker stats:获得容器的CPU,内存等资源使用情况,默认情况下,stats 命令会每隔 1 秒钟刷新一次输出的内容直到你按下ctrl + c,如果不想持续的监控容器使用资源的情况,可以通过--no-stream选项只输出当前的状态。docker events:用于打印出实时的系统事件。
启动nginx容器(随机端口映射),并挂载本地文件目录到容器html的命令?
docker run -d -p --name nginx2 -v /home/nginx:/usr/share/nginx/html nginx
容器退出后,通过docker ps 命令查看不到,数据会丢失么?
容器退出后会处于 终止(exited) 状态,此时可以通过 docker ps -a 查看,其中数据不会丢失,还可以通过 docker start 来启动,只有删除容器才会清除数据。
如何停止所有正在运行的容器?
docker kill $(sudo docker ps -q)
如何清理批量后台停止的容器?
docker rm $(sudo docker ps -a -q)
如何临时退出一个正在交互的容器的终端,而不终止它?
docker 以交互式的方式启动容器后,如果使用exit退出交互界面后,整个容器都会exit(按Ctrl+c会使容器内的应用进程终止,进而会使容器终止)。但是如何使我们退出交互模式的同时不关闭容器呢,那就是在要退出交互模式时不使用exit还是使用命令 Ctrl+P+Q (先按Ctrl+p,后按Ctrl+q)。
如何退出容器时候自动删除?
使用 -rm 选项,例如:sudo docker run -rm -it ubuntu。
怎么快速查看本地的镜像和容器?
- 通过
docker images来快速查看本地镜像。 - 通过
docker ps -a快速查看本地容器。
很多应用容器都是默认后台运行的,怎么查看它们的输出和日志信息?
使用docker logs,后面跟容器的名称或者ID信息。
可以在一个容器中同时运行多个应用进程吗?
一般不推荐在同一个容器内运行多个应用进程。
如果有类似需求,可以通过额外的进程管理机制。比如,supervisord来管理所运行的进程。
其他
仓库(Repository)、注册服务器(Registry)、注册索引(Index)有何关系?
- 仓库:存放一组关联镜像的集合,比如同一个应用的不同版本的镜像。
- 注册服务器:存放实际的镜像的地方。
- 注册索引:负责维护用户的账号,权限,搜索,标签等管理。
注册服务器利用注册索引来实现认证等管理。
Docker能在非Linux平台(Windows+MacOS)上运行吗?
可以
如何将一台宿主机的docker环境迁移到另外一台宿主机?
- 停止Docker服务。
- 将整个docker存储文件复制到另外一台宿主机上。
- 然后调整另外一台宿主机的配置即可。
Docker 与 虚拟机有何不同?
- 相比于虚拟机,Docker更快速(秒级启动)、轻便(联合文件系统)。
- Docker 是轻量级的沙盒,在其中运行的只是应用,虚拟机里面还有额外的系统。
- Docker是一个系统进程;虚拟机是在操作系统中的操作系统。
- Docker:体积小、启动速度快、性能好;虚拟机:体积大、启动速度慢、性能一般。
Docker 与 LXC(Linux Container)有何不同?
Linux Container 容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,LXC 利用 Linux 上相关技术实现容器。
Docker 则在如下的几个方面进行了改进:
- 移植性:通过抽象容器配置,容器可以实现一个平台移植到另一个平台;
- 镜像系统:基于 AUFS 的镜像系统为容器的分发带来了很多的便利,同时,共同的镜像层只需要存储一份,实现高效率的存储;
- 版本管理:类似于 GIT 的版本管理理念,用户可以更方面的创建、管理镜像文件;
- 仓库系统:仓库系统大大降低了镜像的分发和管理的成本;
- 周边工具:各种现有的工具(配置管理、云平台)对 Docker 的支持,以及基于Docker 的 Pass、CI 等系统,让 Docker 的应用更加方便和多样化。