kubernetes in action - Overview


傳統的應用都是“monoliths”,意思就是大應用,即所有邏輯和模塊都耦合在一起的

這樣明顯很挺多問題的,比如只能scale up,升級必須整體升級,擴容

所以我們就想把大應用,broken down成小,獨立的模塊或組件,這樣組件可以獨立的升級,擴容,組件也可以用不同的語言實現,組件間通過協議通信,每個組件就是一個微服務

微服務技術可以說是傳統組件技術,如以前的COM,Corba,基於docker的演進,對於用戶透明硬件,實現語言,組件間通過Restful或RPC交互

 

問題在於,你把一個大應用拆成很多小應用,是不是很難維護和部署?

好,你在一台物理機上部署這么多的小應用,並且獨立升級,那么他們的依賴如果沖突怎么辦?

並且每個組件跑的環境可能也不一樣,你所有機器都需要把這些環境都裝上?想想就要爆炸

所以任何設計都有利弊,monoliths應用有他的問題,但拆成微服務也會引入一堆新的問題,

之所以現在微服務那么火,當然當年COM和Corba也是紅極一時而后沉寂,是因為docker技術的出現,現有docker和相關框架可以比較好的解決這些問題,比如kubernetes

在這些框架的基礎下,我們可以做到持續開發,甚至Devops,Noops

這里需要理解Devops,不是把ops團隊干掉,然后把ops的工作都交給Dev,而是說在框架的支持下,原來的維護和發布已經變的非常簡單,那么Dev也可以更高效的去做,沒有必要讓ops做,而ops也可以解放出來提供更好的基礎框架,這是一種良性循環,否則張口閉口Devops只是一種惡性循環。

 

那么容器技術有啥牛逼的,原來的VM為啥不行?關鍵點就在“輕量”上

因為微服務是需要把大應用拆分成很多小應用,而這些小應用都是混布在機器上,首先考慮的問題就是隔離,

當然如果都用VM,隔離是沒問題,但是太浪費資源了,都用VM可能比原來用一個應用消耗的資源大一個量級

所以,container技術,是一種輕量的VM

最大的差異是,每個VM都會跑一個獨立的OS,kernel,而container會共用host上的OS

那么對於VM而言,因為OS都是獨立的,所以他的隔離是很直覺的

那么container既然是共享OS,是用什么技術做到隔離的?

linux container主要是用了下面兩種技術做到的容器隔離

首先,Linux namespaces,

Linux會默認用一個namespace,你也可以創建更多的namespace,namespace之間下面這些資源命名是隔離的,也就是說這個namespace看不到其他namespace的pid或userid等其他資源

 Mount (mnt)

 Process ID (pid)

 Network (net)

 Inter-process communication (ipc)

 UTS (host name,domain name)

 User ID (user)

再者,是CGroup,Linux kernel feature that limits the resource usage of a process (or a group of processes).

被限制的進程,使用的資源,cpu,memory,可以限制在規定的范圍內

Cgroup其實也不完美,比如對於IO,只能限制IOPS,無論是磁盤還是網絡,很難去限制真正的流量;Cpu也無法針對突發流量,使用率在瞬間超限,然后再被限制,這樣很容易影響到其他進程,除非明確綁核;

 

容器技術很久之前就有,但是一直到docker技術出現后,才被大家廣泛的關注和接受;原因在於docker是“Portable”的,通過docker image

Docker was the first container system that made containers easily portable across different machines.
It simplified the process of packaging up not only the application but also all its libraries and other dependencies,
even the whole OS file system, into a simple, portable package that can be used to provision the application to any other machine running Docker

docker image把整個執行環境,包含OS file system都package,這樣哪怕docker內和宿主機是不同的os內核都沒關系,比如一個是centos,一個是debian

docker image本身也是從vm image借鑒過來的,但docker image會更輕量

並且docker image一個很優秀的設計是他是分層的,所以如果很多image都用到一個layer,這個layer只需要被下載一次

A big difference between Docker-based container images and VM images is that
container images are composed of layers, which can be shared and reused across multiple images.

所以要理解,docker技術的核心是package技術,而不是隔離,docker的隔離是通過linux內核features,namespaces和cgroup來保證的,docker本身不管隔離的事

所以通俗的講,docker就是一個打包和管理包的技術,就類似maven,只是他管理的不是一個java jar包,而是一個image

 

之前說過container和VM的差別,那么現在再具體看下docker container和VM的差別,加深理解

從這個圖我們可以看出,

首先,之前說的區別,VM是需要自帶OS kernel的,並且VM是完全獨立的;docker共享宿主機的OS,並且需要一個docker進程來管理

再者,對於VM,如果應用A和B需要同一個執行環境,我們需要把他們放在一個VM中,但這樣他們之間是不隔離的;對於docker,A和B需要跑在獨立的容器內,但是還要共享執行環境

那么docker是怎么做的,關鍵就是docker image是分層的,docker可以基於同一層去啟動容器;但這里的layer是read-only的,所以如果一個container改變了環境的話,他會增加一個新的layer,把所有的變更放在這個新的layer中

 

下面來說k8s,

我們有了docker,容器可以在各個機器上遷來遷去,那么如果我有很多容器,和主機,怎么管理他們,靠手工的遷移和管理肯定是不合適的

那么kubernetes就做這個事的,他可以看成cluster的操作系統,提供類似,service discovery, scaling, load-balancing, self-healing, and even leader election等功能

Kubernetes的架構如下,

首先,kubernetes節點分為,master和worker

