Docker
Docker 對進程進行封裝隔離,屬于操作系統層面的虛擬化技術。
Docker 在容器的基礎上,進行了進一步的封裝,從文件系統、網絡互聯到進程隔離等等,極大的簡化了容器的創建和維護。使得 Docker 技術比虛擬機技術更為輕便、快捷。
Docker 和傳統虛擬化方式的不同之處:
傳統虛擬機技術是虛擬出一套硬件后,在其上運行一個完整操作系統,在該系統上再運行所需應用進程;而容器內的應用進程直接運行于宿主的內核,容器內沒有自己的內核,而且也沒有進行硬件虛擬。因此容器要比傳統虛擬機更為輕便。
K8S
K8S,就是基于容器的集群管理平臺,它的全稱,是kubernetes。
在現實的生產環境中 Docker 本身是一個相對底層的容器引擎,在有很多服務器的集群中,不太可能單獨去管理任務和資源。所以我們需要 Kubernetes 這樣的系統來進行任務的編排和調度。
關于pod
Kubernetes 中部署的最小單位是 pod,而不是 Docker 容器。實時上 Kubernetes 是不依賴于 Docker 的,完全可以使用其他的容器引擎在 Kubernetes 管理的集群中替代 Docker。
Kubernetes 引入 Pod 主要基于下面兩個目的:
- 可管理性。
有些容器天生就是需要緊密聯系,一起工作。Pod 提供了比容器更高層次的抽象,將它們封裝到一個部署單元中。Kubernetes 以 Pod 為最小單位進行調度、擴展、共享資源、管理生命周期。 - 通信和資源共享。
Pod 中的所有容器使用同一個網絡 namespace,即相同的 IP 地址和 Port 空間。它們可以直接用 localhost 通信。同樣的,這些容器可以共享存儲,當 Kubernetes 掛載 volume 到 Pod,本質上是將 volume 掛載到 Pod 中的每一個容器。
在與 Docker 結合使用時,一個 pod 中可以包含一個或多個 Docker 容器。但除了有緊密耦合的情況下,通常一個 pod 中只有一個容器,這樣方便不同的服務各自獨立地擴展。Pod 中的容器會作為一個整體被 Master 調度到一個 Node 上運行。Pods 有兩種使用方式:
- 運行單一容器。
one-container-per-Pod 是 K8s 最常見的模型,這種情況下,只是將單個容器簡單封裝成 Pod。即便是只有一個容器,K8s 管理的也是 Pod 而不是直接管理容器。 - 運行多個容器。
但問題在于:哪些容器應該放到一個 Pod 中?
答案是:這些容器聯系必須非常緊密,而且需要直接共享資源。
關于Controller
Kubernetes 通常不會直接創建 Pod,而是通過 Controller 來管理 Pod 的。Controller 中定義了 Pod 的部署特性,比如有幾個副本,在什么樣的 Node 上運行等。為了滿足不同的業務場景,Kubernetes 提供了多種 Controller,包括 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等。
實戰
參考官網提供的一個實踐方案。結果是把一個 node.js 的簡單的 Hello World 應用,在 Kubernetes 上部署成為一個復制應用,將代碼變成一個 Docker 鏡像,并且在Google Container Engine上運行它。(Kubernetes 是可以運行在許多不同環境的開源項目,無論是筆記本還是高可用多點集群,公有云還是本地環境,無論是虛擬機還是物理機。范例提到的是google的k8s托管環境。)
步驟:
登陸google云平臺,創建并配置項目,記下配置的
PROJECT_ID
創建nodejs項目并起服務
創建一個docker容器鏡像
先創建dockerfile
// 讓搭建的 Docker 鏡像基于 Docker 鏡像倉庫的 Node.js LTS鏡像
// 開放 8080 端口,復制我們的 server.js 文件到鏡像并啟動 Node 服務
FROM node:4.4
EXPOSE 8080
COPY server.js .
CMD node server.js
然后使用docker構建容器并用project_id標記
docker build -t gcr.io/$PROJECT_ID/hello-node:v1 .
(范例文件夾命名為hello-node)
docker run -d -p 8080:8080 --name hello_tutorial gcr.io/$PROJECT_ID/hello-node:v1
通過docker run本地運行鏡像試試可否正常訪問。
最后推送鏡像到google容器倉庫(命令行需要先安裝Google Cloud SDK)
gcloud docker push gcr.io/$PROJECT_ID/hello-node:v1
如果一切順利,應該會在控制臺中看到容器鏡像
創建一個集群
集群由一個 master API server 和一組叫做 node 的虛擬機構成。
先選擇地區,再通過gcloud container clusters create hello-world
創建一個集群。另外可以通過Google Cloud Console的New container cluster可視化創建一個集群。
最后通過gcloud container clusters get-credentials hello-world
部署容器式應用到 Kubernetes 集群。創建pod
借助kubectl run
命令來創建一個pod
kubectl run hello-node --image=gcr.io/$PROJECT_ID/hello-node:v1 --port=8080
允許外部訪問
在我們的開發機上,我們可以使用kubectl expose
以及--type="LoadBalancer"
標識需要從外部 IP 訪問來公開 pod。
kubectl expose deployment hello-node --type="LoadBalancer"
此命令中使用deployment這個標識指定了我們將使用底層架構來提供負載均衡。*我們開放的是 deployment,而不是直接公開 pod,這將會讓所有由 deployment 管理的 pod 負載均衡(這只有一個 pod,我們一會會復制多個)
- 滾動升級你的網站
與往常一樣,修復 bug 或者添加功能的應用,部署到生產環境。
首先編輯修改代碼。
再構建鏡像docker build -t gcr.io/$PROJECT_ID/hello-node:v2 .
上傳gcloud docker push gcr.io/$PROJECT_ID/hello-node:v2
借助kubectl set image
命令用新的鏡像更新deployment,它會創建新的pod并刪除舊的pod
kubectl set image deployment/hello-node hello-node=gcr.io/$PROJECT_ID/hello-node:v2
當然,我們也可以借助 Kubernetes Web UI 圖形化管理,用它來部署容器化應用,以及監視和管理你的群集。
12要素
12-Factor 為構建如下的 SaaS(software as a service 軟件即服務) 應用提供了方法論:
- 使用標準化流程自動配置,從而使新的開發者花費最少的學習成本加入這個項目。
- 和操作系統之間盡可能的劃清界限,在各個系統中提供最大的可移植性。
- 適合部署在現代的云計算平臺,從而在服務器和系統管理方面節省資源。
- 將開發環境和生產環境的差異降至最低,并使用持續交付實施敏捷開發。
- 可以在工具、架構和開發流程不發生明顯變化的前提下實現擴展。
這套理論適用于任意語言和后端服務(數據庫、消息隊列、緩存等)開發的應用程序。
基準代碼(一份基準代碼,多份部署)
每個應用只對應一份基準代碼,但可以同時存在多份部署。每份部署相當于運行了一個應用的實例。通常會有一個生產環境,一個或多個預發布環境。此外,每個開發人員都會在自己本地環境運行一個應用實例,這些都相當于一份部署。依賴(顯式聲明依賴關系)
12-Factor規則下的應用程序不會隱式依賴系統級的類庫。 它一定通過依賴清單,確切地聲明所有依賴項。此外,在運行過程中通過依賴隔離工具來確保程序不會調用系統中存在但清單中未聲明的依賴項。這一做法會統一應用到生產和開發環境。配置(在環境中存儲配置)
12-Factor推薦將應用的配置存儲于環境變量中( env vars, env )。環境變量可以非常方便地在不同的部署間做修改,卻不動一行代碼;與配置文件不同,不小心把它們簽入代碼庫的概率微乎其微;與一些傳統的解決配置問題的機制(比如 Java 的屬性配置文件)相比,環境變量與語言和系統無關。后端服務(把后端服務當作附加資源)
12-Factor 應用不會區別對待本地或第三方服務。 對應用程序而言,兩種都是附加資源,通過一個 url 或是其他存儲在配置中的服務定位/服務證書來獲取數據。12-Factor 應用的任意部署,都應該可以在不進行任何代碼改動的情況下,將本地 MySQL 數據庫換成第三方服務(例如 Amazon RDS)。類似的,本地 SMTP 服務應該也可以和第三方 SMTP 服務(例如 Postmark )互換。上述 2 個例子中,僅需修改配置中的資源地址。
每個不同的后端服務是一份資源,這些資源和它們附屬的部署保持松耦合。
部署可以按需加載或卸載資源。例如,如果應用的數據庫服務由于硬件問題出現異常,管理員可以從最近的備份中恢復一個數據庫,卸載當前的數據庫,然后加載新的數據庫 – 整個過程都不需要修改代碼。構建,發布,運行(嚴格分離構建和運行)
12-factor 應用嚴格區分構建,發布,運行這三個步驟。
- 構建階段 是指將代碼倉庫轉化為可執行包的過程。構建時會使用指定版本的代碼,獲取和打包依賴項,編譯成二進制文件和資源文件。
- 發布階段 會將構建的結果和當前部署所需配置相結合,并能夠立刻在運行環境中投入使用。
- 運行階段 (或者說“運行時”)是指針對選定的發布版本,在執行環境中啟動一系列應用程序進程。
進程(以一個或多個無狀態進程運行應用)
12-Factor 應用的進程必須無狀態且無共享。 任何需要持久化的數據都要存儲在后端服務內,比如數據庫。端口綁定(通過端口綁定提供服務)
12-Factor 應用完全自我加載而不依賴于任何網絡服務器就可以創建一個面向網絡的服務?;ヂ摼W應用通過端口綁定來提供服務 ,并監聽發送至該端口的請求。
端口綁定這種方式也意味著一個應用可以成為另外一個應用的后端服務 ,調用方將服務方提供的相應 URL 當作資源存入配置以備將來調用。-
并發(通過進程模型進行擴展)
在 12-factor 應用中,進程是一等公民。12-Factor 應用的進程主要借鑒于unix 守護進程模型。
進程和進程類型關系 易處理(快速啟動和優雅終止可最大化健壯性)
12-Factor 應用的進程易處理(disposable)的,意思是說它們可以瞬間開啟或停止。 這有利于快速、彈性的伸縮應用,迅速部署變化的代碼或配置,穩健的部署應用。
進程應當追求最小啟動時間,一旦接收終止信號就會優雅的終止。進程還應當在面對突然死亡時保持健壯,例如底層硬件故障。開發環境與線上環境等價(盡可能的保持開發,預發布,線上環境相同)
12-Factor 應用的開發人員應該反對在不同環境間使用不同的后端服務,即使適配器已經可以幾乎消除使用上的差異。這是因為,不同的后端服務意味著會突然出現的不兼容,從而導致測試、預發布都正常的代碼在線上出現問題。這些錯誤會給持續部署帶來阻力。從應用程序的生命周期來看,消除這種阻力需要花費很大的代價。
- 縮小時間差異:開發人員可以幾小時,甚至幾分鐘就部署代碼。
- 縮小人員差異:開發人員不只要編寫代碼,更應該密切參與部署過程以及代碼在線上的表現。
- 縮小工具差異:盡量保證開發環境以及線上環境的一致性。
日志(把日志當作事件流)
12-factor應用本身從不考慮存儲自己的輸出流。不應該試圖去寫或者管理日志文件。相反,每一個運行的進程都會直接的標準輸出(stdout)事件流。開發環境中,開發人員可以通過這些數據流,實時在終端看到應用的活動。管理進程(后臺管理任務當作一次性進程運行)
進程構成是指用來處理應用的常規業務(比如處理 web 請求)的一組進程。
參考
干貨滿滿!10分鐘看懂Docker和K8S
12要素
k8s中文社區pod名詞解釋
k8s基本概念
借助k8s Web UI進行圖形化管理