translate underly into traditional chinese
parent
cb4963b8fa
commit
6b168bced1
|
@ -1,13 +1,13 @@
|
|||
# 底层实现
|
||||
# 底層實現
|
||||
|
||||
Docker 底层的核心技术包括 Linux 上的名字空间(Namespaces)、控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。
|
||||
Docker 底層的核心技術包括 Linux 上的名字空間(Namespaces)、控制組(Control groups)、Union 文件系統(Union file systems)和容器格式(Container format)。
|
||||
|
||||
我们知道,传统的虚拟机通过在宿主主机中运行 hypervisor 来模拟一整套完整的硬件环境提供给虚拟机的操作系统。虚拟机系统看到的环境是可限制的,也是彼此隔离的。
|
||||
这种直接的做法实现了对资源最完整的封装,但很多时候往往意味着系统资源的浪费。
|
||||
例如,以宿主机和虚拟机系统都为 Linux 系统为例,虚拟机中运行的应用其实可以利用宿主机系统中的运行环境。
|
||||
我們知道,傳統的虛擬機通過在宿主主機中運行 hypervisor 來模擬一整套完整的硬件環境提供給虛擬機的操作系統。虛擬機系統看到的環境是可限制的,也是彼此隔離的。
|
||||
這種直接的做法實現了對資源最完整的封裝,但很多時候往往意味著系統資源的浪費。
|
||||
例如,以宿主機和虛擬機系統都為 Linux 系統為例,虛擬機中運行的應用其實可以利用宿主機系統中的運行環境。
|
||||
|
||||
我们知道,在操作系统中,包括内核、文件系统、网络、PID、UID、IPC、内存、硬盘、CPU 等等,所有的资源都是应用进程直接共享的。
|
||||
要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等等的相互隔离。
|
||||
前者相对容易实现一些,后者则需要宿主机系统的深入支持。
|
||||
我們知道,在操作系統中,包括內核、文件系統、網絡、PID、UID、IPC、內存、硬盤、CPU 等等,所有的資源都是應用進程直接共享的。
|
||||
要想實現虛擬化,除了要實現對內存、CPU、網絡IO、硬盤IO、存儲空間等的限制外,還要實現文件系統、網絡、PID、UID、IPC等等的相互隔離。
|
||||
前者相對容易實現一些,後者則需要宿主機系統的深入支持。
|
||||
|
||||
随着 Linux 系统对于名字空间功能的完善实现,程序员已经可以实现上面的所有需求,让某些进程在彼此隔离的名字空间中运行。大家虽然都共用一个内核和某些运行时环境(例如一些系统命令和系统库),但是彼此却看不到,都以为系统中只有自己的存在。这种机制就是容器(Container),利用名字空间来做权限的隔离控制,利用 cgroups 来做资源分配。
|
||||
隨著 Linux 系統對於名字空間功能的完善實現,程序員已經可以實現上面的所有需求,讓某些進程在彼此隔離的名字空間中運行。大家雖然都共用一個內核和某些運行時環境(例如一些系統命令和系統庫),但是彼此卻看不到,都以為系統中只有自己的存在。這種機制就是容器(Container),利用名字空間來做權限的隔離控制,利用 cgroups 來做資源分配。
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
## 基本架构
|
||||
Docker 采用了 C/S架构,包括客户端和服务端。
|
||||
Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。
|
||||
客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。
|
||||
## 基本架構
|
||||
Docker 采用了 C/S架構,包括客戶端和服務端。
|
||||
Docker daemon 作為服務端接受來自客戶的請求,並處理這些請求(創建、運行、分發容器)。
|
||||
客戶端和服務端既可以運行在一個機器上,也可通過 socket 或者 RESTful API 來進行通信。
|
||||
|
||||
![Docker 基本架构](../_images/docker_arch.png)
|
||||
![Docker 基本架構](../_images/docker_arch.png)
|
||||
|
||||
|
||||
Docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。
|
||||
Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker daemon 交互。
|
||||
Docker daemon 一般在宿主主機後臺運行,等待接收來自客戶端的消息。
|
||||
Docker 客戶端則為用戶提供一系列可執行命令,用戶用這些命令實現跟 Docker daemon 交互。
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
## 控制组
|
||||
## 控制組
|
||||
|
||||
控制组([cgroups](http://en.wikipedia.org/wiki/Cgroups))是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。
|
||||
控制組([cgroups](http://en.wikipedia.org/wiki/Cgroups))是 Linux 內核的一個特性,主要用來對共享資源進行隔離、限制、審計等。只有能控制分配到容器的資源,才能避免當多個容器同時運行時的對系統資源的競爭。
|
||||
|
||||
控制组技术最早是由 Google 的程序员 2006 年起提出,Linux 内核自 2.6.24 开始支持。
|
||||
控制組技術最早是由 Google 的程序員 2006 年起提出,Linux 內核自 2.6.24 開始支持。
|
||||
|
||||
控制组可以提供对容器的内存、CPU、磁盘 IO 等资源的限制和审计管理。
|
||||
控制組可以提供對容器的內存、CPU、磁盤 IO 等資源的限制和審計管理。
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## 容器格式
|
||||
最初,Docker 采用了 LXC 中的容器格式。自 1.20 版本开始,Docker 也开始支持新的 [libcontainer](https://github.com/docker/libcontainer) 格式,并作为默认选项。
|
||||
最初,Docker 采用了 LXC 中的容器格式。自 1.20 版本開始,Docker 也開始支持新的 [libcontainer](https://github.com/docker/libcontainer) 格式,並作為默認選項。
|
||||
|
||||
对更多容器格式的支持,还在进一步的发展中。
|
||||
對更多容器格式的支持,還在進一步的發展中。
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
## 名字空间
|
||||
名字空间是 Linux 内核一个强大的特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。
|
||||
## 名字空間
|
||||
名字空間是 Linux 內核一個強大的特性。每個容器都有自己單獨的名字空間,運行在其中的應用都像是在獨立的操作系統中運行一樣。名字空間保證了容器之間彼此互不影響。
|
||||
|
||||
### pid 名字空间
|
||||
不同用户的进程就是通过 pid 名字空间隔离开的,且不同名字空间中可以有相同 pid。所有的 LXC 进程在 Docker 中的父进程为Docker进程,每个 LXC 进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。
|
||||
### pid 名字空間
|
||||
不同用戶的進程就是通過 pid 名字空間隔離開的,且不同名字空間中可以有相同 pid。所有的 LXC 進程在 Docker 中的父進程為Docker進程,每個 LXC 進程具有不同的名字空間。同時由於允許嵌套,因此可以很方便的實現嵌套的 Docker 容器。
|
||||
|
||||
### net 名字空间
|
||||
有了 pid 名字空间, 每个名字空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 名字空间实现的, 每个 net 名字空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。
|
||||
### net 名字空間
|
||||
有了 pid 名字空間, 每個名字空間中的 pid 能夠相互隔離,但是網絡端口還是共享 host 的端口。網絡隔離是通過 net 名字空間實現的, 每個 net 名字空間有獨立的 網絡設備, IP 地址, 路由表, /proc/net 目錄。這樣每個容器的網絡就能隔離開來。Docker 默認采用 veth 的方式,將容器中的虛擬網卡同 host 上的一 個Docker 網橋 docker0 連接在一起。
|
||||
|
||||
### ipc 名字空间
|
||||
容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 名字空间中的进程间交互,因此需要在 IPC 资源申请时加入名字空间信息,每个 IPC 资源有一个唯一的 32 位 id。
|
||||
### ipc 名字空間
|
||||
容器中進程交互還是采用了 Linux 常見的進程間交互方法(interprocess communication - IPC), 包括信號量、消息隊列和共享內存等。然而同 VM 不同的是,容器的進程間交互實際上還是 host 上具有相同 pid 名字空間中的進程間交互,因此需要在 IPC 資源申請時加入名字空間信息,每個 IPC 資源有一個唯一的 32 位 id。
|
||||
|
||||
### mnt 名字空间
|
||||
类似 chroot,将一个进程放到一个特定的目录执行。mnt 名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个名字空间中的容器在 /proc/mounts 的信息只包含所在名字空间的 mount point。
|
||||
### mnt 名字空間
|
||||
類似 chroot,將一個進程放到一個特定的目錄執行。mnt 名字空間允許不同名字空間的進程看到的文件結構不同,這樣每個名字空間 中的進程所看到的文件目錄就被隔離開了。同 chroot 不同,每個名字空間中的容器在 /proc/mounts 的信息只包含所在名字空間的 mount point。
|
||||
|
||||
### uts 名字空间
|
||||
UTS("UNIX Time-sharing System") 名字空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。
|
||||
### uts 名字空間
|
||||
UTS("UNIX Time-sharing System") 名字空間允許每個容器擁有獨立的 hostname 和 domain name, 使其在網絡上可以被視作一個獨立的節點而非 主機上的一個進程。
|
||||
|
||||
### user 名字空间
|
||||
每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。
|
||||
### user 名字空間
|
||||
每個容器可以有不同的用戶和組 id, 也就是說可以在容器內用容器內部的用戶執行程序而非主機上的用戶。
|
||||
|
||||
*注:关于 Linux 上的名字空间,[这篇文章](http://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/) 介绍的很好。
|
||||
*註:關於 Linux 上的名字空間,[這篇文章](http://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/) 介紹的很好。
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
## Docker 网络实现
|
||||
## Docker 網絡實現
|
||||
|
||||
Docker 的网络实现其实就是利用了 Linux 上的网络名字空间和虚拟网络设备(特别是 veth pair)。建议先熟悉了解这两部分的基本概念再阅读本章。
|
||||
Docker 的網絡實現其實就是利用了 Linux 上的網絡名字空間和虛擬網絡設備(特別是 veth pair)。建議先熟悉了解這兩部分的基本概念再閱讀本章。
|
||||
|
||||
### 基本原理
|
||||
首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。
|
||||
首先,要實現網絡通信,機器需要至少一個網絡接口(物理接口或虛擬接口)來收發數據包;此外,如果不同子網之間要進行通信,需要路由機制。
|
||||
|
||||
Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。
|
||||
Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统看来就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要快很多。
|
||||
Docker 中的網絡接口默認都是虛擬的接口。虛擬接口的優勢之一是轉發效率較高。
|
||||
Linux 通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,發送接口的發送緩存中的數據包被直接復制到接收接口的接收緩存中。對於本地系統和容器內系統看來就像是一個正常的以太網卡,只是它不需要真正同外部網絡設備通信,速度要快很多。
|
||||
|
||||
Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 `veth pair`)。
|
||||
Docker 容器網絡就利用了這項技術。它在本地主機和容器內分別創建一個虛擬接口,並讓它們彼此連通(這樣的一對接口叫做 `veth pair`)。
|
||||
|
||||
### 创建网络参数
|
||||
Docker 创建一个容器的时候,会执行如下操作:
|
||||
* 创建一对虚拟接口,分别放到本地主机和新容器中;
|
||||
* 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;
|
||||
* 容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的名字空间可见;
|
||||
* 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。
|
||||
### 創建網絡參數
|
||||
Docker 創建一個容器的時候,會執行如下操作:
|
||||
* 創建一對虛擬接口,分別放到本地主機和新容器中;
|
||||
* 本地主機一端橋接到默認的 docker0 或指定網橋上,並具有一個唯一的名字,如 veth65f9;
|
||||
* 容器一端放到新容器中,並修改名字作為 eth0,這個接口只在容器的名字空間可見;
|
||||
* 從網橋可用地址段中獲取一個空閑地址分配給容器的 eth0,並配置默認路由到橋接網卡 veth65f9。
|
||||
|
||||
完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。
|
||||
完成這些之後,容器就可以使用 eth0 虛擬網卡來連接其他容器和其他網絡。
|
||||
|
||||
可以在 `docker run` 的时候通过 `--net` 参数来指定容器的网络配置,有4个可选值:
|
||||
* `--net=bridge` 这个是默认值,连接到默认的网桥。
|
||||
* `--net=host` 告诉 Docker 不要将容器网络放到隔离的名字空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用 `--privileged=true`,容器会被允许直接配置主机的网络堆栈。
|
||||
* `--net=container:NAME_or_ID` 让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过 `lo` 环回接口通信。
|
||||
* `--net=none` 让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。
|
||||
可以在 `docker run` 的時候通過 `--net` 參數來指定容器的網絡配置,有4個可選值:
|
||||
* `--net=bridge` 這個是默認值,連接到默認的網橋。
|
||||
* `--net=host` 告訴 Docker 不要將容器網絡放到隔離的名字空間中,即不要容器化容器內的網絡。此時容器使用本地主機的網絡,它擁有完全的本地主機接口訪問權限。容器進程可以跟主機其它 root 進程一樣可以打開低範圍的端口,可以訪問本地網絡服務比如 D-bus,還可以讓容器做一些影響整個主機系統的事情,比如重啟主機。因此使用這個選項的時候要非常小心。如果進一步的使用 `--privileged=true`,容器會被允許直接配置主機的網絡堆棧。
|
||||
* `--net=container:NAME_or_ID` 讓 Docker 將新建容器的進程放到一個已存在容器的網絡棧中,新容器進程有自己的文件系統、進程列表和資源限制,但會和已存在的容器共享 IP 地址和端口等網絡資源,兩者進程可以直接通過 `lo` 環回接口通信。
|
||||
* `--net=none` 讓 Docker 將新容器放到隔離的網絡棧中,但是不進行網絡配置。之後,用戶可以自己進行配置。
|
||||
|
||||
### 网络配置细节
|
||||
用户使用 `--net=none` 后,可以自行配置网络,让容器达到跟平常一样具有访问网络的权限。通过这个过程,可以了解 Docker 配置网络的细节。
|
||||
### 網絡配置細節
|
||||
用戶使用 `--net=none` 後,可以自行配置網絡,讓容器達到跟平常一樣具有訪問網絡的權限。通過這個過程,可以了解 Docker 配置網絡的細節。
|
||||
|
||||
首先,启动一个 `/bin/bash` 容器,指定 `--net=none` 参数。
|
||||
首先,啟動一個 `/bin/bash` 容器,指定 `--net=none` 參數。
|
||||
```
|
||||
$ sudo docker run -i -t --rm --net=none base /bin/bash
|
||||
root@63f36fc01b5f:/#
|
||||
```
|
||||
在本地主机查找容器的进程 id,并为它创建网络命名空间。
|
||||
在本地主機查找容器的進程 id,並為它創建網絡命名空間。
|
||||
```
|
||||
$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
|
||||
2778
|
||||
|
@ -41,20 +41,20 @@ $ pid=2778
|
|||
$ sudo mkdir -p /var/run/netns
|
||||
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
|
||||
```
|
||||
检查桥接网卡的 IP 和子网掩码信息。
|
||||
檢查橋接網卡的 IP 和子網掩碼信息。
|
||||
```
|
||||
$ ip addr show docker0
|
||||
21: docker0: ...
|
||||
inet 172.17.42.1/16 scope global docker0
|
||||
...
|
||||
```
|
||||
创建一对 “veth pair” 接口 A 和 B,绑定 A 到网桥 `docker0`,并启用它
|
||||
創建一對 “veth pair” 接口 A 和 B,綁定 A 到網橋 `docker0`,並啟用它
|
||||
```
|
||||
$ sudo ip link add A type veth peer name B
|
||||
$ sudo brctl addif docker0 A
|
||||
$ sudo ip link set A up
|
||||
```
|
||||
将B放到容器的网络命名空间,命名为 eth0,启动它并配置一个可用 IP(桥接网段)和默认网关。
|
||||
將B放到容器的網絡命名空間,命名為 eth0,啟動它並配置一個可用 IP(橋接網段)和默認網關。
|
||||
```
|
||||
$ sudo ip link set B netns $pid
|
||||
$ sudo ip netns exec $pid ip link set dev B name eth0
|
||||
|
@ -62,8 +62,8 @@ $ sudo ip netns exec $pid ip link set eth0 up
|
|||
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
|
||||
$ sudo ip netns exec $pid ip route add default via 172.17.42.1
|
||||
```
|
||||
以上,就是 Docker 配置网络的具体过程。
|
||||
以上,就是 Docker 配置網絡的具體過程。
|
||||
|
||||
当容器结束后,Docker 会清空容器,容器内的 eth0 会随网络命名空间一起被清除,A 接口也被自动从 `docker0` 卸载。
|
||||
當容器結束後,Docker 會清空容器,容器內的 eth0 會隨網絡命名空間一起被清除,A 接口也被自動從 `docker0` 卸載。
|
||||
|
||||
此外,用户可以使用 `ip netns exec` 命令来在指定网络名字空间中进行配置,从而配置容器内的网络。
|
||||
此外,用戶可以使用 `ip netns exec` 命令來在指定網絡名字空間中進行配置,從而配置容器內的網絡。
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
## Union 文件系统
|
||||
Union文件系统([UnionFS](http://en.wikipedia.org/wiki/UnionFS))是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。
|
||||
## Union 文件系統
|
||||
Union文件系統([UnionFS](http://en.wikipedia.org/wiki/UnionFS))是一種分層、輕量級並且高性能的文件系統,它支持對文件系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下(unite several directories into a single virtual filesystem)。
|
||||
|
||||
Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
|
||||
Union 文件系統是 Docker 鏡像的基礎。鏡像可以通過分層來進行繼承,基於基礎鏡像(沒有父鏡像),可以制作各種具體的應用鏡像。
|
||||
|
||||
另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
|
||||
另外,不同 Docker 容器就可以共享一些基礎的文件系統層,同時再加上自己獨有的改動層,大大提高了存儲的效率。
|
||||
|
||||
Docker 中使用的 AUFS(AnotherUnionFS)就是一种 Union FS。 AUFS 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 AUFS 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。
|
||||
Docker 中使用的 AUFS(AnotherUnionFS)就是一種 Union FS。 AUFS 支持為每一個成員目錄(類似 Git 的分支)設定只讀(readonly)、讀寫(readwrite)和寫出(whiteout-able)權限, 同時 AUFS 裏有一個類似分層的概念, 對只讀權限的分支可以邏輯上進行增量地修改(不影響只讀部分的)。
|
||||
|
||||
Docker 目前支持的 Union 文件系统种类包括 AUFS, btrfs, vfs 和 DeviceMapper。
|
||||
Docker 目前支持的 Union 文件系統種類包括 AUFS, btrfs, vfs 和 DeviceMapper。
|
||||
|
|
Loading…
Reference in New Issue