容器技術
容器借鑒了集裝箱的概念,集裝箱解決了什么問題呢?無論形狀各異的貨物,都可以裝入集裝箱,集裝箱與集裝箱之間不會互相影響。由于集裝箱是標準化的,就可以把集裝箱整齊擺放起來,裝在一艘大船把他們都運走。有了集裝箱,就再也不需要為各種貨物單獨準備專門運輸的船了。如果把容器比作集裝箱的話,應用就相當于集裝箱里的貨物。
容器(Container):一種輕量級的虛擬化技術,這種技術允許操作系統上的用戶空間被分割成幾個獨立的單元在內核中運行,彼此互不干擾。這樣一個獨立的空間,就稱之為一個“容器”。
容器為應用軟件及其依賴組件提供了一個資源獨立的運行環境。應用軟件所依賴的組件會被打包成一個可重用的鏡像,鏡像運行環境并不會與主機操作系統共享內存、CPU和硬盤空間,由此也保證了容器內部的進程與容器外部進程的獨立關系。
舉個例子,一個操作系統,可以類比成一套公寓,那么容器就相當于公寓中的一個房間,大家共享同一個客廳,廚房和衛生間。但是房間和房間之間彼此隔離,一個房間里面的人的活動,不會影響到其他房間的住客。房間也有門,因此有一定的安全隔離保障。
容器的技術特點:
? 容器是自包含的。它打包了應用程序及其所有依賴,可以直接運行。
? 容器是可移植的。可以在幾乎任何地方以相同的方式運行。這就可以確保應用在開發環境、測試環境、生產環境等都有完全一樣的運行環境。
? 容器是輕量級的。占用資源很少,可以秒級啟動。
? 容器是互相隔離的。同一主機上運行的多個容器,不會互相影響。
這兩種架構,一個很直觀的對比結果是,容器的運行不需要再額外安裝虛擬機操作系統。可見,容器是一種比虛擬機更輕量級的虛擬化技術,支持秒級啟動具備更好的快速擴展能力,具備更好的跨平臺遷移能力。當然也由于這個原因,容器的隔離性上不如虛擬機。兩者主要差異如下:
? 虛擬機OS占用了較多資源,一個虛擬機基本是GB 級的,一個容器可小至幾MB。
? 虛擬機的啟動時間一般是分鐘級的,而容器的啟動時長是毫秒級的。
? 由于容器的輕量級,它具備了更好的快速擴展能力。
容器比虛擬機具備更好的跨平臺遷移能力,如虛擬機無法從Vmware遷移至KVM。
docker
Docker是一個開源的應用容器引擎,它實現了容器化技術的一種具體形式。
Docker核心概念
Docker 有三大核心概念,分別是容器(Container)、鏡像(Image)和倉庫(Repository)。
? 鏡像:類似虛擬機的鏡像,通俗的理解就是安裝文件,相當于是容器的模板,可以根據不同的鏡像來創建不同的容器。鏡像和容器的關系可以理解為面向對象中類和實例對象的關系。
? 容器:類似一個輕量級的沙箱,容器是根據鏡像創建的應用運行實例,具體運行應用程序的一個進程,可以將其啟動、開始、停止、刪除,而這些容器都是相互隔離、互不可見的。
? 倉庫:類似代碼倉庫,是 Docker 集中存放鏡像文件的場所。倉庫有本地鏡像倉庫 Docker-Registry 和公共鏡像倉庫 Docker Hub,平時使用本地倉庫的鏡像,沒有的話可以去公共鏡像倉庫下載。
可以用編程中面向對象的概念來做類比:鏡像可以看成一個類,容器可以看做是類的實例化對象。一個類可以有多個對象。同理,一個鏡像可以有多個容器。容器是由鏡像實例化而來。簡單來說,鏡像是文件,容器是進程,倉庫是保存鏡像的地方。
通過Docker命令,運行一個容器一般情況下只需要三步:
- pull:從鏡像倉庫中將相應的鏡像下載下來;
- list:當鏡像下載完成之后就可以通過docker images 來查看本地鏡像,會列出一個完整的鏡像列表,可以在列表中選中想要的鏡像;
- run:當選中鏡像之后,就可以通過 docker run 來運行這個鏡像,得到想要的容器。當然可以通過多次運行得到多個容器。
采用容器技術搭建并運行企業網站,需要經歷三個主要過程:
? 構建(build):把應用代碼和運行環境一起,制作成鏡像文件
? 發布(release):將鏡像文件發布到鏡像倉庫。
運行(run):從鏡像倉庫中獲取鏡像并運行。
docker和k8s的關系
Docker 和 Kubernetes(通常縮寫為 k8s)是容器化技術領域中兩個互補的工具,它們共同工作以提供強大的應用程序部署和管理解決方案。
Docker:
Docker 是一個開源的容器化平臺,它允許開發者將應用及其依賴打包到一個輕量級、可移植的容器中。
容器與底層系統隔離,確保了應用程序在不同環境中的一致性。
Docker 提供了容器的創建、運行、分發和管理的工具,如 Docker Engine 和 Docker Hub。
Kubernetes:
Kubernetes 是一個開源的容器編排系統,用于自動化部署、擴展和管理容器化應用程序。
它提供了高級的集群管理功能,包括服務發現、負載均衡、自我修復(自動替換失敗的容器)、存儲編排等。
Kubernetes 允許在集群中運行和管理成千上萬的容器,支持服務的彈性伸縮和高可用性。
Docker 和 Kubernetes 的關系:
容器化:Docker 用于創建容器化的應用程序,而 Kubernetes 用于管理這些容器的生命周期和部署。
互補性:Docker 提供了容器的運行時環境,而 Kubernetes 則提供了容器的管理和編排。
生態系統:Kubernetes 支持多種容器運行時,包括 Docker,但也支持其他如 containerd、CRI-O 等。
部署和管理:Docker 可以獨立使用來運行和管理單個容器,而 Kubernetes 提供了大規模容器部署和管理的能力。
服務網格:在 Kubernetes 上,Docker 容器可以作為 Pod 運行,Kubernetes 負責 Pod 的調度、網絡、存儲等。
社區和企業支持:兩者都有龐大的社區和企業支持,Docker 由 Docker Inc. 維護,而 Kubernetes 由 Cloud Native Computing Foundation (CNCF) 維護。
總的來說,Docker 為應用程序提供了容器化的基礎,而 Kubernetes 則為這些容器化的應用提供了一個強大的運行平臺,兩者結合使用可以實現高效的持續集成和持續部署(CI/CD)流程,以及在云環境中的彈性伸縮和高可用性部署。
K8s
容器編排是指自動化容器的部署、管理、擴展和聯網。通過容器編排,可以構建跨多個容器的應用服務、跨集群調度容器、擴展這些容器,并持續管理它們的健康狀況。容器編排給容器技術帶來了巨大的價值,包括:
? 自動化部署:支持根據副本數量,回滾,重啟等策略自動部署容器。
? 服務發現與負載均衡:自動發現增加的容器,并進行流量的負載均衡。
? 自動化容器恢復:自動對容器進行健康檢查,并根據策略進行重啟。
? 彈性伸縮:支持工作節點、容器的自動擴縮容。
一個容器編排平臺的核心功能:首先可以自動生成容器實例,并且生成的容器可以跨服務器的,幫助提高可用性和性能,同時還有健康檢查、容錯、可擴展、網絡、服務發現、滾動升級等功能,可以很好地解決需求與資源的匹配編排問題。
容器編排平臺的市場競爭曾經非常激烈,主流的有三個:Docker Swarm、Mesos Marathon和Kubernetes。它們各有特點,但同時滿足上面上述能力的,只有Kubernetes。
Kubernetes 設計思想
Kubernetes 基于API管理一切的思想,采用聲明式即“面向結果”的API,圍繞 etcd(分布式存儲與協調數據庫) 構建出來的一套 “面向終態” 的編排體系。
當用戶向 Kubernetes 提交了一個 API 對象(Kubernetes Object)的期望狀態(Spec)之后,Kubernetes 會負責保證整個集群里各項資源的當前狀態(Status),都與 API 對象描述的需求相一致。更重要的是,這個保證是一項 “無條件的”、“沒有期限” 的承諾:對于每個保存在 etcd 里的 API 對象,Kubernetes 都通過啟動一種叫做 “控制器模式”(Controller Pattern)的無限循環,不斷對 etcd 里的 API 對象的變化進行監視(Watch),然后執行控制器(Controller)里定義的編排動作的響應邏輯,進行調諧,最后確保整個集群的狀態與 API 對象的描述一致。
為了實現“面向終態”的管理,支持自動化部署、擴縮和管理容器應用,Kubernetes采用了控制平面和計算平面分離的架構。控制平面是整個集群的大腦,負責控制、調度集群資源;計算平面負責運行容器化應用,是控制平面調度的對象,通過增加或減少工作節點實現容器集群處理能力的擴縮。控制平面由至少一個管理節點(Master節點)組成,通常會采用三個管理節點組成高可用集群(一個管理節點提供服務,剩下兩個管理節點為備用節點,當管理節點不可用時,從備用節點中自動選舉一個出來成為管理節點)。計算平面則由多個工作節點(Node節點)組成。
K8S集群分為Master節點和Node節點,Master節點負責調度分配任務,Node節點接受Master調度進行工作。
1.1 Master節點組件
/1. API Server
集群的統一入口,各組件協調者,以RESTful API方式提供接口服務,所有對象資源的增刪查改和監聽操作都交給API Server處理后再提交給Etcd存儲。
2. Controller Manager
負責維護集群的狀態,比如故障檢測、自動擴展、滾動更新等。一個資源對應一個控制器,而Controller Manager就是負責管理這些控制器的。
工作負載是一種Controller,在Kubernetes中還有Node Controller等其他多種控制器。每種控制器都是一個智能系統,通過API Server提供的(List-Watch)接口實時監控集群中資源對象的變化,當資源對象因某些原因發生狀態變化時,Controller會執行相應邏輯使其最終狀態調整到期望狀態。比如:某個Node意外宕機時,Node Controller會及時發現此故障并執行自動化修復流程,確保集群始終處于預期的工作狀態。
每種Controller都負責一種特定的資源控制器,Controller Manager是Kubernetes中各種Controller的管理者,是集群內部的管理控制中心,也是Kubernetes自動化功能核心。
3. Scheduler
負責資源的調度,按照預定的調度策略將Pod調度到相應的機器上。
4.etcd
分布式鍵值存儲系統,用于保存群集狀態數據,比如Pod、Service等對象信息。
1.2 Node組件
Node節點(工作節點)是Kubernetes集群中的工作節點,Node節點上的工作由Master節點進行分配,比如當某個Node節點宕機時,Master節點會將其上面的工作轉移到其他Node節點上。Node節點在集群中主要負責如下任務:
? 負責管理所有容器(Container)。
? 負責監控/上報所有Pod的運行狀態。
一個Node節點主要包含三個組件:kubelet、kube-proxy、Container Runtime。
- kubelet
kubelet是Master在Node節點上的Agent,管理本機運行容器的生命周期,比如創建容器、Pod掛載數據卷、下載secret、獲取容器和節點狀態等工作。kubelet將每個Pod轉換成一組容器。 - kube-proxy
為Service提供cluster內部的服務發現和負載均衡。Service是通過Selector選擇的一組Pods的服務抽象,提供了服務的負載均衡和反向代理的能力。實現 Service 負載均衡和反向代理功能,是通過kube-proxy實現的。kube-proxy 運行在每個節點上,監聽 API Server 中服務對象的變化,通過管理 iptables 來實現網絡的轉發。
Service的負載均衡實現的過程共分為五步,如下: - 運行在每個Node節點的kube-proxy會實時的watch Service和Endpoints(IP+端口)對象, 當用戶在Kubernetes集群中創建了含有Label的Service之后,同時會在集群中創建出一個同名的Endpoints對象,用于存儲Service下的Pod IP。
- 當每個Node節點的kube-proxy感知到Service和Endpoints的變化之后,會在各自的Node節點上打開代理端口,并設置相關的iptables或IPVS轉發規則。
- 客戶端訪問Service的ClusterIP。
- 客戶端請求會經過iptables/IPVS,會被重定向到kube-proxy的代理端口。IPVS模式的調度由IPVS完成,其他功能仍是iptables實現。
- kube-proxy將請求發送到真實的后端Pod。
Kubernetes中如何實現多個環境的隔離?
在Kubernetes容器集群中,同一類型的資源名稱是唯一的。在實際中,我們往往需要將不同業務、不同的項目、不同的環境進行隔離管理,這就需要通過命名空間Namespace進行分區管理。
Namespace 是用來做集群內部的邏輯隔離的,它包括鑒權、資源管理等。Kubernetes 的每個資源,比如 Pod、Deployment、Service,都屬于一個 Namespace,同一個 Namespace 中的資源命名唯一,不同的 Namespace 中的資源可以重名。在一個Kubernetes集群中可以擁有多個命名空間,它們在邏輯上彼此隔離。
不過,Kubernetes也有一些資源隸屬于集群級別的,如Node、Namespace和Persistent Volume等,不屬于任何名稱空間,所以這些資源對象的名稱必須全局唯一。
在K8s 中部署一個前后端應用
編寫Dockerfile
拷貝前端工程dist目錄至/frontend,并進行目錄授權
from nginx
copy ./dist /frontend
run chown nginx.nginx /frontend -R
copy nginx.conf /etc/nginx/conf.d/default.conf
編寫nginx.conf文件
server{
listen 80;
server_name localhost;
root /frontend;
index index.html index.htm;
location /login {try_files $uri $uri/ /login.html;}
}
backend-dp.yaml
由于我們服務是無狀態服務,使用Deployment進行部署,Deployment擁有更加靈活強大的升級、回滾功能,并且支持滾動更新
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
selector:
matchLabels:
app: backend
replicas: 1
template:
metadata:
labels:
# service 會根據此標簽來查找此pod
app: backend
version: latest
spec:
containers:
- name: backend
image: “dweizhao/backend:latest”
imagePullPolicy: Always
backend-svc.yaml
Service相當于Spring cloud中Ribbon的作用,提供了服務發現和負載均衡的功能,而不用關心具體服務實例有多少個,在 k8s的服務實例就是Pod,這里我們使用ClusterIP類型,因為是通過Ingress在集群內訪問,通過 app:backend標簽,來查找對應pod,所以 pod 的label必須包含app:backend
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
ports:
- name: backend-http
port: 8080
targetPort: 8080
protocol: TCP
selector:
# 根據標簽查找 pod
app: backend
之后在服務器上創建命名空間:
kubectl create namespace k8sdemo
部署:
kubectl create namespace k8sdemo && kubectl apply -f backend-dp.yaml -f backend-svc.yaml -f frontend-dp.yaml -f frontend-svc.yaml -f ingress.yaml -n k8sdemo
k8s常用命令
#查看pods列表,這里主要是看pod狀態
kubectl get pods -n tbds(n后面是namespace)
#查看某個pod的日志
kubectl logs tm-platform-96c9cd9d-w6zr8 -n tbds
#查看pod的詳細信息,這些信息包括了 Pod 的配置、狀態、事件等
kubectl describe pod kubectl logs tm-platform-96c9cd9d-w6zr8 -n tbds
#在pod中啟動一個交互式shell,可以在這個shell中執行命令
kubectl exec -it tsf-data-gateway-86f59d85-vlvgq(pod名稱) -n tbds -- bash
#獲取應用列表
kubectl get app -n tbds
#刪除某個應用
kubectl delete app product-kylin-sp2-es-x86(應用名稱) -n tbds
#獲取容器的configmap
kubectl get -o yaml configmap te-elasticsearch-config(config名稱) -n tbds
#或者這樣寫:
kubectl get cm my-configmap -o yaml
#查看某個secret的值(渲染后的)
kubectl get secret secret-tbdsnew -o yaml -n default
#查看pod的資源使用情況
kubectl top pod <pod-name> -n <namespace>
#查看所有命名空間
kubectl get namespaces
#創建命名空間
kubectl create namespace tbds
#將base64編碼的字符串進行解碼
echo "dGJkcy1pbWFnZXM=" |base64 --decode