Docker面试系列-01

2022年7月17日
大约 14 分钟

Docker面试系列-01

1. 什么是 Docker?

Docker是一个容器化平台,它以容器的形式将你的应用程序及所有的依赖项打包在一起,以确保你的应用程序在任何环境中无缝运行。

到目前为止,Docker看起来还很像一个典型的Linux虚拟化栈。实际上,Docker镜像的第二层是root文件系统rootfs,它位于引导文件系统之上。rootfs可以是一种或多种操作系统(如Debian或者 Ubuntu文件系统)。

在传统的Linux 引导过程中,root文件系统会最先以只读的方式加载,当引导结束并完成了完整性检查之后,它才会被切换为读写模式。但是在Docker中root文件系统永远只能是只读状态,并且Docker利用联合加载(union mount)技术又会在root文件系统层加载更多的只读文件系统。联合加载指的是一次同时加载多个文件系统,但是在外面看起来只能看到一个文件系统。联合加载会将各层文件系统叠加到一起,这样最终的文件系统会包含所有底层的文件和目录。

Docker将这样的文件系统称为镜像。一个镜像可以放到另一个镜像的顶部。位于下面的镜像称为父镜像(parent image),可以依次类推,直到镜像栈的最底部,最底部的镜像称为基础镜像(base image)。最后,当从一个镜像启动容器时,Docker会在该镜像的最顶层加载一个读写文件系统。如果想在Docker中运行的程序就是在这个读写层中执行的。

2. 什么是 Docker 镜像?

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。

Docker镜像是Docker容器的源代码,Docker镜像用于创建容器,使用Build命令创建镜像。

Docker镜像是由文件系统叠加而成。最底端是一个引导文件系统,即bootfs,这很像典型的Linu/Unix的引导文件系统。Docker 用户几乎永远不会和引导文件系统有什么交互。实际上,当一个容器启动后,它将会被移到内存中,而引导文件系统则会被卸载(ummount),以留出更多的内存供initrd 磁盘镜像使用。

3. 什么是 Docker 容器?

Docker容器是一个开源的应用容器引擎,让开发者可以以统一的方式打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何安装了docker引擎的服务器上(包括流行的Linux机器、windows机器),也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类似iPhone的app)。

几乎没有性能开销,可以很容易地在机器和数据中心中运行。最重要的是,他们不依赖于任何语言、框架包括系统。

4. 什么是容器?什么是 Docker?

容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。开发人员在自己笔记本上创建并测试好的容器,无需任何修改就能够在生产系统的虚拟机、物理服务器或公有云主机上运行。

Docker容器包括应用程序及所有的依赖项,作为操作系统的独立进程运行。Docker是容器的一种,还有其他容器,比如CoreOS rkt等。

5. Docker 容器有几种状态?

四种状态:运行、已停止、重新启动、已退出。

6. Docker 有哪些优缺点?

docker优点

1、部署方便

你一定还有印象,在我们最开始学习编程的时候,搭建环境这一步往往会耗费我们好几个小时的时间,而且其中一个小问题可能需要找很久才能够解决。你还会得到关于环境搭建方面的团队其他成员的求助。而有了容器之后,这些都变得非常容易,你的开发环境就只是一个或者几个容器镜像的地址,最多再需要一个控制部署流程的执行脚本。或者进一步将你的环境镜像以及镜像脚本放入一个git项目,发布到云端,需要的时候将它拉到本地就可以了。

2、部署安全

当我们收到一个bug反馈的时候,很多时候心里面的第一反应一定是“我本地是好的啊”!这种情况的发生就在于环境的不一致,我们在开发过程中的调试往往不能保证其他环境的问题,但是我们却要为此买单,这真是一件令人苦恼的事情。有了容器之后,这将很少发生。我们可以通过容器技术将开发环境和测试环境以及生产环境保持版本和依赖上的统一,保证代码在一个高度统一的环境上执行。而测试环境的统一,也同样能解决CI流程对环境的要求。

3、隔离性好

不管是开发还是生产,往往我们一台机器上可能需要跑多个服务,而服务各自需要的依赖配置不尽相同,假如说两个应用需要使用同一个依赖,或者两个应用需要的依赖之间会有一些冲突,这个时候就很容易出现问题了。所以同一台服务器上不同应用提供的不同服务,最好还是将其隔离起来。而容器在这方面有天生的优势,每一个容器就是一个隔离的环境,你对容器内部提供服务的要求,容器可以自依赖的全部提供。

4、快速回滚