master,Control plane,包含API server,用於通信,client和control plane,或多個control plane之間;Scheduler,顧名思義,負責調度應用到各個worker nodes;ETCD,類似zk,存儲配置,並保證一致性;Controller Manager,負責集群級別的管理,監控worker nodes,節點failover等

woker node,首先要個Container Runtime,如docker進程來執行容器;Kubelet,用於和master通信,並管理改woker上的所有容器;Kube-proxy,類似SLB,做服務訪問load balance的

下面通過一個例子來看下,用戶是如何通過kubernetes來提交應用的,

1. 用戶首先要把應用相關的docker image提交到image registry

2. 然后用戶需要寫,App descriptor,用於描述應用中各個container是如何組織的
這里有個概念是,pods,可以理解成容器分組,在一個pods中,會被要求在一起執行,調度的時候也是按照一個整體調用,並且container之間也是不完全隔離的
所以在descriptor中,需要將container分成pods,並且給出每個pods的並發數

3. 接着就把應用提交給master,master會將各個pods調度到woker,通過woker上的kubelet,kubelet會讓節點上的docker runtime把容器啟動起來

4,docker runtime按照之前的步驟,先去image registry下載,然后啟動容器即可

 

下面開始action,Docker篇

1. 啟動docker

docker run <image> 

docker run <image>:<tag>

例子,執行busybox image,傳入參數 echo “hello world”

 

2. 創建docker image

首先,需要有一個要跑在docker中的程序,這里用個js,

const http = require('http');
const os = require('os');
console.log("Kubia server starting...");
var handler = function(request, response) {
  console.log("Received request from " + request.connection.remoteAddress);
  response.writeHead(200);
  response.end("You've hit " + os.hostname() + "\n");
};
var www = http.createServer(handler);
www.listen(8080);

然后,需要寫個Dockerfile,

FROM node:7   #基於的image layer,“node” container image, tag 7

ADD app.js /app.js  #把app.js放到容器的root目錄

ENTRYPOINT ["node", "app.js"]  #容器啟動的時候執行那個命令,這里是“node app.js”

最終調用,docker build創建image,

docker build -t kubia .

這里再通過這個例子看下,image layer的分層,

可以看到,對於dockerfile中每一行命令,都會產生一個layer

You may think that each Dockerfile creates only a single new layer, but that’s not the case. When building an image, a new layer is created for each individual command

in the Dockerfile.

這個時候,我們可以查看剛剛創建的image,

現在你可以用docker run,啟動這個容器,

docker run --name kubia-container -p 8080:8080 -d kubia

--name,容器名字
-p,Port 8080 on the local machine will be mapped to port 8080 inside the container,docker的端口是隔離的,所以你想從外面訪問,需要和宿主機的端口匹配上
-d,daemon,后台程序;

容器啟動后,可以通過 http://localhost:8080 來訪問

 

3. 查看容器

 docker ps   #查看容器基本信息

 docker inspect kubia-container  #查看容器相關的所有信息

 登入到容器內部,

 docker exec -it kubia-container bash 

-i, which makes sure STDIN is kept open. You need this for entering commands into the shell.

-t, which allocates a pseudo terminal (TTY).

這里需注意,因為容器的進程其實是跑在宿主機的os上,所以容器內核宿主機上都可以看到這個容器進程,但是PID不一樣,docker內的PID是隔離的

 

4. 停止和刪除容器

docker stop kubia-container  #停止的容器,可以用docker ps -a查看到

docker rm kubia-container   #刪除容器

 

5. 上傳和注冊容器image

經過上面的步驟,容器已經可以在local正常使用,但是如果要跨機器使用,需要把image注冊到docker hub上

先要給image加tag,因為docker hub只允許用戶上傳,以用戶docker hub id開頭的image

docker tag kubia luksa/kubia #如果dockerhub id是luksa

docker push luksa/kubia  #上傳

這樣你就可以在其他機器上,這樣啟動這個image

docker run -p 8080:8080 -d luksa/kubia

 

Kubernetes篇

集群版本kubernetes按照比較麻煩,所以一般是用miniKube,先啟動miniKube

minikube start

然后,即可以用kubectl來連接kubernetes,kubectl就是一個client,用於連接kubernetes的APIServer

你可以看集群情況,

也可以看到所有節點的情況,

看某一個節點,

kubectl describe node gke-kubia-85f6-node-0rr

現在開始部署應用到kubernetes,

$ kubectl run kubia --image=luksa/kubia --port=8080 --generator=run/v1

replicationcontroller "kubia" created

這里看到啟動應用的時候,創建的是一個replicationcontroller,因為應用部署的時候需要多並發,所以需要rc來管理各個應用的replica

部署完后,我們怎么看部署的應用,
對於kubernetes,應用的部署的粒度是pod,而不是container

A pod is a group of one or more tightly related containers that will always run together on the same worker node and in the same Linux namespace(s).

pod類似邏輯machine,pod內部的container不是完全隔離,是共用同一個linux namespaces的

container,pod,work node的關系如下,

那么我們就可以看看pod的狀態,

詳細的信息,

 

接着,如何把pod所提供的服務暴露給外部用戶?這里就需要創建一個service,把rc暴露出來,因為rc管理的pod是動態的,臨時的,如果掛了,會拉起新的,但服務的ip不能老變,所以需要一個service做層proxy

kubectl expose rc kubia --type=LoadBalancer --name kubia-http

service "kubia-http" exposed

查看services的狀態,

所以整個應用的組件圖如下,

 

kubernetes可以動態擴容的,下面可以看到擴容前后的情況

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM