1、entrypoint & cmd 指令的区别
这主要考察 Dockerfile 良好实践中关于容器启动时运行的命令。
entrypoint 和 cmd 命令都是设置容器启动时要执行的命令,但用法稍有不同。entrypoint 和 cmd 指令都是在 Dockerfile 中定义,但在镜像构建过程中并不会被执行,只有当容器启动时,entrypoint 和 cmd 指令设置的命令才会被执行。Dockerfile 中可以有多个 entrypoint 指令,但生效的只有最后一个 entrypoint 指令,cmd 指令也类似,两者的区别主要如下:
entrypoint 指令一般用来设置容器启动后要执行的命令,这对容器来说,往往是固定不变的。
cmd 指令一般用来设置容器启动后执行命令的默认参数,这对容器来说,往往是可以改变的,cmd 能够被docker run 后面跟的命令行参数替换,一般而言,两者是可以结合使用的。
举个例子
FROM baseimage:v1.0
ENTRYPOINT ["/usr/sbin/nginx"]
CMD [""]
从以上 Dockerfile 设置的 entrypoint 和 cmd 指令来看,容器启动时会运行 nginx 进程,而 cmd 指令可以在执行 docker run 传入参数进行覆盖,如 docker run --name:** -p **:** -g "daemon off",其中 -g "daemon off" 将会被作为命令参数追加到 entrypoint 后面的指令,也就是说最后容器的启动命令为:/usr/sbin/nginx -g "daemon off;",以前台进程来运行 nginx 进程。
2、如何覆盖 entrypoint 和 cmd 指令
这个问题是考察 entrypoint 和 cmd 的格式
CMD 有三种格式:
(1) Exec 格式:CMD ["executabel", "param1", "param2"],这是 CMD 的推荐格式
(2) CMD ["param1", "param2"],这种模式和 entrypoint 结合使用,为 entrypoint 提供额外的参数,此时 entrypoint 必须使用 exec 格式。
(3) Shell 格式:CMD command param1 param2
ENTRYPOINT 有两种格式:
(1) Exec 格式:ENTRYPOINT ["executable", "param1", "param2"],这是 ENTRYPOINT 的推荐方式
(2) Shell 格式:ENTRYPOINT command param1 param2
其中,CMD 无论是哪种格式,都会被 docker run 命令带的参数直接覆盖
而 ENTRYPOINT 无论是哪种格式,ENTRYPOINT 指令一定会被执行,并不会被覆盖,但 ENTRYPOINT 在选择格式时必须格外小心,因为这两种格式的效果差别很大。
Exec 格式
ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。
Shell 格式
ENTRYPOINT 的 shell 格式会忽略任何 CMD 或者 docker run 提供的任何参数。
3、ADD 和 COPY 指令有什么区别?推荐使用哪种方式
这几道面试题都是 Dockerfile 良好实践中的知识点,这道题主要考察在构建镜像时,如何向镜像拷贝文件。
ADD 指令
ADD 指令的功能是将主机构建环境(上下文)目录中的文件和目录,拷贝到镜像中,如果源文件是个归档文件(压缩文件,如tar, gzip, bzip2),ADD 指令会自动进行解压,如:
ADD /foo.tar.gz /tmp/
上述指令会将 foo.tar.gz 压缩文件解压到容器的 /tmp 目录下。
COPY指令
COPY 指令和 ADD 指令类似,都是负责拷贝文件或者目录到容器里,但 COPY 指令功能更简洁和易懂,COPY 是ADD 的一种简化版本,目的在于满足大多数人复制文件到容器的需求,在大多数情况下,都建议使用 COPY 指令,除非你明确需要ADD指令。
4、sed、grep 和 awk 命令的区别
这道是考察 linux 常见运维命令。
简单理解,grep 命令主要用于关键字的筛选,sed 指令是以行为单位的文本编辑工具,而 awk 指令通过指定分割符将一行(一条记录)划分为多个字段,以字段为单位来处理文本,一般结合 grep 命令来使用,比如只打印第一列,如:cat /etc/hosts | grep *** | awk '{print $1}',更详细的说明可以参考以下文档:
5、两个 namespace 如何进行通信
这道题主要考察 Docker 主机两个 namespace(容器)或者是容器与主机如何进行通信的原理。
我们都知道,Docker 是基于 LXC容器技术 namespace 来实现资源的隔离,基于 LXC容器技术 cgroups 来实现资源的限制,Docker 采用虚拟网络设置(Virtual Network Device)的方式,将不同命名空间的网络设备连接到一起,这种设备对都是成对存在的,一端作为容器的网卡eth0,一端连接到宿主机上的docker网桥 veth,从而实现 Docker 主机上不同 namespace通信,详情可见下图:
![](http://upload-images.jianshu.io/upload_images/16605471-df55e5fc0b5d2ba5.png?imageMogr2/auto-orient/strip|imageView2/2/w/600/format/webp)
或者参考如下文档:docker namespace
6、简述 Docker 如何用 namespace 来进行资源隔离
这道题主要也是考察 namespace 相关的知识。
Docker 主要通过六大 Namespace 来实现资源的隔离,如下:
(1) Mount Namespace,挂载命名空间,用来隔离挂载目录,让不同 Namespace 拥有独立的挂载结构,而程序中对挂载信息的修改不会影响到其他 Namespace 中程序的运行。
(2) UTS Namespace,UTS Namespace,用来隔离主机名和域名,通过UTS Namespace,让不同 Namespace 拥有独立的主机名称和网络访问域名。
(3) IPC Namespace,进程通信命名空间,用来隔离进程间通信,主要作用于 消息队列、信号量或者是管道,IPC 只能做到同一个命名空间进行通信,无法做到不同命名空间进行信息交换通信。
(4) PID Namespace,进程命名空间,用来隔离进程的运行信息,PID Namespace 让命名空间拥有独立的进程号管理。
(5) Networt Namespace,网络命名空间,用来隔离网络协议栈,包括网络设备接口、IPV4 和 IPV6 协议等。
(6) User Namespace,用户命名空间,用来隔离用户和用户组信息,通过严格的用户隔离机制,避免 Namespace 中的程序直接操作到宿主机或者其他 Namespace 中的用户。
除了 Namespace ,还有一项核心技术 Cgroups(控制组),可以参考这篇博客:Docker底层技术架构
7、glusterfs 分布式存储元数据不一致时,如何恢复处理
这道是考察存储相关的知识。
对存储底层了解的不多,因此到时这道题我就简单粗暴地说重启 glusterfs服务进程,明显没有 get 到面试官的点。
后来查阅相关的资料,说是跟时间戳有关系,但本人也没有验证过,详细可以参考这篇博客:glusterfs 数据不一致处理
8、service 对外提供服务的方式有几种
这道是考察外部如何访问 k8s 集群内的 service 服务。
目前来说总共有以下4种方式:
NodePort 方式
这种方式会将 Service 的端口映射到集群内的所有的 node节点,集群内的所有 node 节点都会起一个相同的随机端口,通过访问:${任一node节点IP}:${nodeport端口} 就可以访问到 k8s 集群内指定的 service 服务了,iptables 会捕获这种方式的请求,根据 iptables 中的规则转发到后端具体的 pod 实例上,这种方式简单,但会占用 node 节点的端口资源,并且 nodeport 没有一个负载均衡器进行路由分发,这也就衍生了第二种方式。
LoadBalancer 方式
这种方式,在nodeport的外部搭建一个负载均衡器(云服务提供商),但 LoadBalancer 需要 k8s 集群跑在支持的 Cloud Provider 上,这对于企业内部运行在私有云上的 k8s 集群不太适合。
Ingress 方式
Ingress 主要有两大组件, Ingress 和 Ingress Controller,其中 Ingress 解决的是服务和域名的对应问题,基本上一个 Ingress 对象,通过 yaml 文件进行创建和更新,而 Ingress Controller 是将 Ingress 的这种变化动态生成一段 nginx 的配置,并通过 apiserver 更新到 nginx 这个 pod 中,并自动 reload。
Router 方式
这种方式是 Openshift 特有的方式,通过为 k8s 集群内的每个 service 对象生成一个 Router 对象,就能实现外界访问 k8s 集群内的 service 服务了。
9、ovs 访问外部服务 ovs 网桥到物理网卡是如何连接的
这道是考察 sdn 网络 openvswitch的架构和组成。
正常跨节点之间的通信是通过 vxlan 隧道 或者是 gre连接来完成,见下图:
![](http://upload-images.jianshu.io/upload_images/16605471-1a9fe641eaf46e14.png?imageMogr2/auto-orient/strip|imageView2/2/w/669/format/webp)
但如果集群内的容器要访问外部服务,是通过ovs 的 tun0 端口来完成。