容器之前的回滚机制,一般需要基于上个版本的应用重新部署,且替换掉目前的问题版本。在最初的时代,可能是一套完整的开发到部署的流程,而执行这一套流程往往需要很长的时间。在基于git的环境中,可能是回退某个历史提交,然后重新部署。这些跟容器技术相比都不够快,而且可能会引起新的问题(因为是基于新版本的修改)。而容器技术天生带有回滚属性,因为每个历史容器或者镜像都会有保存,而替换一个容器或者某个历史镜像是非常快速和简单的。

5、成本低

这可能是一个最明显和有用的优点了,在容器出现之前,我们往往构筑一个应用就需要一台新的服务器或者一台虚机。服务器的购置成本和运维成本都很高,而虚机需要占用很多不必要的资源。相比之下,容器技术就小巧轻便的多,只需要给一个容器内部构建应用需要的依赖就可以了,这也是容器技术发展迅速的最主要原因。

6、管理成本更低

随着大环境的发展,docker等容器的使用和学习的成本也是愈发降低,成为更多开发者和企业的选择。

docker缺点

1、隔离性

基于hypervisor的虚机技术,在隔离性上比容器技术要更好,它们的系统硬件资源完全是虚拟化的,当一台虚机出现系统级别的问题,往往不会蔓延到同一宿主机上的其他虚机。但是容器就不一样了,容器之间共享同一个操作系统内核以及其他组件,所以在收到攻击之类的情况发生时,更容易通过底层操作系统影响到其他容器。当然,这个问题可以通过在虚机中部署容器来解决,可是这样又会引出新的问题,比如成本的增加以及下面要提到的问题:性能。

2、性能

不管是虚机还是容器,都是运用不同的技术,对应用本身进行了一定程度的封装和隔离,在降低应用和应用之间以及应用和环境之间的耦合性上做了很多努力,但是随机而来的,就会产生更多的网络连接转发以及数据交互,这在低并发系统上表现不会太明显,而且往往不会成为一个应用的瓶颈(可能会分散于不同的虚机或者服务器上),但是当同一虚机或者服务器下面的容器需要更高并发量支撑的时候,也就是并发问题成为应用瓶颈的时候,容器会将这个问题放大,所以,并不是所有的应用场景都是适用于容器技术的。

7. DockerFile 中最常见指令有哪些?

指令说明
FROM指定基础镜像
LABEL功能为镜像指定标签
RUN运行指定命令
CMD容器启动时要运行的命令

8. 构建 Docker 镜像应该遵循哪些原则?

整体原则上, 尽量保待镜像功能的明确和内容的精简, 避免添加额外文件和操作步骤, 要点包括:

  • 尽量选取满足需求但较小的基础系统镜像, 例如大部分时候可以选择 debian:wheezy或debian:jessie镜像, 仅有不足百兆大小;

  • 清理编译生成文件、 安装包的缓存等临时文件;

  • 安装各个软件时候要指定准确的版本号, 并避免引入不需要的依赖;

  • 从安全角度考虑, 应用要尽量使用系统的库和依赖;

  • 如果安装应用时候需要配置一些特殊的环境变量, 在安装后要还原不需要保持的变量值;

  • 使用Dockerfile创建镜像时候要添加.dockerignore文件或使用干净的工作目录;

  • 区分编译环境容器和运行时环境容器, 使用多阶段镜像创建。

9. Docker 中都有哪些常用命令?

命令说明
docker pull拉去或更新指定的镜像
docker push将镜像推送到远程仓库
docker rm删除容器
docker rmi删除镜像
docker images列出所有镜像
docker ps列出所有容器

10. Docker 容器和主机之间如何复制数据?

docker cp命令用于容器和主机之间的数据复制。

1、从容器里面拷文件到宿主机

在宿主机里面执行以下命令 docker cp 容器名:要拷贝的文件在容器里面的路径 要拷贝到宿主机的相应路径

docker cp project:/opt/jingxuan.txt /home/

2、从宿主机拷文件到容器

在宿主机里面执行如下命令

docker cp 要拷贝的文件路径 容器名:要拷贝到容器里面对应的路径

docker cp /home/jingxuan.txt project:/opt/

需要注意的是不管容器有没有启动,拷贝命令都会生效。如果拷贝的内容有重复,会直接覆盖,不会提示。

11. Docker 中什么是 Dockerfile?

Dockerfile:用于创建image镜像的模板文件,出于管理和安全的考虑,docker官方建议所有的镜像文件应该由dockerfile来创建,而当前不少用户把docker当虚拟机来使用,甚至容器中安装SSH,从安全的角度,这是不恰当的。

12. 解释一下 dockerfile 的 ONBUILD 指令?

