# CNI - Container Network Interface(容器網絡接口)
CNI(Container Network Interface)是CNCF旗下的一個項目,由一組用于配置Linux容器的網絡接口的規范和庫組成,同時還包含了一些插件。CNI僅關心容器創建時的網絡分配,和當容器被刪除時釋放網絡資源。通過此鏈接瀏覽該項目:<https://github.com/containernetworking/cni>。
Kubernetes源碼的`vendor/github.com/containernetworking/cni/libcni`目錄中已經包含了CNI的代碼,也就是說kubernetes中已經內置了CNI。
## 接口定義
CNI的接口中包括以下幾個方法:
```go
type CNI interface {
AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
DelNetwork(net *NetworkConfig, rt *RuntimeConf) error
}
```
該接口只有四個方法,添加網絡、刪除網絡、添加網絡列表、刪除網絡列表。
## 設計考量
CNI設計的時候考慮了以下問題:
- 容器運行時必須在調用任何插件之前為容器創建一個新的網絡命名空間。
- 然后,運行時必須確定這個容器應屬于哪個網絡,并為每個網絡確定哪些插件必須被執行。
- 網絡配置采用JSON格式,可以很容易地存儲在文件中。網絡配置包括必填字段,如`name`和`type`以及插件(類型)。網絡配置允許字段在調用之間改變值。為此,有一個可選的字段`args`,必須包含不同的信息。
- 容器運行時必須按順序為每個網絡執行相應的插件,將容器添加到每個網絡中。
- 在完成容器生命周期后,運行時必須以相反的順序執行插件(相對于執行添加容器的順序)以將容器與網絡斷開連接。
- 容器運行時不能為同一容器調用并行操作,但可以為不同的容器調用并行操作。
- 容器運行時必須為容器訂閱ADD和DEL操作,這樣ADD后面總是跟著相應的DEL。 DEL可能跟著額外的DEL,但是,插件應該允許處理多個DEL(即插件DEL應該是冪等的)。
- 容器必須由ContainerID唯一標識。存儲狀態的插件應該使用(網絡名稱,容器ID)的主鍵來完成。
- 運行時不能調用同一個網絡名稱或容器ID執行兩次ADD(沒有相應的DEL)。換句話說,給定的容器ID必須只能添加到特定的網絡一次。
## CNI插件
CNI插件必須實現一個可執行文件,這個文件可以被容器管理系統(例如rkt或Kubernetes)調用。
CNI插件負責將網絡接口插入容器網絡命名空間(例如,veth對的一端),并在主機上進行任何必要的改變(例如將veth的另一端連接到網橋)。然后將IP分配給接口,并通過調用適當的IPAM插件來設置與“IP地址管理”部分一致的路由。
### 參數
CNI插件必須支持以下操作:
#### 將容器添加到網絡
參數:
- **版本**。調用者正在使用的CNI規范(容器管理系統或調用插件)的版本。
- **容器ID **。由運行時分配的容器的唯一明文標識符。一定不能是空的。
- **網絡命名空間路徑**。要添加的網絡名稱空間的路徑,即`/proc/[pid]/ns/net`或綁定掛載/鏈接。
- **網絡配置**。描述容器可以加入的網絡的JSON文檔。架構如下所述。
- **額外的參數**。這提供了一個替代機制,允許在每個容器上簡單配置CNI插件。
- **容器內接口的名稱**。這是應該分配給容器(網絡命名空間)內創建的接口的名稱;因此它必須符合Linux接口名稱上的標準限制。
結果:
- **接口列表**。根據插件的不同,這可以包括沙箱(例如容器或管理程序)接口名稱和/或主機接口名稱,每個接口的硬件地址以及接口所在的沙箱(如果有的話)的詳細信息。
- **分配給每個接口的IP配置**。分配給沙箱和/或主機接口的IPv4和/或IPv6地址,網關和路由。
- **DNS信息**。包含nameserver、domain、search domain和option的DNS信息的字典。
#### 從網絡中刪除容器
參數:
- **版本**。調用者正在使用的CNI規范(容器管理系統或調用插件)的版本。
- **容器ID **,如上所述。
- **網絡命名空間路徑**,如上定義。
- **網絡配置**,如上所述。
- **額外的參數**,如上所述。
- **上面定義的容器**內的接口的名稱。
- 所有參數應與傳遞給相應的添加操作的參數相同。
- 刪除操作應釋放配置的網絡中提供的containerid擁有的所有資源。
報告版本
- 參數:無。
- 結果:插件支持的CNI規范版本信息。
```json
{
“cniVersion”:“0.3.1”,//此輸出使用的CNI規范的版本
“supportedVersions”:[“0.1.0”,“0.2.0”,“0.3.0”,“0.3.1”] //此插件支持的CNI規范版本列表
}
```
CNI插件的詳細說明請參考:[CNI SPEC](https://github.com/containernetworking/cni/blob/master/SPEC.md)。
### IP分配
作為容器網絡管理的一部分,CNI插件需要為接口分配(并維護)IP地址,并安裝與該接口相關的所有必要路由。這給了CNI插件很大的靈活性,但也給它帶來了很大的負擔。眾多的CNI插件需要編寫相同的代碼來支持用戶需要的多種IP管理方案(例如dhcp、host-local)。
為了減輕負擔,使IP管理策略與CNI插件類型解耦,我們定義了IP地址管理插件(IPAM插件)。CNI插件的職責是在執行時恰當地調用IPAM插件。 IPAM插件必須確定接口IP/subnet,網關和路由,并將此信息返回到“主”插件來應用配置。 IPAM插件可以通過協議(例如dhcp)、存儲在本地文件系統上的數據、網絡配置文件的“ipam”部分或上述的組合來獲得信息。
#### IPAM插件
像CNI插件一樣,調用IPAM插件的可執行文件。可執行文件位于預定義的路徑列表中,通過`CNI_PATH`指示給CNI插件。 IPAM插件必須接收所有傳入CNI插件的相同環境變量。就像CNI插件一樣,IPAM插件通過stdin接收網絡配置。
## 可用插件
### Main:接口創建
- **bridge**:創建網橋,并添加主機和容器到該網橋
- **ipvlan**:在容器中添加一個[ipvlan](https://www.kernel.org/doc/Documentation/networking/ipvlan.txt)接口
- **loopback**:創建一個回環接口
- **macvlan**:創建一個新的MAC地址,將所有的流量轉發到容器
- **ptp**:創建veth對
- **vlan**:分配一個vlan設備
### IPAM:IP地址分配
- **dhcp**:在主機上運行守護程序,代表容器發出DHCP請求
- **host-local**:維護分配IP的本地數據庫
### Meta:其它插件
- **flannel**:根據flannel的配置文件創建接口
- **tuning**:調整現有接口的sysctl參數
- **portmap**:一個基于iptables的portmapping插件。將端口從主機的地址空間映射到容器。
## 參考
- https://github.com/containernetworking/cni
- https://github.com/containernetworking/plugins
- [Container Networking Interface Specification](https://github.com/containernetworking/cni/blob/master/SPEC.md#container-networking-interface-specification)
- [CNI Extension conventions](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md)
- 序言
- 云原生
- 云原生(Cloud Native)的定義
- CNCF - 云原生計算基金會簡介
- CNCF章程
- 云原生的設計哲學
- Play with Kubernetes
- 快速部署一個云原生本地實驗環境
- Kubernetes與云原生應用概覽
- 云原生應用之路——從Kubernetes到Cloud Native
- 云原生編程語言
- 云原生編程語言Ballerina
- 云原生編程語言Pulumi
- 云原生的未來
- Kubernetes架構
- 設計理念
- Etcd解析
- 開放接口
- CRI - Container Runtime Interface(容器運行時接口)
- CNI - Container Network Interface(容器網絡接口)
- CSI - Container Storage Interface(容器存儲接口)
- Kubernetes中的網絡
- Kubernetes中的網絡解析——以flannel為例
- Kubernetes中的網絡解析——以calico為例
- 具備API感知的網絡和安全性管理開源軟件Cilium
- Cilium架構設計與概念解析
- 資源對象與基本概念解析
- Pod狀態與生命周期管理
- Pod概覽
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中斷與PDB(Pod中斷預算)
- 集群資源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污點和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定義指標HPA
- 準入控制器(Admission Controller)
- 服務發現
- Service
- Ingress
- Traefik Ingress Controller
- 身份與權限控制
- ServiceAccount
- RBAC——基于角色的訪問控制
- NetworkPolicy
- 存儲
- Secret
- ConfigMap
- ConfigMap的熱更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存儲
- 集群擴展
- 使用自定義資源擴展API
- 使用CRD擴展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 資源調度
- QoS(服務質量等級)
- 用戶指南
- 資源對象配置
- 配置Pod的liveness和readiness探針
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的資源配額
- 命令使用
- Docker用戶過度到kubectl命令行指南
- kubectl命令概覽
- kubectl命令技巧大全
- 使用etcdctl訪問kubernetes數據
- 集群安全性管理
- 管理集群中的TLS
- kubelet的認證授權
- TLS bootstrap
- 創建用戶認證授權的kubeconfig文件
- IP偽裝代理
- 使用kubeconfig或token進行用戶身份認證
- Kubernetes中的用戶與身份認證授權
- Kubernetes集群安全性配置最佳實踐
- 訪問Kubernetes集群
- 訪問集群
- 使用kubeconfig文件配置跨集群認證
- 通過端口轉發訪問集群中的應用程序
- 使用service訪問群集中的應用程序
- 從外部訪問Kubernetes中的Pod
- Cabin - Kubernetes手機客戶端
- Kubernetic - Kubernetes桌面客戶端
- Kubernator - 更底層的Kubernetes UI
- 在Kubernetes中開發部署應用
- 適用于kubernetes的應用開發部署流程
- 遷移傳統應用到Kubernetes中——以Hadoop YARN為例
- 最佳實踐概覽
- 在CentOS上部署Kubernetes集群
- 創建TLS證書和秘鑰
- 創建kubeconfig文件
- 創建高可用etcd集群
- 安裝kubectl命令行工具
- 部署master節點
- 安裝flannel網絡插件
- 部署node節點
- 安裝kubedns插件
- 安裝dashboard插件
- 安裝heapster插件
- 安裝EFK插件
- 生產級的Kubernetes簡化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速構建測試集群
- 服務發現與負載均衡
- 安裝Traefik ingress
- 分布式負載測試
- 網絡和集群性能測試
- 邊緣節點配置
- 安裝Nginx ingress
- 安裝配置DNS
- 安裝配置Kube-dns
- 安裝配置CoreDNS
- 運維管理
- Master節點高可用
- 服務滾動升級
- 應用日志收集
- 配置最佳實踐
- 集群及應用監控
- 數據持久化問題
- 管理容器的計算資源
- 集群聯邦
- 存儲管理
- GlusterFS
- 使用GlusterFS做持久化存儲
- 使用Heketi作為Kubernetes的持久存儲GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存儲
- GlusterD-2.0
- Ceph
- 用Helm托管安裝Ceph集群并提供后端存儲
- 使用Ceph做持久化存儲
- 使用rbd-provisioner提供rbd持久化存儲
- OpenEBS
- 使用OpenEBS做持久化存儲
- Rook
- NFS
- 利用NFS動態提供Kubernetes后端存儲卷
- 集群與應用監控
- Heapster
- 使用Heapster獲取集群和對象的metric數據
- Prometheus
- 使用Prometheus監控kubernetes集群
- Prometheus查詢語言PromQL使用說明
- 使用Vistio監控Istio服務網格中的流量
- 分布式跟蹤
- OpenTracing
- 服務編排管理
- 使用Helm管理Kubernetes應用
- 構建私有Chart倉庫
- 持續集成與發布
- 使用Jenkins進行持續集成與發布
- 使用Drone進行持續集成與發布
- 更新與升級
- 手動升級Kubernetes集群
- 升級dashboard
- 領域應用概覽
- 微服務架構
- 微服務中的服務發現
- 使用Java構建微服務并發布到Kubernetes平臺
- Spring Boot快速開始指南
- Service Mesh 服務網格
- 企業級服務網格架構
- Service Mesh基礎
- Service Mesh技術對比
- 采納和演進
- 定制和集成
- 總結
- Istio
- 安裝并試用Istio service mesh
- 配置請求的路由規則
- 安裝和拓展Istio service mesh
- 集成虛擬機
- Istio中sidecar的注入規范及示例
- 如何參與Istio社區及注意事項
- Istio教程
- Istio免費學習資源匯總
- 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由轉發
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概覽
- 安裝Conduit
- Envoy
- Envoy的架構與基本術語
- Envoy作為前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 構建 SOFAMesh
- 大數據
- Spark standalone on Kubernetes
- 運行支持Kubernetes原生調度的Spark程序
- Serverless架構
- 理解Serverless
- FaaS-函數即服務
- OpenFaaS快速入門指南
- 邊緣計算
- 人工智能