# 云原生應用之路——從Kubernetes到Cloud Native
**從Kubernetes到Cloud Native——云原生應用之路**,這是我最近在 [ArchSummit2017北京站](http://bj2017.archsummit.com/presentation/306) 和 [數人云&TalkingData合辦的Service Mesh is coming meetup](https://www.kubernetes.org.cn/3211.html) 中分享的話題。
本文簡要介紹了容器技術發展的路徑,為何Kubernetes的出現是容器技術發展到這一步的必然選擇,而為何Kubernetes又將成為云原生應用的基石。
我的分享按照這樣的主線展開:容器->Kubernetes->微服務->Cloud Native(云原生)->Service Mesh(服務網格)->使用場景->Open Source(開源)。
## 容器
> 容器——Cloud Native的基石
容器最初是通過開發者工具而流行,可以使用它來做隔離的開發測試環境和持續集成環境,這些都是因為容器輕量級,易于配置和使用帶來的優勢,docker和docker-compose這樣的工具極大的方便的了應用開發環境的搭建,開發者就像是化學家一樣在其中小心翼翼的進行各種調試和開發。
隨著容器的在開發者中的普及,已經大家對CI流程的熟悉,容器周邊的各種工具蓬勃發展,儼然形成了一個小生態,在2016年達到頂峰,下面這張是我畫的容器生態圖:

該生態涵蓋了容器應用中從鏡像倉庫、服務編排、安全管理、持續集成與發布、存儲和網絡管理等各個方面,隨著在單主機中運行容器的成熟,集群管理和容器編排成為容器技術亟待解決的問題。譬如化學家在實驗室中研究出來的新產品,如何推向市場,進行大規模生產,成了新的議題。
## 為什么使用Kubernetes
> Kubernetes——讓容器應用進入大規模工業生產。
**Kubernetes是容器編排系統的事實標準**
在單機上運行容器,無法發揮它的最大效能,只有形成集群,才能最大程度發揮容器的良好隔離、資源分配與編排管理的優勢,而對于容器的編排管理,Swarm、Mesos和Kubernetes的大戰已經基本宣告結束,Kubernetes成為了無可爭議的贏家。
下面這張圖是Kubernetes的架構圖(圖片來自網絡),其中顯示了組件之間交互的接口CNI、CRI、OCI等,這些將Kubernetes與某款具體產品解耦,給用戶最大的定制程度,使得Kubernetes有機會成為跨云的真正的云原生應用的操作系統。

隨著Kubernetes的日趨成熟,“Kubernetes is becoming boring”,基于該“操作系統”之上構建的適用于不同場景的應用將成為新的發展方向,就像我們將石油開采出來后,提煉出汽油、柴油、瀝青等等,所有的材料都將找到自己的用途,Kubernetes也是,畢竟我們誰也不是為了部署和管理容器而用Kubernetes,承載其上的應用才是價值之所在。
**云原生的核心目標**

云已經可以為我們提供穩定可以唾手可得的基礎設施,但是業務上云成了一個難題,Kubernetes的出現與其說是從最初的容器編排解決方案,倒不如說是為了解決應用上云(即云原生應用)這個難題。
包括微服務和FaaS/Serverless架構,都可以作為云原生應用的架構。

但就2017年為止,Kubernetes的主要使用場景也主要作為應用開發測試環境、CI/CD和運行Web應用這幾個領域,如下圖[TheNewStack](http://thenewstack.io)的Kubernetes生態狀況調查報告所示。

另外基于Kubernetes的構建PaaS平臺和Serverless也處于爆發的準備的階段,如下圖中Gartner的報告中所示:

當前各大公有云如Google GKE、微軟Azure ACS、亞馬遜EKS(2018年上線)、VMWare、Pivotal、騰訊云、阿里云等都提供了Kubernetes服務。
## 微服務
> 微服務——Cloud Native的應用架構。
下圖是[Bilgin Ibryam](https://developers.redhat.com/blog/author/bibryam/)給出的微服務中應該關心的主題,圖片來自[RedHat Developers](https://developers.redhat.com/blog/2016/12/09/spring-cloud-for-microservices-compared-to-kubernetes/)。

微服務帶給我們很多開發和部署上的靈活性和技術多樣性,但是也增加了服務調用的開銷、分布式系統管理、調試與服務治理方面的難題。
當前最成熟最完整的微服務框架可以說非[Spring](https://spring.io/)莫屬,而Spring又僅限于Java語言開發,其架構本身又跟Kubernetes存在很多重合的部分,如何探索將Kubernetes作為微服務架構平臺就成為一個熱點話題。
就拿微服務中最基礎的**服務注冊發現**功能來說,其方式分為**客戶端服務發現**和**服務端服務發現**兩種,Java應用中常用的方式是使用Eureka和Ribbon做服務注冊發現和負載均衡,這屬于客戶端服務發現,而在Kubernetes中則可以使用DNS、Service和Ingress來實現,不需要修改應用代碼,直接從網絡層面來實現。

## Cloud Native
> DevOps——通向云原生的云梯
CNCF(云原生計算基金會)給出了云原生應用的三大特征:
- **容器化包裝**:軟件應用的進程應該包裝在容器中獨立運行。
- **動態管理**:通過集中式的編排調度系統來動態的管理和調度。
- **微服務化**:明確服務間的依賴,互相解耦。
下圖是我整理的關于云原生所需要的能力和特征。

[CNCF](https://cncf.io)所托管的應用(目前已達12個),即朝著這個目標發展,其公布的[Cloud Native Landscape](https://github.com/cncf/landscape),給出了云原生生態的參考體系。

**使用Kubernetes構建云原生應用**
我們都是知道Heroku推出了適用于PaaS的[12 factor app](https://12factor.net/)的規范,包括如下要素:
1. 基準代碼
2. 依賴管理
3. 配置
4. 后端服務
5. 構建,發布,運行
6. 無狀態進程
7. 端口綁定
8. 并發
9. 易處理
10. 開發環境與線上環境等價
11. 日志作為事件流
12. 管理進程
另外還有補充的三點:
- API聲明管理
- 認證和授權
- 監控與告警
如果落實的具體的工具,請看下圖,使用Kubernetes構建云原生架構:

結合這12因素對開發或者改造后的應用適合部署到Kubernetes之上,基本流程如下圖所示:

**遷移到云架構**
遷移到云端架構,相對單體架構來說會帶來很多挑戰。比如自動的持續集成與發布、服務監控的變革、服務暴露、權限的管控等。這些具體細節請參考**Kubernetes-handbook**中的說明:<https://jimmysong.io/kubernetes-handbook>,在此就不細節展開,另外推薦一本我翻譯的由Pivotal出品的電子書——[Migrating to Cloud Native Application Architectures](https://content.pivotal.io/ebooks/migrating-to-cloud-native-application-architectures),地址:<https://jimmysong.io/migrating-to-cloud-native-application-architectures/>。
## Service Mesh
> Services for show, meshes for a pro.
Kubernetes中的應用將作為微服務運行,但是Kubernetes本身并沒有給出微服務治理的解決方案,比如服務的限流、熔斷、良好的灰度發布支持等。
**Service Mesh可以用來做什么**
- Traffic Management:API網關
- Observability:服務調用和性能分析
- Policy Enforcment:控制服務訪問策略
- Service Identity and Security:安全保護
**Service Mesh的特點**
- 專用的基礎設施層
- 輕量級高性能網絡代理
- 提供安全的、快速的、可靠地服務間通訊
- 擴展kubernetes的應用負載均衡機制,實現灰度發布
- 完全解耦于應用,應用可以無感知,加速應用的微服務和云原生轉型
使用Service Mesh將可以有效的治理Kubernetes中運行的服務,當前開源的Service Mesh有:
- Linkderd:<https://linkerd.io>,由最早提出Service Mesh的公司[Buoyant](https://buoyant.io)開源,創始人來自Twitter
- Envoy:<https://www.envoyproxy.io/>,Lyft開源的,可以在Istio中使用Sidecar模式運行
- Istio:<https://istio.io>,由Google、IBM、Lyft聯合開發并開源
- Conduit:<https://conduit.io>,同樣由Buoyant開源的輕量級的基于Kubernetes的Service Mesh
此外還有很多其它的Service Mesh魚貫而出,請參考[awesome-cloud-native](https://jimmysong.io/awesome-cloud-native)。
**Istio VS Linkerd**
Linkerd和Istio是最早開源的Service Mesh,它們都支持Kubernetes,下面是它們之間的一些特性對比。
| **Feature** | **Istio** | **Linkerd** |
| ----------- | ------------- | ---------------------------- |
| 部署架構 | Envoy/Sidecar | DaemonSets |
| 易用性 | 復雜 | 簡單 |
| 支持平臺 | Kubernetes | Kubernetes/Mesos/Istio/Local |
| 當前版本 | 0.8 | 1.4.3 |
| 是否已有生產部署 | 否 | 是 |
關于兩者的架構可以參考各自的官方文檔,我只從其在Kubernetes上的部署結構來說明其區別。

Istio的組件復雜,可以分別部署在Kubernetes集群中,但是作為核心路由組件**Envoy**是以**Sidecar**形式與應用運行在同一個Pod中的,所有進入該Pod中的流量都需要先經過Envoy。
Linker的部署十分簡單,本身就是一個鏡像,使用Kubernetes的[DaemonSet](https://jimmysong.io/kubernetes-handbook/concepts/daemonset.html)方式在每個node節點上運行。
更多信息請參考[kubernetes-handbook](https://jimmysong.io/kubernetes-handbook)。
## 使用場景
> Cloud Native的大規模工業生產
**GitOps**
給開發者帶來最大的配置和上線的靈活性,踐行DevOps流程,改善研發效率,下圖這樣的情況將更少發生。

我們知道Kubernetes中的所有應用的部署都是基于YAML文件的,這實際上就是一種**Infrastructure as code**,完全可以通過Git來管控基礎設施和部署環境的變更。
**Big Data**
Spark現在已經非官方支持了基于Kubernetes的原生調度,其具有以下特點:
- Kubernetes原生調度:與yarn、mesos同級
- 資源隔離,粒度更細:以namespace來劃分用戶
- 監控的變革:單次任務資源計量
- 日志的變革:pod的日志收集
| **Feature** | **Yarn** | **Kubernetes** |
| ------------- | ---------------- | -------------- |
| queue | queue | namespace |
| instance | ExcutorContainer | Executor Pod |
| network | host | plugin |
| heterogeneous | no | yes |
| security | RBAC | ACL |
下圖是在Kubernetes上運行三種調度方式的spark的單個節點的應用部分對比:

從上圖中可以看到在Kubernetes上使用YARN調度、standalone調度和Kubernetes原生調度的方式,每個node節點上的Pod內的Spark Executor分布,毫無疑問,使用Kubernetes原生調度的Spark任務才是最節省資源的。
提交任務的語句看起來會像是這樣的:
```bash
./spark-submit \
--deploy-mode cluster \
--class com.talkingdata.alluxio.hadooptest \
--master k8s://https://172.20.0.113:6443 \
--kubernetes-namespace spark-cluster \
--conf spark.kubernetes.driverEnv.SPARK_USER=hadoop \
--conf spark.kubernetes.driverEnv.HADOOP_USER_NAME=hadoop \
--conf spark.executorEnv.HADOOP_USER_NAME=hadoop \
--conf spark.executorEnv.SPARK_USER=hadoop \
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
--conf spark.driver.memory=100G \
--conf spark.executor.memory=10G \
--conf spark.driver.cores=30 \
--conf spark.executor.cores=2 \
--conf spark.driver.maxResultSize=10240m \
--conf spark.kubernetes.driver.limit.cores=32 \
--conf spark.kubernetes.executor.limit.cores=3 \
--conf spark.kubernetes.executor.memoryOverhead=2g \
--conf spark.executor.instances=5 \
--conf spark.app.name=spark-pi \
--conf spark.kubernetes.driver.docker.image=spark-driver:v2.1.0-kubernetes-0.3.1-1 \
--conf spark.kubernetes.executor.docker.image=spark-executor:v2.1.0-kubernetes-0.3.1-1 \
--conf spark.kubernetes.initcontainer.docker.image=spark-init:v2.1.0-kubernetes-0.3.1-1 \
--conf spark.kubernetes.resourceStagingServer.uri=http://172.20.0.114:31000 \
~/Downloads/tendcloud_2.10-1.0.jar
```
關于支持Kubernetes原生調度的Spark請參考:https://jimmysong.io/spark-on-k8s/
## Open Source
> Contributing is Not only about code, it is about helping a community.
下圖是我們剛調研準備使用Kubernetes時候的調研方案選擇。

對于一個初次接觸Kubernetes的人來說,看到這樣一個龐大的架構選型時會望而生畏,但是Kubernetes的開源社區幫助了我們很多。

我組建了**K8S&Cloud Native實戰**、**ServiceMesher**微信群,參與了k8smeetup、KEUC2017、[kubernetes-docs-cn](https://github.com/kubernetes/kubernetes-docs-cn) Kubernetes官方中文文檔項目。
**有用的資料和鏈接**
- 我的博客: <https://jimmysong.io>
- 微信群:k8s&cloud native實戰群、ServiceMesher(見:<https://jimmysong.io/about>)
- Meetup:k8smeetup、[ServiceMesher](http://www.servicemesher.com)
- Cloud Native Go - 基于Go和React云原生Web應用開發:https://jimmysong.io/cloud-native-go
- Gitbook:<https://jimmysong.io/kubernetes-handbook>
- Cloud native開源生態:<https://jimmysong.io/awesome-cloud-native/>
- 資料分享整理:<https://github.com/rootsongjc/cloud-native-slides-share>
- 遷移到云原生架構:<https://jimmysong.io/migrating-to-cloud-native-application-architectures/>
- KubeCon + CloudNativeCon 2018年11月14-15日 上海
- 序言
- 云原生
- 云原生(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快速入門指南
- 邊緣計算
- 人工智能