一、宿主如果和容器系统不同的话,那不是和虚拟机一样,一层层的调用,那么Docker和虚拟机还有什么差别?
要把Windows和Linux分清楚,更要把内核(kernel)和用户空间(userland)分清楚。容器内的进程是直接运行于宿主内核的,这点和宿主进程一致,只是容器的userland不同,容器的 userland由容器镜像提供,也就是说镜像提供了rootfs。假设宿主是Ubuntu,容器是CentOS。CentOS 容器中的进程会直接向Ubuntu宿主内核发送syscall,而不会直接或间接的使用任何 Ubuntu 的 userland 的库。
这点和虚拟机有本质的不同,虚拟机是虚拟环境,在现有系统上虚拟一套物理设备,然后在虚拟环境内运行一个虚拟环境的操作系统内核,在内核之上再跑完整系统,并在里面调用进程。
还以上面的例子去考虑,虚拟机中,CentOS的进程发送syscall内核调用,该请求会被虚拟机内的CentOS的内核接到,然后CentOS内核访问虚拟硬件时,由虚拟机的服务软件截获,并使用宿主系统,也就是Ubuntu的内核及userland的库去执行。
而且,Linux和Windows在这点上非常不同。Linux的进程是直接发syscall的,而Windows则把 syscall隐藏于一层层的DLL服务之后,因此Windows的任何一个进程如果要执行,不仅仅需要 Windows内核,还需要一群服务来支撑,所以如果Windows要实现类似的机制,容器内将不会像Linux这样轻量级,而是非常臃肿。看一下微软移植的Docker就非常清楚了。
所以不要把Docker和虚拟机弄混,Docker容器只是一个进程而已,只不过利用镜像提供的 rootfs提供了调用所需的userland库支持,使得进程可以在受控环境下运行而已,它并没有虚拟出一个机器出来。
二、如果 Docker 升级或者重启的话,那容器是不是都会被停掉然后重启啊?
在 1.12 以前的版本确实如此,但是从 1.12 开始,Docker 引擎加入了 --live-restore 参数,使用该参数可以避免引擎升级、重启导致容器停止服务的情况。
默认情况该功能不会被启动,如需启动,需要配置 docker 服务配置文件。比如 Ubuntu 16.04 这类 systemd 的系统,可以修改 /etc/systemd/system/multi-user.target.wants/docker.service 文件,在 ExecStart= 后面配置上 --live-restore:
ExecStart=/usr/bin/dockerd \ --registry-mirror=https://registry.docker-cn.com \ --live-restore上面的格式中使用了行尾 \ 的换行形式,这点和 bash 脚本一样,systemd 支持这种换行形式,如对此不了解可以先去学习 bash 程序设计。
需要注意的是,--live-restore 和 Swarm Mode 不兼容,所以在集群环境中不要使用。实际上集群环境也不用担心某个服务器重启的问题,因为其上的服务都会被调度到别的节点上,因此服务并不会被中断。
三、怎么固定容器 IP 地址?每次重启容器都要变化 IP 地址怎么办?
一般情况是不需要指定容器 IP 地址的。这不是虚拟主机,而是容器。其地址是供容器间通讯的,容器间则不用 IP 直接通讯,而使用容器名、服务名、网络别名。
为了保持向后兼容,docker run 在不指定 --network 时,所在的网络是 default bridge,在这个网络下,需要使用 --link 参数才可以让两个容器找到对方。
但这是有局限性的,因为这个时候使用的是 /etc/hosts 静态文件来进行的解析,比如一个主机挂了后,重新启动IP可能会改变。虽然说这种改变Docker是可能更新/etc/hosts文件,但是这有诸多问题,可能会因为竞争冒险导致 /etc/hosts 文件损毁,也可能还在运行的容器在取得 /etc/hosts 的解析结果后,不再去监视该文件是否变动。种种原因都可能会导致旧的主机无法通过容器名访问到新的主机。
如果可能不要使用这种过时的方式,而是用下面说的自定义网络的方式。而对于新的环境(Docker 1.10以上),应该给容器建立自定义网络,同一个自定义网络中,可以使用对方容器的容器名、服务名、网络别名来找到对方。这个时候帮助进行服务发现的是Docker 内置的DNS。所以,无论容器是否重启、更换IP,内置的DNS都能正确指定到对方的位置。
四、如何修改容器的 /etc/hosts 文件?
容器内的 /etc/hosts 文件不应该被随意修改,如果必须添加主机名和 IP 地址映射关系,应该在 docker run 时使用 --add-host 参数,或者在 docker-compose.yml 中添加 extra_hosts 项。不过在用之前,应该再考虑一下真的需要修改 /etc/hosts 么?如果只是为了容器间互相访问,应该建立自定义网络,并使用 Docker 内置的 DNS 服务。
五、怎么映射宿主端口?Dockerfile 中的EXPOSE和 docker run -p 有什么区别?
Docker中有两个概念,一个叫做 EXPOSE ,一个叫做 PUBLISH 。
EXPOSE 是镜像/容器声明要暴露该端口,可以供其他容器使用。这种声明,在没有设定 --icc=false的时候,实际上只是一种标注,并不强制。也就是说,没有声明EXPOSE的端口,其它容器也可以访问。但是当强制--icc=false的时候,那么只有EXPOSE的端口,其它容器才可以访问。
PUBLISH则是通过映射宿主端口,将容器的端口公开于外界,也就是说宿主之外的机器,可以通过访问宿主IP及对应的该映射端口,访问到容器对应端口,从而使用容器服务。
EXPOSE的端口可以不PUBLISH,这样只有容器间可以访问,宿主之外无法访问。而PUBLISH 的端口,可以不事先EXPOSE,换句话说PUBLISH等于同时隐式定义了该端口要EXPOSE。
docker run命令中的-p, -P参数,以及docker-compose.yml中的ports部分,实际上均是指PUBLISH。
小写-p是端口映射,格式为 [宿主IP:]<宿主端口>:<容器端口>,其中宿主端口和容器端口,既可以是一个数字,也可以是一个范围,比如:1000-2000:1000-2000。对于多宿主的机器,可以指定宿主IP,不指定宿主IP时,守护所有接口。
大写 -P 则是自动映射,将所有定义 EXPOSE 的端口,随机映射到宿主的某个端口。
来源:CSDN
作者:不甘平凡※
链接:https://blog.csdn.net/LS19990712/article/details/103835727