docker desktop创建容器制定端口 docker怎么创建容器_容器

2.4 Namespace 介绍
2.41 Namespace是什么
Namespace是将内核的全局资源做封装,使得每个Namespace 都有一份独立的资源
因此不同的进程在各自的Namespace内对同一种资源的使用不会互相干扰这样的解释可能不清楚,举个例子,执行 sethostname这个系统调用时,可以改变系统的主机名,这个主机名就是一个内核的全局资源。内核通过实现 UTS Namespace,可以将不同的进程分隔在不同的UTS Namespace 中,在某个Namespace修改主机名时,另一个Namespace的主机名还是保持不变
第2章关于容器技术。
目前Linux内核总共实现了6种Namespace:
口IPC:隔离SystemVIPC和POSIX消息队列
口Network:隔离网络资源。
Mount:隔离文件系统挂载点
口PID:隔离进程ID。
口UTS:隔离主机名和域名。
User:隔离用户D和组ID 。

2.4.2Namespace的接口和使用
对Namespace的操作,主要是通过clone、setns和unshare这3个系统调用来完成的。clone可以用来创建新的Namespace。它接受一个叫flags的参衍苍独币榜数,这些flag包括CLONE NEWNS、CLONE NEWIPC、CLONE NEWUTS、CLONE NEWNETCLONE NEWPID和CLONE NEWUSER,我们通过传人这些CLONE NEW*来创建新的Namespace。这些flag对应的Namespace 都可以从字面上看出来,除了CLONE NEWNS这是用来创建Mount Namespace 的。指定了这些flag后,由clone创建出来的新进程,就位于全新的Namespace 里了,并且很自然地这个新进程以后创建出来的进程,也都在这个Namespace中
提Mount Namespace是第一个实现的Namespace,当初实现时并不是为了实现 Linux容器,因此也就没有预料到会有新的Namespace出现,因此用了CLONE NEWNS而不是CLONENEWMNT之类的名字。

那么,能不能为已有的进程创建新的 Namespace呢?答案是可以,unshare就是用来达到这个目的的。调用这个系统调用的进程,会被放进新创建的Namespace 里,要创建什么Namespace由flags参数指定,可以使用的flag也就是上面提到的那些。
以上两个系统调用都是用来创建新的Namespace 的,而setns 则可以将进程放到已有的Namespace 里,问题是如何指定已有的Namespace ?答案在procf里。每个进程在procfs下都有一个目录,在那里面就有 Namespace相关的信息,如下

docker desktop创建容器制定端口 docker怎么创建容器_docker_02


这里每个虚拟文件都对应了这个进程所处的Namespace。因此,如果另一个进程要进

入这个进程的Namespace,可以通过open 系统调用打开这里面的虚拟文件并得到一个文件描述符,然后把文件描述符传给setns,调用返回成功的话,就进入这个进程的 Namespace了
提示:docker exec命令的实现原理就是setns。
以下是一个简单的程序,在 Linux终端调用这个程序就会进入新的Namespace,同时也可以打开另一个终端,这个终端是在 host的Namespace里,这样就可以对比两个Namespace的区别了。 

docker desktop创建容器制定端口 docker怎么创建容器_Docker 命令启动容器_03

这个程序创建了UTS Namespace,可以通过修改 flag,创建其他Namespace,也可以创建几个Namespace的组合。这个程序将会用来为下面的内容做演示。

2.4.3各个Namespace介绍
1.UTS NamespaceUTSNamespace用于对主机名和域名进行隔离,也就是uname系统调用使用的结构体struct utsname里的nodename和domainname这两个字段,UTS这个名字也是由此而来的。那么,为什么要使用UTS Namespace 做隔离?这是因为主机名可以用来代替IP 地址因此,也就可以使用主机名在网络上访问某台机器了,如果不做隔离,这个机制在容器里就会出问题。

调用之前的程序后,在Namespace终端执行以下命令:
# hostname container
# hostname
container
这里已经改变了主机名,现在通过 host终端来看看host的主机名
# hostnameIinux-host
可以看到,host 的主机名并没有变化,这就是Namespace所起的作用
2.IPC Namespace
IPC是Inter-Process Communication的简写,也就是进程间通信。Linux提供了很多种讲程间通信的机制IPC Namespace 针对的是 SstemVIPC和 Poix 消息队列。这些IPC机制都会用到标识符,例如用标识符来区别不同的消息队列,然后两个进程通过标识符找到对应的消息队列进行通信等。

docker desktop创建容器制定端口 docker怎么创建容器_Docker 命令启动容器_04

3.PID Namespace
PIDNamespace用于隔离进程PID号,这样一来,不同的Namespace里的进程PID号就可以是一样的了。
当创建一个PIDNamespace 时,第一个进程的PID号是1,也就是init进程。init进程有一些特殊之处,例如init 进程需要负责回收所有孤儿进程的资源。另外,发送给 imnit进程的任何信号都会被屏蔽,即使发送的是SIGKILL信号,也就是说,在容器内无法“杀死”init进程。
但是当用ps命令查看系统的进程时,会发现竟然可以看到host的所有进程 :

docker desktop创建容器制定端口 docker怎么创建容器_Docker 命令启动容器_05

