本文目錄一覽:
- 1、springboot2.X使用k8s的configmap
- 2、Jenkins-配置K8S負載
- 3、Kubernetes 的REST API指的是什麼?
- 4、給 運行在 k8s 里的 springboot 指定 jvm 參數
- 5、開發和運維對K8S中的應用都做了什麼?
springboot2.X使用k8s的configmap
處於項目需要使用kubernetes 的configmap作為配置中心。
這裡的 app-config 是configmap 的名稱可根據不同項目不同環境來自定義如: test-app-main-config 或者 test-redis-config 等等。
創建完成後 使用如下命令查看k8s中的configmap 我這裡查看的默認 namespace 下的cm 。
使用下列命令查看 configmap中的 內容
會把指定文件夾下的 文件都存入configmap中,這裡不展開贅述
這裡的 –from-literal 可以指定多個 key-value 鍵值對
創建的配置到此創建完畢。接下來說重點
配置完成後 reimport 一下
在springboot項目 — resources 文件下創建 bootstrap.yml 文件 如果有其他配置文件建議都移動到 自己新建一個文件下面
文件內容如下
這裡的 @ConfigurationProperties(prefix = “common.redis”) 需要注意 common.redis 這個東西是配置文件中讀取的前綴。需要更具自己的項目所用的配置來定義
如propertes 文件
創建RedisConfigProperties.java
自行寫個controller 來測試,當然我這邊也提供一個 方便大家複製粘貼
至此springboot 中獲取 configmap主要配置結束。本地如果有k8s環境則可以直接啟動訪 上面controller的連接來驗證是否載入了配置。
注意 如果使用 @Vaule 註解來獲取配置 時不會在configmap有變化的時候 獲取到變化的值
這個配置到算簡單。重點是在你的springboot項目部署到 pod 中時 會提示無法訪問 configmap 。是因為在k8s集群環境中 創建的 pod 默認使用的是 RBAC 模式授權 ,使用的是default的許可權,然而 default 許可權無法在pod內訪問到 APIservice 開放的 restful 介面。
思路:創建 RBAC 模式的 角色 和許可權
創建 config-reader-role.yml 文件 。
文件內容如下:
創建文件完成後直接執行如下命令:
創建完成後需要在我們創建部署的 deployment.yml 文件中指定 使用 config-reader 的許可權 。在下面節點
spec– template– spec 添加 serviceAccountName: config-reader
下面貼出 deployment.yml 文件內容:
如此依賴 啟動的 pod 內 springboot項目就能獲取到configmap 的配置文件了。
Jenkins-配置K8S負載
隨著Jenkins被大量使用,單台打包機完全無法應對打包慢,線程不夠等一系列問題
這時候可以添加固定Node的方式去解決問題,但是慢慢你會發現固定Node也無法解決問題,如果並不是超級多的打包任務,或者根本沒得使用K8S的這個條件請移步 Jenkins配置從節點 來解決單台打包機性能不夠的問題
其中最主要的矛盾如下
1.不同的打包環境指定不同的打包機
2.集中在一個時間段打包,特別是在發版本的前夕,所有項目組都在打包,顯得特別無力
3.大部分時間閑置的打包負載顯得有點浪費
這時候就急需一個可以動態縮放的Node來解決這個問題。
將K8S作為Jenkins負載就是為了解決動態縮放,不同環境需要指定不同打包機的問題(Windows和Mac還是需要單獨處理)。
官網文檔 在 Kubernetes 上擴展 Jenkins
首先在Jenkins中搜索 Kubernetes 這個插件,安裝上
配置K8S荷載
其中這個Kubernetes地址就是K8S-Api-Server的地址,可以在kube.config中找到
然後點擊連接測試,出現如下就對了,但是講道理會出現一個
找不到 /var/lib/jenkins/.kube/config.json 的錯誤,出現這個錯誤就要將kubeConfig放到這個位置
(Tips:如果你是Rancher搭建的K8S集群就在這個位置找API-Server的地址和kubeConfig)
這裡是比較重要的,Pod模板是為了方便打包的, jnlp 這個鏡像是必須要的,沒有這個鏡像就無法連接上Jenkins,這個鏡像是可以拓展的。
不建議再這個鏡像中安裝Docker,安裝Dotnet,安裝Java,安裝NodeJs,因為這些都可以用多容器和Jenkins插件來解決
可以在這個鏡像中安裝例如解壓縮這樣的小工具。
重寫的配置如下
這種K8S中的Node有一個很大的缺陷就是緩存的問題,如Nuget緩存,這時候就需要掛載一個盤去進行緩存了,有條件的建議掛載一個PVC,但是像我這樣沒條件的HostPath也香。
PS:這裡用Dotnet打包為例子
Dotnet打包需要用到的鏡像是dotnetsdk,所以需要在jnlp的基礎上再加上一個其他鏡像,使用的時候就
利用 container 這個指令去指定容器。後面的名稱就是容器模板中定義的名稱,需要唯一指定。
Dotnet打包要想快就要將Nuget的包全部緩存下來,所以需要將~/.nuget 這個文件夾裡面的東西用PV緩存起來(鄙人沒這個條件,用的HostPath)
使用 node 這個命令去指定節點
然後再NodeManager中查看就會看到出現了一個新的節點了,這個節點就是K8S中調度的,在打包完成後就會回收掉這個Pod。
到這裡為Jenkins配置K8S的負載就全部完畢了。
Kubernetes 的REST API指的是什麼?
REST API是Kubernetes系統的重要部分,組件之間的所有操作和通信均由API Server處理的REST API調用,大多數情況下,API定義和實現都符合標準的HTTP REST格式,可以通過 kubectl命令管理工具或其他命令行工具來執行。
API 版本
為了在兼容舊版本的同時不斷升級新的API,Kubernetes支持多種API版本,每種API版本都有不同的API路徑,例如/api/v1或 /apis/extensions/v1beta1。
API版本規則是通過基於API level選擇版本,而不是基於資源和域級別選擇,是為了確保API能夠描述一個清晰的連續的系統資源和行為的視圖,能夠控制訪問的整個過程和控制實驗性API的訪問。
JSON和Protobuf序列化模式遵循相同的模式變化原則,以下所有描述都涵蓋了這兩種模式。
需要注意,API版本和軟體的版本沒有直接關係,不同API版本有不同程度穩定性,API文檔中詳細描述了每個級別的標準。
Alpha級別:
包含alpha名稱的版本(例如v1alpha1)。
該軟體可能包含錯誤。啟用一個功能可能會導致bug。默認情況下,功能可能會被禁用。
隨時可能會丟棄對該功能的支持,恕不另行通知。
API可能在以後的軟體版本中以不兼容的方式更改,恕不另行通知。
該軟體建議僅在短期測試集群中使用,因為錯誤的風險增加和缺乏長期支持。
Beta級別:
包含beta名稱的版本(例如v2beta3)。
該軟體經過很好的測試。啟用功能被認為是安全的。默認情況下功能是開啟的。
細節可能會改變,但功能在後續版本不會被刪除
對象的模式或語義在隨後的beta版本或Stable版本中可能以不兼容的方式發生變化。如果這種情況發生時,官方會提供遷移操作指南。這可能需要刪除、編輯和重新創建API對象。
該版本在後續可能會更改一些不兼容地方,所以建議用於非關鍵業務,如果你有多個可以獨立升級的集群,你也可以放寬此限制。
大家使用過的Beta版本後,可以多給社區反饋,如果此版本在後續更新後將不會有太大變化。
Stable級別:
該版本名稱命名方式:vX這裡X是一個整數。
Stable版本的功能特性,將出現在後續發布的軟體版本中。
Kubernetes API 概述
給 運行在 k8s 里的 springboot 指定 jvm 參數
我們知道,對於 tomcat 來說,設置 JAVA_OPTS 就可以給 jvm 設置一些參數, 比如 -Xms -Xmx 之類的堆大小參數
但是 對於 Spring boot 來說,因為是直接運行 java -jar 的,除非你修改 dockerfile , 不然直接設置 JAVA_OPTS 是沒有效果的
最近在網上找了一些資料,得到了答案,分享到這裡
如果容器是直接運行 tomcat 的, 那麼 入口其實是指定運行 catalina.sh
JAVA_OPTS 是 catalina.sh 使用到的一個環境變數,在運行 org.apache.catalina.startup.Bootstrap 前, 會把 JAVA_OPTS 參數拼到前面
所以這是我們直接在 k8s yaml 里設置變數 JAVA_OPTS 可以生效的原因
大概看下 catalina.sh
Spring boot 項目打出來的一般是 jar , 我們的 dockerfile 入口一般也是 java -jar xxx.jar
修改 dockerfile, 變成 java $JAVA_OPTS -jar xxx.jar 思路肯定是可行的,但是裡面有些坑,
此處不詳細描述,可以見 stackoverflow
在不修改 dockerfile 的情況下有一種很簡單的方法,可以達到傳遞 jvm 參數的效果
就是使用 JAVA_TOOL_OPTIONS
我們以 初始堆大小 參數為例,來看一下
我們什麼環境變數都不加
可以看到默認 大小是 24MB
命令解釋一下:
執行三個命令
jps 看下運行的java進程pid 是啥
jinfo -flag InitialHeapSize {pid} 看下 初始堆大小參數是多少, 去掉 -flag InitialHeapSize 看所有的參數(具體看jvm廠商有沒有實現這個功能,據我所知,oracle 的 openjdk 實現了,IcedTea的OpenJdk沒有實現)
echo $(( {size} 10 10)) 位運算,jinfo 輸出的是 byte, 除以1024 是 KB, 再除以1024 是 MB, 1024=2^10,所以除以1024等於位運算右移10位,計算更快
JAVA_OPTS -XX:InitialHeapSize=66m
可以看到 還是 24MB
細心的應該注意到了 exec 的 pod name 變了,因為我修改了環境變數,需要重啟,重啟之後pod name 自然就變了
可以看到 變成 66MB 了,符合我們的設置
另外,執行 jps 的時候,就輸出了 Picked up JAVA_TOOL_OPTIONS: -XX:InitialHeapSize=66m
前面兩種場景是沒有輸出的哦
開發和運維對K8S中的應用都做了什麼?
在應用的整個生命周期里,開發和運維都和它密不可分。一個塑造它,一個保養它。
如果應用需要部署到K8S中,開發和運維在其中都做了什麼呢?
從開發側來說,我們的應用應該具備以下能力:
健康 檢測介面用於檢測應用的 健康 狀態,在K8S中,使用Readiness和Liveness分別來探測應用是否就緒和是否存活,如果未就緒或者未存活,K8S會採取相應的措施來確保應用可用。
如果我們應用未定義好相應的 健康 檢測介面,K8S就無法判斷應用是否正常可用,整個應用對我們來說就是黑匣子,也就談不上應用穩定性了。
定義一個簡單的 健康 檢測介面如下:
如上我們定義了 health 介面,當應用啟動後,只需要探測這個介面,如果返回OK,表示應用是正常的。
當然,上面的介面是非常簡單的,在實際情況下,應用本身也許還依賴起來應用,比如redis,mysql,mq等,如果它們異常,應用是不是異常的呢?那我們的應用 健康 檢測需不需要檢測其他應用的 健康 狀態呢?
既然我們定義好了 健康 檢測介面,那我們的YAML模板就可以增加 健康 檢測功能,如下:
應用發版是常規不能再常規的操作,通常情況下都是滾動更新的方式上線,也就是先起一個新應用,再刪一個老應用。
如果這時候老應用有部分的流量,突然把老應用的進程殺了,這部分流量就無法得到正確的處理,部分用戶也會因此受到影響。
怎麼才會不受影響呢?
假如我們在停止應用之前先告訴網關或者註冊中心,等對方把我們應用摘除後再下線,這樣就不會有任何流量受到影響了。
在K8S中,當我們要刪除Pod的時候,Pod會變成Terminating狀態,kubelet看到Pod的狀態如果為Terminating,就會開始執行關閉Pod的流程,給Pod發SIGTERM信號,如果達到寬限期Pod還未結束就給Pod發SIGKILL信號,從Endpoints中摘除Pod等。
從上面可知,Pod在停止之前會收到SIG信號,如果應用本身沒有處理這些信號的能力,那應用如果知道什麼時候該結束呢?
下面簡單定義一個處理SIG信號的功能。
當接收到SIG信號的時候,就會調用 Shutdown 方法做應用退出處理。
除此,還要結合K8S的 PreStop Hook 來定義結束前的鉤子,如下:
如果使用註冊中心,比如nacos,我們可以在 PreStop Hook 中先告訴nacos要下線,如下:
Metrics主要用來暴露應用指標,可以根據實際情況自定義指標,以便於監控工具Prometheus進行數據收集展示。
有些語言有現成的exporter,比如java的jmx_exporter,沒有的就需要自己在應用中集成。
比如:
這種會暴露默認的Http指標,可以通過 curl 127.0.0.1:9527/metrics 獲取指標。
如果需要自定義指標的話,只需按規則定義即可,如下:
這樣就定義了 httpserver_request_total 和 httpserver_request_duration_seconds 指標,引用過後就能在 /metrics 中看到對應的數據。
定義好了指標,下面就是收集了。既可以通過自定義收集規則收集,也可以通過自動發現的方式收集,為了方便,主要採用自動發現的方式。
我們只需要在deployment的templates中定義好annotation,prometheeus就會自動添加採集目標,如下:
Trace用於跟蹤,每個請求都會生成一個 TraceID ,這個ID會伴隨請求的整個生命周期,我們也可以根據這個ID查詢請求的整個鏈路情況。
鏈路追蹤,目前市面上有很多開源系統,比如Skywalking,Jeager,Zipkin等,它們各有各的特點,如下。
我比較推薦使用Jaeger,它是CNCF的畢業項目,成長空間和雲原生的系統架構兼容性比較好。
不過,我這裡採用的Skywalking。
Skywalking有許多現成的客戶端,比如Java、Python等,可以直接使用,它們都會自動埋點,但是對於Go來說就只有自己手動埋點了,需要我們自己去寫代碼。
比如:
定義reporter用於上報數據給Skywalking,這就是一個簡單的集成Trace的例子。
應用的可觀測性主要來源日誌、監控、鏈路追蹤,標準的日誌有利於日誌收集以及排查問題。
原則上,不論是什麼類型的日誌輸出,什麼格式的日誌內容,都能收集。但是為了方便友好,建議把日誌輸出到標準輸出,這樣收集更方便。
我個人理解,在K8s中,完全沒必要把日誌輸出到文件,浪費不說,沒多大意義,因為所有的日誌我們都會收集到日誌系統,而輸出到文件的日誌也會隨著應用發版而丟失,所以輸出到文件的意義是什麼呢?
開發把系統開發完,就會交付給運維部署。為了保障應用的穩定性,運維在部署應用的時候應該考慮以下幾點。
K8S中可以部署有狀態應用,也可以部署無狀態應用。對於有狀態應用,我其實很少部署到K8S中,大部分還是部署的無狀態應用,至於為什麼,用多了就曉得了。
對於業務應用,強烈建議使其保持無狀態,就算有需要持久化的東西,要麼保存到資料庫,要麼保存到對象存儲或者其他單獨的文件系統中,不要掛載到應用Pod上。
這樣的好處是,應用和數據是分開的,應用可以隨意啟停、擴展、遷移等。
保持高可用應該是每個運維人員的使命。
在K8S中,我們應該怎麼配置呢?(1)應用Pod應該是多副本
(2)應用Pod之間做反親和性,避免同一應用調度到同一台主機,如下。
(3) 為了避免應用因為節點維護等原因驅逐Pod,導致全部Pod被驅逐,特別配置了PodDisruptionBudget,保障應用至少有一個可用,如下。
(4)如果某個節點因為一些原因需要驅逐一些Pod,為了避免重要應用被驅逐,應該給應用配置較高的QoS,如下:
所謂優雅上線能力,就是要確保應用能夠提供服務了,再接入外界流量,不能在還沒完全啟動的情況下就提供服務。
在K8S中,應用在啟動後會加入endpoints中,然後通過service接入流量,那在什麼情況下才算啟動成功呢?主要是通過K8S的 ReadinessProbe 來進行檢測。這時候開發的 健康 檢測介面就派上用場了,如下:
所以我們K8S的YAML文件應該加上如上的配置。
所謂異常自愈,就是應用本身在出現Crash,或者應用Pod所在節點出現異常的情況,應用能夠自動重啟或者遷移。這時候就需要通過K8S的 LivenessProbe 來進行檢測了,如下。
當K8S的YAML清單加上如上配置過後,就會定時去探測應用是否正常,如果異常,就會觸發重啟的動作。如果是節點異常,K8S會對Pod進行重新調度。
應用通過HTTPS訪問是比較常見的,企業級應用建議自己購買相應的SSL證書,然後進行配置即可。
比如。
上面介紹了開發和運維對於應用上線應該做的工作, 不全但夠用 。
在不同的企業都有不同的尿性,但是作為運維,我們都要牢牢記住 穩定 永遠是第一尿性。通過上面的梳理,我們的應用模板就整理如下:
如果我的文章對你有所幫助,還請幫忙一下,你的支持會激勵我輸出更高質量的文章,非常感謝!
你還可以把我的公眾號設為「 星標 」,這樣當公眾號文章更新時,你會在第一時間收到推送消息,避免錯過我的文章更新。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/200509.html