当镜像用作另一个镜像构建的基础时,ONBUILD指令向镜像添加将在稍后执行的触发指令。如果要构建将用作构建其他镜像的基础的镜像,这将非常有用。

例如,可以使用特定于用户的配置自定义的应用程序构建环境或守护程序。

13. 什么是 Docker Swarm?

Docker Swarm是docker的本地群集。

Docker Swarm将docker主机池转变为单个虚拟docker主机。

Docjer Swarm提供标准的docker API,任何已经与docker守护进程通信的工具都可以使用Swarm透明地扩展到多个主机。

14. 生产环境中如何监控 Docker?

1、Docker提供docker:stats和docker事件等工具来监控生产中的docker。我们可以使用这些命令获取重要统计数据的报告。

2、Docker统计数据:当我们使用容器ID调用docker stats时,我们获得容器的CPU,内存使用情况等。它类似于Linux中的top命令。

3、Docker事件:docker事件是一个命令,用于查看docker守护程序中正在进行的活动流。

一些常见的docker事件:attach、commit、die、detach、rename、destroy等。还可以使用各种选项来限制或过滤我们关注的事情。

15. Docker 容器如何运行在非Linux系统?

1、通过添加到Linux内核版本2.6.24的名称空间功能,可以实现容器的概念。

容器将其ID添加到每个进程,并向每个系统调用添加新的访问控制检查。它由clone()系统调用访问,该调用允许创建先前全局命名空间的单独实例。

2、如果由于Linux内核中可用的功能而可以使用容器,那么显而易见的问题是非Linux系统如何运行容器。

Docker for Mac和Windows都使用Linux VM来运行容器。

Docker Toolbox用于在Virtual Box VM中运行容器。但是,罪行的docker早Windows中使用Hyper-V,在MAC中使用Hypervisor.framework。

16. Docker 中如何批量清理容器和镜像文件?

1、清理所有已经停止的容器

docker rm $(docker ps -a -q)

2、清理所有镜像

docker rmi $(docker images -q)

3、强制清理所有镜像

docker rmi -f $(docker images -q)

4、清理过滤出来的镜像

docker rmi $(docker images | grep "关键字" | awk '{print $3}')

## 17. Docker 中如何查看镜像支持环境变量?

**方式一:docker inspect**

通过docker inspect命令不仅能查看环境变量,还能查看容器其它相关信息,非常丰富,以Json格式输出。
```shell
docker inspect centos

可读性还可以,但也不算很高,可以通过grep命令过滤一下:

$ docker inspect centos | grep SERVER "SERVER_PORT=80"

或者可以解析一下Json文本:

$ docker inspect -f '{{range $index, $value := .Config.Env}}{{println $value}}{{end}}' centosPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

方式二:doecker exec env

这种方式获取的环境变量就跟我们平时获取linux环境变量是一样的了。只是在容器跑了个env命令而已。如下:

$ docker exec centos envPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=f8b489603f31HOME=/root

18. Docker 中本地镜像文件一般存放在什么位置?

Docker相关的本地资源存在/var/lib/docker/目录下。

其中container目录存放容器信息,graph目录存放镜像信息,aufs目录下存放具体的镜像底层文件。

19. Docker 容器和虚拟机有什么区别?

相同点

1、容器和虚拟机一样,都会对物理硬件资源进行共享使用。

2、容器和虚拟机的生命周期比较相似(创建、运行、暂停、关闭等等)。

3、容器中或虚拟机中都可以安装各种应用,如redis、mysql、nginx等。也就是说,在容器中的操作,如同在一个虚拟机(操作系统)中操作一样。

4、同虚拟机一样,容器创建后,会存储在宿主机上:linux上位于/var/lib/docker/containers下

不同点

1、虚拟机的创建、启动和关闭都是基于一个完整的操作系统。一个虚拟机就是一个完整的操作系统。而容器直接运行在宿主机的内核上,其本质上以一系列进程的结合。

2、容器是轻量级的,虚拟机是重量级的。首先容器不需要额外的资源来管理(不需要Hypervisor、Guest OS),虚拟机额外更多的性能消耗;其次创建、启动或关闭容器,如同创建、启动或者关闭进程那么轻松,而创建、启动、关闭一个操作系统就没那么方便了。

也因此,意味着在给定的硬件上能运行更多数量的容器,甚至可以直接把Docker运行在虚拟机上。

20. Docker 中一个容器可以同时运行多个应用进程吗?

一般不推荐在用以容器内运行多个应用进程,如果有类似需求,可以用过额外的进程管理机制,比如supervisord来管理所运行的进程。