共计 2801 个字符,预计需要花费 8 分钟才能阅读完成。
此‘容器’非彼容器
很多人可能曾经晓得了这一点:其实并不存在真正的 Linux“container”,在 Linux 中没有所谓的“容器”。家喻户晓,容器是应用 Linux 内核的两个个性(称为 namespaces 和 cgroups)运行的惯例过程。namespace 能够为过程提供“视图”用来暗藏 namespace 之外的所有内容,从而为本人提供一个独立的运行环境,在其中运行的过程将无奈看到或烦扰其余过程。
命名空间蕴含以下这些:
• Hostname
• Process IDs
• File System
• Network interfaces
• Inter-Process Communication (IPC)
尽管我在下面说过,在名称空间中运行的过程不会烦扰到其余过程,然而一个过程实践上能够应用其所在的物理计算机上的所有资源,从而使其余过程无奈应用资源。为了限度这一点,Linux 推出了称为 cgroups 的个性。过程能够像命名空间一样在 cgroup 中运行,然而 cgroup 限度了该过程能够应用的资源。这些资源包含 CPU,RAM,块设施 I /O,网络 I / O 等,CPU 通常受毫核(内核的千分之一)限度,而内存则受 RAM 字节数限度。该过程自身能够失常运行,然而将只能应用 cgroup 限度范畴内的最大 CPU,并且如果过程超出 cgroup 上设置的内存限度,则会呈现内存不足谬误。
对于 namespace 和 cgroups 能够参考之前的文章 什么是容器:namespces 和 cgroups
我想在这里指出的是 cgroups 和每个 namespce 类型都是独立的个性,下面列出的命名空间的某些子集能够应用或基本不应用,你只能应用 cgroup 或两者的某种其余组合(好吧,你仍在应用名称空间和 cgroup,但仅应用根目录 cgroup)。命名空间和 cgroup 也可用于过程组(一个命名空间中运行的多个过程),这样的话,过程之间就能够看到彼此并进行交互,或者在单个 cgroup 中运行它们,这样这些过程将一起被限度在特定数量的 CPU 和 RAM 中。
组合的组合
当在 Docker 上以通常形式运行容器时,Docker 会为每个容器创立 namespace 和 cgroup 并让它们一一映射,这就是开发人员对容器的通常认识。
容器实质上是独立的孤岛,但它们可能具备映射到宿主机的存储卷或端口,以便它们能够进行通信。然而,通过一些额定的命令行参数,你能够应用单个 namespace 组合 Docker 容器。首先,咱们创立一个 nginx 容器。
$ cat <<EOF >> nginx.conf
> error_log stderr;
> events {worker_connections 1024;}
> http {
> access_log /dev/stdout combined;
> server {
> listen 80 default_server;
> server_name example.com www.example.com;
> location / {
> proxy_pass http://127.0.0.1:2368;
> }
> }
> }
> EOF
$ docker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf -p 8080:80 nginx
接着,在其中运行 ghost 容器,增加额定的参数以使其退出到 nginx 容器的命名空间之中。
$ docker run -d --name ghost --net=container:nginx --ipc=container:nginx --pid=container:nginx ghost
当初,nginx 容器能够将本地主机上的申请间接代理到咱们的 ghost 容器,拜访 http://localhost:8080/,可能 … 这些命令创立一组在同一命名空间中运行的容器,在此命名空间中运行的 Docker 容器能够发现彼此并进行通信。
Pod 是某种容器吗?
当初看到能够将 namespace 和 cgroup 与多个过程联合应用,而这,正是 Kubernetes Pods 的实质。Pod 容许指定要运行的容器,Kubernetes 会以正确的形式主动设置 namespace 和 cgroup,然而比上述形式要简单得多,因为 Kubernetes 不应用 Docker 网络(它应用 CNI)
一旦以这种形式设置了容器,每个过程就会“感觉”在同一台机器上运行一样。它们能够在 localhost 上相互通信,能够应用共享卷,甚至能够应用 IPC 或相互发送信号,例如 HUP 或 TERM(在 Kubernetes 1.7 中具备共享的 PID 名称空间,Docker> = 1.13)。
假如当初要运行 nginx 并应用 confd,confd 会在每次增加 / 删除应用程序服务器时更新 nginx 配置并重新启动 nginx。假如有一个 etcd 服务器,其中蕴含后端应用程序服务器的 IP 地址,当列表更改时,confd 能够失去告诉并写出新的 nginx 配置,并向 Nginx 发送 HUP 信号,从而使得 nginx 可能从新加载配置。
仅应用 Docker 时的形式是将 nginx 和 confd 都放在一个容器中,因为 Docker 只有一个入口点,所以须要使两个过程都运行在诸如 supervisor 之类的条件下,这是不太现实的,因为须要应用 supervisord 运行每个 nginx 正本。更重要的是,Docker 仅“理解”supervisord,因为这是 entrypoint,它不理解每个过程,这意味着其余工具无奈通过 Docker API 获取该信息,Nginx 可能会解体,然而 Docker 并不知道。
Kubernetes 借助 Pod 来治理每个过程,从而洞悉每个过程的状态,这样,它能够通过 API 向用户提供相干状态信息,当服务解体时还能够提供重启或自动记录日志等服务。
Pod 是伪装成 API 的容器
通过以这种形式将容器组合到 Pod 中,咱们本质上能够创立其他人能够应用的“API”增加到 Pods 中的容器。从失常的 Web API 角度来看,这不是 API,而是其余 Pod 能够应用的形象 API。
以下面的 nginx + confd 为例,confd 对 nginx 过程无所不知,它所晓得的仅仅只是监督 etcd 中的值并将 HUP 信号发送到过程或运行命令,它运行的应用程序不应该是 nginx,而能够是任意一种应用程序,这样就能够应用 confd 容器镜像和配置,并将其与任意数量不同类型的 Pod 替换。能够在其中执行操作的 pod 通常称为“sidecar(边车)容器”,能够设想一下摩托车上边车的图像。
你还能够设想其余类型的形象,诸如 istio 之类的服务网格能够作为边车固定,无需更改主应用程序即可提供服务路由,遥测和策略执行。也能够应用多个 sidecar,没有什么能够阻止你同时应用 confd sidecar 和 istio sidecar。通过这种形式组合的应用程序,能够构建更加简单和牢靠的零碎,同时使单个 app 放弃简洁。