文章目錄
- 目的篇
- 概念篇
- 實操篇
- 問題總結篇
- PV-NFS創建時accessModes選擇Many,PVC綁定PV失敗,選擇Once後成功,也可讓多個Pod共享訪問,控制檯只能選擇硬盤PV 單臺讀寫
- service 綁定deployment時,label選擇不正確或少了,導致綁定不成功,訪問空白
- deployment pod的labels 與deployment的labels必須相同
- ingress本質就是clb,創建ingress會自動創建一個clb
- pv一旦被pvc綁定後,就被該pvc獨佔,不能在與其他pvc綁定
- pod 減少的時候會不會等待pod內的請求處理完成!
- 業務的代碼放在NFS中,更新重啓pod即可,鏡像在配置文件變更時在pull!
- tomcat更改war包和解壓文件放到不同目錄!
- pod的自動擴容頻率的間隔時長?
- pod的自動擴容數量爲現有pod的2倍,TKE是否同樣限制?是否可配置
- 突然過高併發流量導致pod阻塞,健康檢查無法通過導致服務崩潰?
- service對pod的負載規則?能否設置?權重,輪詢
- 超出指定pod數量的pod實列多長時間會刪除和回收?
- Terminating狀態的pod會如何處理?時長?
- node的調度局部最優解和全局最優解:1.12版本後默認未局部最優解
- 設置pod的自動擴容的實例數量範圍後,pod的數量並未自動擴容到範圍的下限數量
- 容器服務的概覽中的集羣資源使用量至少需要保持在30%~40%的可用率
- 健康檢測中就緒檢測只在容器初始化時檢測一次?
- server的Selectors只匹配到deployment不匹配pod?
- hpa間隔60S獲取一次pod的擴容指標,2~3分鐘後擴容的pod恢復到最小數量
- hpa獲取擴容指標時,有時會並不準確,關閉壓測了,並且hpa值已經下降,但下一分鐘的hpa值又飆升
- 相關資料地址和網站
目的篇
本文再githup上持續更新 https://github.com/ROOT137/Docker
現有體系分析
- 成本伴隨着服務規模的擴大會越來越高
- 服務器規模伴隨着服務規模的擴大會越來越龐大
- 虛擬機性能利用率不高
- 無法自動擴容,自動調度,自動重啓
期望Docker+Kubernetes的效果
- 快速部署應用,快速擴展應用
- 無縫對接新的應用功能節省資源,優化硬件資源的使用
- 交付、部署:虛擬機可以通過鏡像實現環境交付的一致性
- 可擴展: 模塊化,插件化,可掛載,可組合
- 自動化: 自動部署,自動重啓,自動複製,自動伸縮/擴展
傳統虛擬化與Docker對比
虛擬機概述
虛擬機在本質上就是在模擬一臺真實的計算機設備,同時遵循同樣的程序執行方式。虛擬機能夠利用“虛擬機管理程序”運行在物理設備之上。反過來,虛擬機管理程序則可運行在主機設備或者“裸機”之上。
傳統的虛擬機需要模擬整臺機器包括硬件,每臺虛擬機都需要有自己的操作系統,虛擬機一旦被開啓,預分配給他的資源將全部被佔用。,每一個虛擬機包括應用,必要的二進制和庫,以及一個完整的用戶操作系統。
Docker虛擬化的架構
其中Docker Engine可以簡單看成對Linux的NameSpace、Cgroup、鏡像管理文件系統操作的封裝。Docker並沒有和虛擬機一樣利用一個完全獨立的Guest OS實現環境隔離,它利用的是目前linux內核本身支持的容器方式實現資源和環境隔離。簡單的說,Docker是利用namespace實現系統環境的隔離;利用Cgroup實現資源限制;利用鏡像實現根目錄環境的隔離。
docker化優點
-
Docker啓動快速屬於秒級別。虛擬機通常需要幾分鐘去啓動。
-
Docker在操作系統級別進行虛擬化,Docker容器和內核交互,幾乎沒有性能損耗,性能優於通過Hypervisor層與內核層的虛擬化。
-
Docker更輕量,Docker的架構可以共用一個內核與共享應用程序庫,所佔內存極小。同樣的硬件環境,Docker運行的鏡像數遠多於虛擬機數量。對系統的利用率非常高。與虛擬機相比,Docker隔離性更弱,Docker屬於進程之間的隔離,虛擬機可實現系統級別隔離。
-
安全性:Docker的安全性也更弱。Docker的租戶root和宿主機root等同,一旦容器內的用戶從普通用戶權限提升爲root權限,它就直接具備了宿主機的root權限,進而可進行無限制的操作。虛擬機租戶root權限和宿主機的root虛擬機權限是分離的,並且虛擬機利用如Intel的VT-d和VT-x的ring-1硬件隔離技術,這種隔離技術可以防止虛擬機突破和彼此交互,而容器至今還沒有任何形式的硬件隔離,這使得容器容易受到攻擊。
-
可管理性:Docker的集中化管理工具還不算成熟。各種虛擬化技術都有成熟的管理工具,例如VMware vCenter提供完備的虛擬機管理能力。
-
高可用和可恢復性:Docker對業務的高可用支持是通過快速重新部署實現的。虛擬化具備負載均衡、高可用、容錯、遷移和數據保護等經過生產實踐檢驗的成熟保障機制,VMware可承諾虛擬機99.999%高可用,保證業務連續性。
-
快速創建、刪除:虛擬化創建是分鐘級別的,Docker容器創建是秒級別的,Docker的快速迭代性,決定了無論是開發、測試、部署都可以節約大量時間。
-
交付、部署:虛擬機可以通過鏡像實現環境交付的一致性,但鏡像分發無法體系化;Docker在Dockerfile中記錄了容器構建過程,可在集羣中實現快速分發和快速部署。
K8S 優點
- 快速部署應用,快速擴展應用
- 無縫對接新的應用功能節省資源,優化硬件資源的使用
- 可移植: 支持公有云,私有云,混合雲,多重雲(multi-cloud)
- 可擴展: 模塊化,插件化,可掛載,可組合
- 自動化: 自動部署,自動重啓,自動複製,自動伸縮/擴展
概念篇
Dcoker相關
Dcoker是什麼
Docker是一個集開發、打包、運行應用於一體的開放式平臺。Docker可以用來快速交付應用。使用Docker,你可以將應用程序從你的基礎設施中分離出來,並將基礎設施當做一個管理平臺。Docker可以加快打包時間,加快測試,加快發佈,縮短開發及運行代碼之間的週期。Docker通過結合內核容器化特點和工作流,並使之工具化來實現這一切,幫助管理和發佈你的應用。
Docker 鏡像
Docker鏡像是一個只讀的模板。包含了容器運行時所需要的文件系統和一些參數。鏡像是無狀態的,也不會改變。鏡像是用來創建容器的。你可以使用docker pull命令獲取一個別人已創建好的鏡像,或者使用dockerbuild來構建一個自己的鏡像。
Docker 容器
Docker容器就像是一個文件夾,容器中包含了應用運行所需的一切。每個容器都是一個隔離的和安全的應用平臺。容器是鏡像的一個實例,它是有狀態的,而且隨時會改變,容器一般是短暫的。
Docker Daemon
Docker Daemon直接將執行命令發送至Docker Client——例如構建、運行以及分發等等。Docker Daemon運行在主機設備之上,但作爲用戶,我們永遠不會直接與該Daemon進行通信。Docker Client也可以運行在主機設備上,但並非必需。它亦能夠運行在另一臺設備上,並與運行在目標主機上的Docker Daemon進行遠程通信。
Docker Client
Docker Client是我們作爲最終用戶的通信對象。我們可以將其視爲Docker的UI。我們進行的一切操作都將直接接入Docker Client,再由其將指令傳遞至Docker Daemon。
Docker API
用於同Docker Daemon遠程交互。
Docker 應用場景
- web應用的自動化打包和發佈;
- 自動化測試和持續集成、發佈;
- 在服務型環境中部署和調整數據庫或其他的後臺應用;
- 從頭編譯或者擴展現有的OpenShift或Cloud Foundry平臺來搭建自己的PaaS環境。
Kubernetes相關
K8S是什麼
Kubernetes是容器集羣管理系統,是一個開源的平臺,可以實現容器集羣的自動化部署、自動擴縮容、維護等功能。
Kubernetes是Google 2014年創建管理的,是Google 10多年大規模容器管理技術Borg的開源版本
TKE是什麼
騰訊雲容器服務(Tencent Kubernetes Engine,TKE)基於原生 kubernetes 提供以容器爲核心的、高度可擴展的高性能容器管理服務。騰訊雲容器服務完全兼容原生 kubernetes API ,擴展了騰訊雲的 CBS、CLB 等 kubernetes 插件,爲容器化的應用提供高效部署、資源調度、服務發現和動態伸縮等一系列完整功能,解決用戶開發、測試及運維過程的環境一致性問題,提高了大規模容器集羣管理的便捷性,幫助用戶降低成本,提高效率。容器服務提供免費使用,涉及的其他雲產品另外單獨計費。
K8S架構圖及應用集羣節點說明
Pod
pod運行在Node上,包含一組容器和卷。同一個Pod裏的容器共享同一個網絡命名空間,可以使用localhost互相通信。Pod是短暫的,不是持續性實體。你可能會有這些問題:
- 如果Pod是短暫的,那麼我怎麼才能持久化容器數據使其能夠跨重啓而存在呢? 是的,Kubernetes支持卷的概念,因此可以使用持久化的卷類型。
- 是否手動創建Pod,如果想要創建同一個容器的多份拷貝,需要一個個分別創建出來麼?可以手動創建單個Pod,但是也可以使用Replication Controller使用Pod模板創建出多份拷貝
- 如果Pod是短暫的,那麼重啓時IP地址可能會改變,那麼怎麼才能從前端容器正確可靠地指向後臺容器呢?這時可以使用Service
Pod的生命週期:
- Pending Pod:Pod已經被創建,但是一個或多個容器還未創建,包括Pod調度階段,以及容器鏡像的下載過程
- Running: Pod已經被調度到Node,所有容器已經創建,並且至少一個容器在運行或者正在重啓。
- Successded: Pod中所有容器正常退出
- Failed: Pod中所有容器推出,至少有一個容器時一次退出的
Lable
一些Pod有Label([外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BaN3FLeV-1589009640677)(en-resource://database/730:1)])。一個Label是attach到Pod的一對鍵/值對,用來傳遞用戶定義的屬性。比如,你可能創建了一個"tier"和“app”標籤,通過Label(tier=frontend, app=myapp)來標記前端Pod容器,使用Label(tier=backend, app=myapp)標記後臺Pod。然後可以使用Selectors選擇帶有特定Label的Pod,並且將Service或者Replication Controller應用到上面。
Replication Controller
是否手動創建Pod,如果想要創建同一個容器的多份拷貝,需要一個個分別創建出來麼,能否將Pods劃到邏輯組裏?
Replication Controller確保任意時間都有指定數量的Pod“副本”在運行。如果爲某個Pod創建了Replication Controller並且指定3個副本,它會創建3個Pod,並且持續監控它們。如果某個Pod不響應,那麼Replication Controller會替換它,保持總數爲3.如下面的動畫所示:
如果之前不響應的Pod恢復了,現在就有4個Pod了,那麼Replication Controller會將其中一個終止保持總數爲3。如果在運行中將副本總數改爲5,Replication Controller會立刻啓動2個新Pod,保證總數爲5。還可以按照這樣的方式縮小Pod,這個特性在執行滾動升級時很有用。
當創建Replication Controller時,需要指定兩個東西:
-
Pod模板:用來創建Pod副本的模板
-
Label:Replication Controller需要監控的Pod的標籤。
現在已經創建了Pod的一些副本,那麼在這些副本上如何均衡負載呢?我們需要的是ServiceService
如果Pods是短暫的,那麼重啓時IP地址可能會改變,怎麼才能從前端容器正確可靠地指向後臺容器呢?
Service是定義一系列Pod以及訪問這些Pod的策略的一層抽象。Service通過Label找到Pod組。因爲Service是抽象的,所以在圖表裏通常看不到它們的存在,這也就讓這一概念更難以理解。
現在,假定有2個後臺Pod,並且定義後臺Service的名稱爲‘backend-service’,lable選擇器爲(tier=backend, app=myapp)。backend-service 的Service會完成如下兩件重要的事情:
-
會爲Service創建一個本地集羣的DNS入口,因此前端Pod只需要DNS查找主機名爲 ‘backend-service’,就能夠解析出前端應用程序可用的IP地址。
-
現在前端已經得到了後臺服務的IP地址,但是它應該訪問2個後臺Pod的哪一個呢?Service在這2個後臺Pod之間提供透明的負載均衡,會將請求分發給其中的任意一個(如下面的動畫所示)。通過每個Node上運行的代理(kube-proxy)完成。這裏有更多技術細節。
下述動畫展示了Service的功能。注意該圖作了很多簡化。如果不進入網絡配置,那麼達到透明的負載均衡目標所涉及的底層網絡和路由相對先進。如果有興趣,這裏有更深入的介紹。
有一個特別類型的Kubernetes Service,稱爲'LoadBalancer',作爲外部負載均衡器使用,在一定數量的Pod之間均衡流量。比如,對於負載均衡Web流量很有用。
service的類型
- ClusterIP 默認模式,只能在集羣內部訪問
- NodePort 在每個節點上都監聽一個同樣的端口號(30000-32767),ClusterIP和路由規則會自動創建。集羣外部可以訪問:聯繫到集羣內部服務,可以配合外部負載均衡使用
- LoadBalancer 要配合支持公有云負載均衡使用比如GCE、AWS。其實也是NodePort,只不過會把:自動添加到公有云的負載均衡當中
- ExternalName 創建一個dns別名指到service name上,主要是防止service name發生變化,要配合dns插件使用
Node
節點(上圖橘色方框)是物理或者虛擬機器,作爲Kubernetes worker,通常稱爲Minion。每個節點都運行如下Kubernetes關鍵組件:
- Kubelet:是主節點代理。
- Kube-proxy:Service使用其將鏈接路由到Pod,如上文所述。
- Docker或Rocket:Kubernetes使用的容器技術來創建容器。
Kubernetes Master
集羣擁有一個Kubernetes Master(紫色方框)。Kubernetes Master提供集羣的獨特視角,並且擁有一系列組件,比如Kubernetes API Server。API Server提供可以用來和集羣交互的REST端點。master節點包括用來創建和複製Pod的Replication Controller。
Deployment
- Deployment:負責控制Pod的生命週期、保證服務有一定數量的Pod在運行。Deployment定義了Pod內容,包括Pod數量、更新方式、使用的鏡像,資源限制等等。
- StatefulSet:管理應用程序的工作負載 API 對象,且該應用程序爲有狀態的應用程序。
- DaemonSet:確保所有或部分節點上運行 Pod,例如日誌採集。
- Job:一個 Job 創建一個或多個 Pod,直至運行結束。
- CronJob:定時運行的 Job 任務。
Ingress
通常情況下,service和pod僅可在集羣內部網絡中通過IP地址訪問。所有到達邊界路由器的流量或被丟棄或被轉發到其他地方。從概念上講,可能像下面這樣:
internet --> service
Ingress是授權入站連接到達集羣服務的規則集合。
internet -->ingress --> service
你可以給Ingress配置提供外部可訪問的URL、負載均衡、SSL、基於名稱的虛擬主機等。用戶通過POST Ingress資源到API server的方式來請求ingress。 Ingress controller負責實現Ingress,通常使用負載平衡器,它還可以配置邊界路由和其他前端,這有助於以HA方式處理流量。
Ingress與騰訊雲的CLB類似,可以提供根據url進行轉發的功能,與Service最根本的區別就是Service不能根據url進行轉發只能定義端口轉發與負載方式如公網訪問,集羣內訪問等。兩者互補。
(K8S是使用IP tables的nat表進行轉發,騰訊針對IP tables在大併發情況下的性能差二次開發了IPVS)
NameSpace
對資源進行隔離,不同NameSpace空間的資源無法互相訪問,可不同業務分配不同的命名空間。
當團隊或項目中具有許多用戶時,可以考慮使用Namespace來區分,a如果是少量用戶集羣,可以不需要考慮使用Namespace,如果需要它們提供特殊性質時,可以開始使用Namespace。Namespace爲名稱提供了一個範圍。資源的Names在Namespace中具有唯一性。
Namespace是一種將集羣資源劃分爲多個用途(通過 resource quota)的方法。
在未來的Kubernetes版本中,默認情況下,相同Namespace中的對象將具有相同的訪問控制策略。對於稍微不同的資源沒必要使用多個Namespace來劃分,例如同意軟件的不同版本,可以使用labels(標籤)來區分同一Namespace中的資源。
Persistent Volumes(PV)
集羣內的存儲資源,例如節點是集羣的資源。PV 獨立於 Pod 的生命週期,根據不同的 StorageClass 類型創建不同類型的 PV。
Persistent Volume 簡稱PV是一個K8S資源對象,我們可以單獨創建一個PV。它不和Pod直接發生關係,而是通過Persistent Volume Claim,簡稱PVC來實現動態綁定。Pod定義裏指定的是PVC,然後PVC會根據Pod的要求去自動綁定合適的PV給Pod使用。
PersistentVolumeClaim(PVC)
PersistentVolumeClaim(PVC):集羣內的存儲請求。例如,PV 是 Pod 使用節點資源,PVC 則聲明使用 PV 資源。當 PV 資源不足時,PVC 也可以動態創建 PV。
服務的自動擴容算法
服務自動擴縮容後臺組件會定期(30s)向騰訊云云監控拉取容器和 POD 的監控指標,然後根據該指標當前值,當前副本數和該指標目標值計算出目標副本數,然後以該目標副本數作爲服務的期望副本數,達到自動伸縮的目的。 比如當前有 2 個實例, 平均 CPU 利用率爲 90%,服務自動伸縮設置目標 CPU 爲 60%, 則自動調整實例數量爲:90% * 2 / 60% = 3 個。如果用戶設置了多個彈性伸縮指標,HPA 會依據各個指標,分別計算出目標副本數,然後取最大的一個作爲最終目標副本數。—TKE文檔中心
Node的自動擴容
K8S核心組件
Kubernetes遵循master-slave architecture。Kubernetes的組件可以分爲管理單個的 node 組件和控制平面的一部分的組件。
Kubernetes Master是集羣的主要控制單元,用於管理其工作負載並指導整個系統的通信。Kubernetes控制平面由各自的進程組成,每個組件都可以在單個主節點上運行,也可以在支持high-availability clusters的多個主節點上運行。
Kubernetes主要由以下幾個核心組件組成:
核心組件結構圖
除了核心組件,還有一些推薦的Add-ons:
實操篇
服務的自動擴容
自動擴容其實是K8S判斷POD的一些硬件指標(CPU使用率,帶寬等)是否達到了預警值,如果達到了,就行擴容,沒有到不變
命令行方式實現
kubectl autoscale deployment php-apache --min=1 --max=10 --cpu-percent=50
最小Pod數量爲1,最大爲10,當CPU使用率超過50%時觸發
yaml文件中指定
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1beta1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 50
TKE 控制檯創建Deployment時指定
有狀態的服務如何通過deployment創建
鏡像的對接
1.先從docker hub上找到nginx 或tomcat指定版本的官方Dokcer file構建生成基礎鏡像,並推到私有倉庫中
基礎openresty鏡像例子:
# Dockerfile - alpine
# https://github.com/openresty/docker-openresty
ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.9"
FROM ${RESTY_IMAGE_BASE}:${RESTY_IMAGE_TAG}
LABEL maintainer="Evan Wies <[email protected]>"
# Docker Build Arguments
ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.9"
ARG RESTY_VERSION="1.15.8.1"
ARG RESTY_OPENSSL_VERSION="1.1.1c"
ARG RESTY_PCRE_VERSION="8.42"
ARG RESTY_J="1"
ARG RESTY_CONFIG_OPTIONS="\
--with-compat \
--with-file-aio \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_geoip_module=dynamic \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_image_filter_module=dynamic \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-http_xslt_module=dynamic \
--with-ipv6 \
--with-mail \
--with-mail_ssl_module \
--with-md5-asm \
--with-pcre-jit \
--with-sha1-asm \
--with-stream \
--with-stream_ssl_module \
--with-threads \
"
ARG RESTY_CONFIG_OPTIONS_MORE=""
ARG RESTY_LUAJIT_OPTIONS="--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT'"
ARG RESTY_ADD_PACKAGE_BUILDDEPS=""
ARG RESTY_ADD_PACKAGE_RUNDEPS=""
ARG RESTY_EVAL_PRE_CONFIGURE=""
ARG RESTY_EVAL_POST_MAKE=""
# These are not intended to be user-specified
ARG _RESTY_CONFIG_DEPS="--with-openssl=/tmp/openssl-${RESTY_OPENSSL_VERSION} --with-pcre \
--with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include' \
--with-ld-opt='-L/usr/local/openresty/pcre/lib -Wl,-rpath,/usr/local/openresty/pcre/lib' \
"
LABEL resty_image_base="${RESTY_IMAGE_BASE}"
LABEL resty_image_tag="${RESTY_IMAGE_TAG}"
LABEL resty_version="${RESTY_VERSION}"
LABEL resty_openssl_version="${RESTY_OPENSSL_VERSION}"
LABEL resty_pcre_version="${RESTY_PCRE_VERSION}"
LABEL resty_config_options="${RESTY_CONFIG_OPTIONS}"
LABEL resty_config_options_more="${RESTY_CONFIG_OPTIONS_MORE}"
LABEL resty_config_deps="${_RESTY_CONFIG_DEPS}"
LABEL resty_add_package_builddeps="${RESTY_ADD_PACKAGE_BUILDDEPS}"
LABEL resty_add_package_rundeps="${RESTY_ADD_PACKAGE_RUNDEPS}"
LABEL resty_eval_pre_configure="${RESTY_EVAL_PRE_CONFIGURE}"
LABEL resty_eval_post_make="${RESTY_EVAL_POST_MAKE}"
# 1) Install apk dependencies
# 2) Download and untar OpenSSL, PCRE, and OpenResty
# 3) Build OpenResty
# 4) Cleanup
RUN apk add --no-cache --virtual .build-deps \
build-base \
coreutils \
curl \
gd-dev \
geoip-dev \
libxslt-dev \
linux-headers \
make \
perl-dev \
readline-dev \
zlib-dev \
${RESTY_ADD_PACKAGE_BUILDDEPS} \
&& apk add --no-cache \
bash \
bash-doc \
bash-completion \
gd \
geoip \
libgcc \
libxslt \
zlib \
${RESTY_ADD_PACKAGE_RUNDEPS} \
&& cd /tmp \
&& if [ -n "${RESTY_EVAL_PRE_CONFIGURE}" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi \
&& curl -fSL https://www.openssl.org/source/openssl-${RESTY_OPENSSL_VERSION}.tar.gz -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
&& tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
&& curl -fSL https://ftp.pcre.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz \
&& tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz \
&& cd /tmp/pcre-${RESTY_PCRE_VERSION} \
&& ./configure \
--prefix=/usr/local/openresty/pcre \
--disable-cpp \
--enable-jit \
--enable-utf \
--enable-unicode-properties \
&& make -j${RESTY_J} \
&& make -j${RESTY_J} install \
&& cd /tmp \
&& curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz \
&& tar xzf openresty-${RESTY_VERSION}.tar.gz \
&& cd /tmp/openresty-${RESTY_VERSION} \
&& if [[ "1.1.1" == $(echo -e "${RESTY_OPENSSL_VERSION}\n1.1.1" | sort -V | head -n1) ]] ; then \
echo 'patching Nginx for OpenSSL 1.1.1' \
&& cd bundle/nginx-1.15.8 \
&& curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.15.8-ssl_cert_cb_yield.patch | patch -p1 \
&& curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.15.8-ssl_sess_cb_yield.patch | patch -p1 \
&& cd ../.. ; \
fi \
&& eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS} \
&& make -j${RESTY_J} \
&& make -j${RESTY_J} install \
&& cd /tmp \
&& if [ -n "${RESTY_EVAL_POST_MAKE}" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi \
&& rm -rf \
openssl-${RESTY_OPENSSL_VERSION} \
openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} \
pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} \
&& apk del .build-deps \
&& ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log \
&& ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log
# Add additional binaries into PATH for convenience
ENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin:/bin/bash
# Copy nginx configuration files
COPY conf/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
#CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]
CMD ["bash"]
# Use SIGQUIT instead of default SIGTERM to cleanly drain requests
# See https://github.com/openresty/docker-openresty/blob/master/README.md#tips--pitfalls
STOPSIGNAL SIGQUIT
構建時使用docker build --tag 或構建完成後使用docker --tag imageid imagename:version
docker login url #登陸私有倉庫
docker tag 5787d71f774c shjrccr.ccs.tencentyun.com/yw/openresty:1.15.8.1-alpine-fat-apph5 #更改鏡像名稱
docker push shjrccr.ccs.tencentyun.com/yw /openresty:1.15.8.1-alpine-fat-apph5 #推送鏡像到私有倉庫
基於剛纔構建的openresty基礎鏡像,進行二次構建
業務nginx鏡像:
FROM shjrccr.ccs.tencentyun.com/yw/openresty:1.15.8.1-alpine-fat
MAINTAINER WQ
ADD conf/nginx.conf /usr/local/openresty/nginx/conf/
RUN mkdir -pv /app/public/view/ /app/logs
ADD pro/appH5 /app/public/view/
#CMD ["bash"]
CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]
將此業務鏡像推到私有倉庫即可
日誌的輸出與NFS類型的PV PVC
新建NFS服務器
安裝軟件包,啓動服務並添加至開機自啓
yum install -y rpcbind nfs-utils
systemctl start rpcbind
systemctl enable rpcbind
systemctl start nfs-server
systemctl enable nfs-server
修改配置文件,並重讀配置文件
[root@VM_1_11_centos ~]# cat /etc/exports
/opt/logs *(rw,sync,no_root_squash)
exportfs -r
命令行方式創建pv,pvc
TKE 控制檯無法直接創建nfs pv和nfs pvc可在創建deployment時選擇已有nfs
登陸任意Node節點,創建PV
[root@VM_1_14_centos k8s_test]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvnfs 50Gi RWO Retain Bound default/nfsclaim pvnfs 2d23h
[root@VM_1_14_centos k8s_test]# kubectl create -f pv_nfs.yaml
pv_nfs.yaml實例
apiVersion: v1
kind: PersistentVolume
metadata:
name: pvnfs
namespace: default
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
nfs:
path: /opt/logs
server: 10.2.1.11
storageClassName: pvnfs
創建pvc
[root@VM_1_14_centos k8s_test]# kubectl create -f pvc_nfs.yaml
[root@VM_1_14_centos k8s_test]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfsclaim Bound pvnfs 50Gi RWO pvnfs 2d23h
pvc_nfs.yaml實例:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nfsclaim
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: pvnfs
創建deployment
[root@VM_1_14_centos k8s_test]# kubectl create -f nginx_deployment.yaml
[root@VM_1_14_centos k8s_test]# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
lbapph5 3 3 3 3 2d22h
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-apph5
labels:
app: nginx-deployment-apph5
vers: v02
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment-apph5
vers: v02
template:
metadata:
labels:
app: nginx-deployment-apph5
vers: v02
spec:
containers:
- image: shjrccr.ccs.tencentyun.com/yw/openresty:v1apph5v0.2
imagePullPolicy: IfNotPresent
name: apph5v02
volumeMounts:
- mountPath: "/app/logs/"
name: nginx-nfs-pvc
imagePullSecrets:
- name: w-dr
volumes:
- name: nginx-nfs-pvc
persistentVolumeClaim:
claimName: nfsclaim
service的創建
[root@VM_1_14_centos k8s_test]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.16.255.1 443/TCP 6d23h
lbapph5 LoadBalancer 172.16.255.45 211.159.251.238 8000:30709/TCP 2d22h
[root@VM_1_14_centos k8s_test]# kubectl create -f service.yaml
實例:
apiVersion: v1
kind: Service
metadata:
name: apph5-service
labels:
name: apph5-service
spec:
type: NodePort #這裏代表是NodePort類型的
ports:
- port: 80 #這裏的端口和clusterIP(10.97.114.36)對應,即10.97.114.36:80,供內部訪問。
targetPort: 8000 #端口一定要和container暴露出來的端口對應,nodejs暴露出來的端口是8081,所以這裏也應是8081
protocol: TCP
nodePort: 32143 # 所有的節點都會開放此端口,此端口供外部調用。
selector:
app: nginx-deployment-apph5
vers: v02
創建方式:
- 可直接通過kuberctl create/apply -f servicename.yaml
- 也可通過TKE控制面板創建
service 與CLB綁定
service類型選擇NodePort,CLB綁定Node節點
登陸nfs服務器查看日誌
多個容器日誌會吐到同一文件
K8S相關角色配置文件示例
Node
有兩種創建方式:
- 新增節點
- 添加已有節點
Pod
實例:
apiVersion: v1
kind: Pod
metadata:
name: apph5pod
spec:
containers:
- name: apph5pod
image: shjrccr.ccs.tencentyun.com/yw/openresty:v1apph5v0.1
imagePullPolicy: Always
imagePullSecrets:
- name: w-dr
在任意一臺Node上面通過命令kubectl 創建
kubectl [option] name
kubectl get podname -o wide/json/…
創建Pod以及查看:
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
apph5pod 1/1 Running 0 15m
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
[root@VM_1_14_centos k8s_test]# kubectl delete pod apph5pod
pod “apph5pod” deleted
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
[root@VM_1_14_centos k8s_test]# kubectl create -f pod.yaml
pod/apph5pod created
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
apph5pod 1/1 Running 0 4s
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
PV
硬盤類型PV實例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
qcloudCbs:
cbsDiskId: disk-qlaxhjzq ## 指定已有的CBS id
fsType: ext4
storageClassName: cbs
NFS類型實例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pvnfs
namespace: default
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
nfs:
path: /opt/logs
server: 10.2.1.11
storageClassName: pvnfs
accessModes:
- ReadWriteOnce:數據卷能夠在一個節點上掛載爲讀寫目錄
- ReadWriteMany:數據卷能夠在多個節點上掛載爲讀寫目錄
- ReadOnlyMany: 數據卷能夠在多個節點上掛載爲讀寫目錄
PV回收策略:
-
Retain:PV釋放後,需要人工進行回收操作
- Recycle:PV釋放後,K8S自動進行清理,清理成功後PV則可以在此綁定使用,目前只有NFS和HostPath類型的PV支持回收策略。當執行回收策略時,會創建一個PV Recycler Pod,這個Pod執行清理操作,即刪除PV目錄下的所有文件 含隱藏文件。
創建方式:
- 可直接通過kuberctl create/apply -f pv.yaml
- 也可以通過TKE控制檯創建,控制檯只能創建硬盤類型的PV
POD
apiVersion: v1 //版本
kind: pod //類型,pod
metadata: //元數據
name: String //元數據,pod的名字
namespace: String //元數據,pod的命名空間
labels: //元數據,標籤列表
- name: String //元數據,標籤的名字
annotations: //元數據,自定義註解列表
- name: String //元數據,自定義註解名字
spec: //pod中容器的詳細定義
containers: //pod中的容器列表,可以有多個容器
- name: String
image: String //容器中的鏡像
imagesPullPolicy: [Always|Never|IfNotPresent]//獲取鏡像的策略
command: [String] //容器的啓動命令列表(不配置的話使用鏡像內部的命令)
args: [String] //啓動參數列表
workingDir: String //容器的工作目錄
volumeMounts: //掛載到到容器內部的存儲卷設置
- name: String
mountPath: String
readOnly: boolean
ports: //容器需要暴露的端口號列表
- name: String
containerPort: int //容器要暴露的端口
hostPort: int //容器所在主機監聽的端口(容器暴露端口映射到宿主機的端口)
protocol: String
env: //容器運行前要設置的環境列表
- name: String
value: String
resources: //資源限制
limits:
cpu: Srting
memory: String
requeste:
cpu: String
memory: String
livenessProbe: //pod內容器健康檢查的設置
exec:
command: [String]
httpGet: //通過httpget檢查健康
path: String
port: number
host: String
scheme: Srtring
httpHeaders:
- name: Stirng
value: String
tcpSocket: //通過tcpSocket檢查健康
port: number
initialDelaySeconds: 0//首次檢查時間
timeoutSeconds: 0 //檢查超時時間
periodSeconds: 0 //檢查間隔時間
successThreshold: 0
failureThreshold: 0
securityContext: //安全配置
privileged: falae
restartPolicy: [Always|Never|OnFailure]//重啓策略
nodeSelector: object //節點選擇
imagePullSecrets:
- name: String
hostNetwork: false //是否使用主機網絡模式,默認否
volumes: //在該pod上定義共享存儲卷
- name: String
meptyDir: {}
hostPath:
path: string
secret: //類型爲secret的存儲卷
secretName: String
item:
- key: String
path: String
configMap: //類型爲configMap的存儲卷
name: String
items:
- key: String
path: String
健康檢測
livenessProbe:
failureThreshold: 5
httpGet:
path: /demo/sql
port: 9000
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 30
name: sim-credit-auto
readinessProbe:
failureThreshold: 5
httpGet:
path: /demo/sql
port: 9000
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 30
PVC
NFS-PV實例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-ali
namespace: sim-bis
labels:
pv: pv-nfs-ali
spec:
capacity:
storage: 500Mi
accessModes:
- ReadWriteOnce
nfs:
path: /sim/bis/tomcat/ali
server: 10.2.1.6
storageClassName: sim-b-tomcat
指定pv的PVC實例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-ali
namespace: sim-b
labels:
pv: pv-nfs-ali
spec:
capacity:
storage: 500Mi
accessModes:
- ReadWriteOnce
nfs:
path: /sim/bis/tomcat/ali
server: 10.2.1.6
storageClassName: sim-b-tomcat
創建方式:
- 可直接通過kuberctl create/apply -f pvc.yaml
- 也可通過TKE控制面板創建
Deployment
實例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dm-tomcat-auto
labels:
app: dm-tomcat-auto
vers: v01
namespace: sim-credit
spec:
replicas: 1
selector:
matchLabels:
app: dm-tomcat-auto
vers: v01
template:
metadata:
labels:
app: dm-tomcat-auto
vers: v01
spec:
containers:
- image: shjrccr.ccs.tencentyun.com/sim_credit/tomcat_base:v01
imagePullPolicy: Always
name: dm-tomcat-auto
livenessProbe:
httpGet:
path: /demo/sql
port: 9000
# host: localhost
scheme: HTTP
initialDelaySeconds: 90
timeoutSeconds: 10
volumeMounts:
- mountPath: "/opt/apache-tomcat-8.5.14/webapps/"
name: pvc-nfs-auto-war
- mountPath: "/opt/apache-tomcat-8.5.14/logs/"
name: pvc-nfs-auto-log
imagePullSecrets:
- name: qcloudregistrykey
volumes:
- name: pvc-nfs-auto-war
persistentVolumeClaim:
claimName: pvc-nfs-auto-war
- name: pvc-nfs-auto-log
persistentVolumeClaim:
claimName: pvc-nfs-auto-log
創建方式:
- 可直接通過kuberctl create/apply -f deploymentname.yaml
- 也可通過TKE控制面板創建,控制面板創建會一起創建Service
service
apiVersion: v1
kind: Service
metadata:
name: apph5-service
labels:
name: apph5-service
spec:
type: NodePort #這裏代表是NodePort類型的
ports:
- port: 80 #這裏的端口和clusterIP(10.97.114.36)對應,即10.97.114.36:80,供內部訪問。
targetPort: 8000 #端口一定要和container暴露出來的端口對應,nodejs暴露出來的端口是8081,所以這裏也應是8081
protocol: TCP
nodePort: 32143 # 所有的節點都會開放此端口,此端口供外部調用。
selector:
app: nginx-deployment-apph5
vers: v02
Docker鏡像相關
鏡像對比
- alpine 小巧,只有5M,依賴包較少
- centos 200M左右,各種依賴包,字體等全
基礎鏡像
K8S命令
1、kubectl create -f nginx-deployment.yaml
2、查看deployment
kubectl get deployment
3、查看pod
kubectl get pod -o wide
4、測試pod訪問
curl --head 10.2.83.17
5、更新deployment
kubectl set image deployment/nginx-deployment nginx=nginx:v2 --record
6、查看更新後的deployment
kubectl get deployment -o wide
7、查看更新歷史
kubectl rollout history deployment/nginx-deployment
8、查看具體某一個版本的升級歷史
kubectl rollout history deployment/nginx-deployment --record
9、快速回滾到上一個版本
kubectl rollout undo deployment/nginx-deployment
10、擴容到5各節點
kubectl scale deployment nginx-deployment --replicas=5
私有倉庫命名
問題總結篇
PV-NFS創建時accessModes選擇Many,PVC綁定PV失敗,選擇Once後成功,也可讓多個Pod共享訪問,控制檯只能選擇硬盤PV 單臺讀寫
主要看後端存貯,模式一定要一致,用來吐日誌NFS有性能瓶頸,推薦file beat,壓測NFS性能,容器標準輸出到宿主機,
service 綁定deployment時,label選擇不正確或少了,導致綁定不成功,訪問空白
service 對應Deployment的label
發佈藍鯨調用TKE的API
用NFS方式的war包 TKE一些特性無法實現
本地push鏡像到TKE鏡像倉庫 網速波動
deployment pod的labels 與deployment的labels必須相同
ingress本質就是clb,創建ingress會自動創建一個clb
應用型CLB有url匹配
service ingress 4層7層
pv一旦被pvc綁定後,就被該pvc獨佔,不能在與其他pvc綁定
pod 減少的時候會不會等待pod內的請求處理完成!
優雅關閉優雅關閉是指在pod準備關閉時,可能還需要做一些處理,比如保存數據等。這期間服務不會接受新的請求。kubernetes提供了優雅關閉的配置terminationGracePeriodSeconds: 60
在給pod發出關閉指令時,k8s將會給應用發送SIGTERM信號,程序只需要捕獲SIGTERM信號並做相應處理即可。配置爲k8s會等待60秒後關閉。
docker鏡像的 STOPSIGNAL SIGQUIT
超過等待時間直接強制殺死POD
業務的代碼放在NFS中,更新重啓pod即可,鏡像在配置文件變更時在pull!
根據不同的路徑區分不同的版本
tomcat更改war包和解壓文件放到不同目錄!
pod的自動擴容頻率的間隔時長?
第一次擴 達到即擴容,兩次擴的間隔5分鐘,兩次收縮間隔3分鐘
秒殺活動不現實
pod的自動擴容數量爲現有pod的2倍,TKE是否同樣限制?是否可配置
突然過高併發流量導致pod阻塞,健康檢查無法通過導致服務崩潰?
初始pod數量調高 提高系統整體吞吐量,初始pod佔用資源調高 提升單個pod的可承受併發量
service對pod的負載規則?能否設置?權重,輪詢
輪詢
超出指定pod數量的pod實列多長時間會刪除和回收?
8個總量,實際佔用request的值
Terminating狀態的pod會如何處理?時長?
強制刪除pod
kubectl delete pod podname --force --grace-period 0 -n namespace
容器內有非空目錄(容器運行過程中) 其他情況
node的調度局部最優解和全局最優解:1.12版本後默認未局部最優解
千臺node不會出現調度器瓶頸
設置pod的自動擴容的實例數量範圍後,pod的數量並未自動擴容到範圍的下限數量
容器服務的概覽中的集羣資源使用量至少需要保持在30%~40%的可用率
此處的資源使用量計算:如果node的內存還剩0.5G 內存0.5G,這樣的node有4臺,會在資源使用量中生成2G CPU 2G內存,但pod請求的資源某一項超過0.5G則pod不會創建成功,會造成對pod數量的錯誤計算
健康檢測中就緒檢測只在容器初始化時檢測一次?
在壓測時未配置健康檢測,只配置了就緒檢測,但部分pod發現會重啓導致本來就承受不住併發流量的服務崩潰
有檢測時間間隔
健康檢查失敗 重啓,存活檢查失敗 流量不進入
server的Selectors只匹配到deployment不匹配pod?
因通過控制檯生成的deployment的label和pod的label相同
label匹配
hpa間隔60S獲取一次pod的擴容指標,2~3分鐘後擴容的pod恢復到最小數量
hpa獲取擴容指標時,有時會並不準確,關閉壓測了,並且hpa值已經下降,但下一分鐘的hpa值又飆升
待確定
多個應用放到同一個集羣,namespace隔離
CLB目前只能綁定主機
新增NODE,已有POD只等待下次調度,新的POD會分配到新的NODE
海通證券,QQ空間 微視 騰訊視頻
非核心交易都已容器化(兩年前),秒殺F5限流
前期規劃 容器給一個B端
pod同樣受所在NODE的安全組限制
日誌是filebeat 還是NFS
相關資料地址和網站
Docker官網
DockerHub官網
Kubernetes官網
Kubernetes中文文檔
十分鐘帶你理解Kubernetes核心概念
Kubernetes 編排系統
Docker與虛擬機的簡介以及比較