4.Mount NamespaceMount Namespace用来隔离文件系统挂载点,每个进程能看到的文件系统都记录在/proc/$$/mounts里。在创建了一个新的Mount Namespace后,进程系统对文件系统挂载/卸载的动作就不会影响到其他Namespace。
之前看到,创建PIDNamespace后,由于procfs 没有改变,因此通过ps命令看到的仍然是host的进程树,其实可以通过在这个PIDNamespace 里挂载procfs来解决这个问题如下:
# mount-t proc none /proc
# psax
PID TTYSTATTIME COMMAND1pts/2S+0:00newns3pts/2R+0:00psax
但此时由于文件系统挂载点没有隔离,因此 host看到的 procfs也会是这个新的procfs,这样在host上就会出问题:
# ps ax
Error,do this: mount -t proc none /proc

可如果同时使用Mount Namespace 和PID Namespace,新的Namespace 里的进程和host上的进程将会看到各自的procfs,故而也就不存在上面的问题了。
5、Network Namespace这个Namespace会对网络相关的系统资源进行隔离,每个Network Namespace都有自己的网络设备IP地址、路由表、/proc/net 目录、端口号等。网络隔离的必要性是很明显的.举一个例子,在没有隔离的情况下,如果两个不同的容器都想运行同一个 Web 应用,而这个应用又需要使用80端口,那就会有冲突了。 

新创建的Network Namespace 会有一个loopback设备,除此之外不会有任何其他网络设备,因此用户需要在这里面做自己的网络配置。IP工具已经支持Network Namespace,可以通过它来为新的Network Namespace配置网络功能。首先创建Network Namespace:


docker desktop创建容器制定端口 docker怎么创建容器_Docker 命令启动容器_06

6.User NamespaceUser Namespace 用来隔离用户和组ID,也就是说一个进程在Namespace 里的用户和组ID与它在 host里的ID可以不一样,这样说可能读者还不解有什么实际的用处。UserNamespace 最有用的地方在于,host 的普通用户进程在容器里可以是0号用户,也就是root用户。这样,进程在容器内可以做各种特权操作,但是它的特权被限定在容器内,离开了这个容器它就只有普通用户的权限了。

docker desktop创建容器制定端口 docker怎么创建容器_Docker 命令启动容器_07

 

docker desktop创建容器制定端口 docker怎么创建容器_运维_08


可以看到,我们成功地将 lizf用户映射成容器里的root用户了。对于gid,也可以做类
似的操作。至此,关于Namespace和Cgroup 的知识就讲解完了,可以看到,Namespace和Cgroup的使用是很灵活的,同时这里面又有不少需要注意的地方,因此直接操作 Namespace和Cgroup并不是很容易。正是因为这些原因,Docker 通过 Libcontainer 来处理这些底层的事情。这样一来,Docker 只需要简单地调用Libcontainer 的API,就能将完整的容器搭建起来。而作为 Docker 的用户,就更不用操心这些事情了,而只需要学习 Docker 的使用手册就能通过一两条简单的Docker 命令启动容器。 

2.5 容器造就 Docker
关于容器是否是 Docker的核心技术,业界一直存在着争议。有人认为 Docker 的核心技术是对分层镜像的创新使用,有人认为其核心是统一了应用的打包分发和部署方式,为服务器级别的“应用商店”提供了可能,而这将会是颠覆传统行业的举措。事实上,这一系列创新并不是依赖于容器技术的,基于传统的 hypervisor 也可以做到,业界也由此诞生
第2章关于容器技术27
了一些开源项目,比如 Hyper、Clear Linux 等。另外,Docker 官方对 Docker 核心功能的描述“BuildShipandRun”中也确实没有体现与容器强相关的内容。尽管如此,笔者依然认为容器是 Docker的核心技术之一。

首先从Docker 的诞生历史上,它主要是为了完善当时不愠不火的容器项目LXC,使用户可以更方便地使用容器,让容器可以更好地应用到项目开发和部署的各个流程中。从一开始LXC就是 Docker上的唯一容器引擎也可以看出这一点。所以可以说,Docker 是为容
器而生的。另外,更重要的一点,跟 Docker 一起发展和被大家熟知的,还有叫做“微服务”(microservice)的设计哲学,而这会把容器的优势发挥得更加淋漓尽致。容器作为Linux平台的轻量级虚拟化,其核心优势是跟内核的无缝融合,其在运行效率上的优势和极小的系统开销与需要将各个组件单独部署的微服务应用完美融合。而且微服务在隔离性问题上更加可控这也避免了容器相对传统虚拟化在隔离性上的短板。所以,未来在微服务的设计哲学下容器必将跟Docker一起得到更加广泛的应用和发展。

在理解了容器,理解了容器的核心技术Cgroup和Namespace,理解了容器技术如何巧妙且轻量地实现“容器”本身的资源控制和访问隔离之后,可以看到 Docker 和容器是一种完美的融合和相辅相成的关系,它们不是唯一的搭配,但一定是最完美的组合。与其说是容器造就了 Docker,不如说是它们造就了彼此,容器技术让 Docker 得到更多的应用和推,Docker 也使得容器技术被更多人熟知。在可预见的未来,它们也一定会彼此促进,共同发展,在全新的解决方案和生态系统中扮演着重要的角色。
2.6本章小结
本章对容器技术做了详细的剖析,相信读者已经对容器的概念和原理有了清晰的认识在这样的基础之上,可以更加轻松和深刻地理解 Docker 的一系列技术了,接下来的章节会针对 Docker中的各个子系统做详细的介绍。