寫在前面:2020年面試必備的Java後端進階面試題總結了一份複習指南在Github上,內容詳細,圖文並茂,有需要學習的朋友可以Star一下!
GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master
1 前言
基於各種原因,團隊的 Kubernetes
被加了限制,必須在特定的 Node
纔可以部署。而之前沒有指定,所以 Spring Cloud Data Flow
在跑 Task
時失敗了,無法創建 Pod
。按照 Spring
官方文檔配置也一直沒用,後面查看源碼、修改源碼增加日誌後終於解決了。
2 配置無法生效
在自己定義 yaml
文件,並通過 kubectl apply
部署時,所添加的限制節點的內容是這樣的:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernetes.io/os
operator: In
values:
- linux
containers:
- name: php-apache
image: 'pkslow/hpa-example:latest'
ports:
- containerPort: 80
protocol: TCP
resources:
requests:
cpu: 200m
imagePullPolicy: IfNotPresent
這樣設置是可以成功部署的。
修改 Data Flow
的配置如下:
spring:
cloud:
dataflow:
task:
platform:
kubernetes:
accounts:
default:
limits:
memory: 1024Mi
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernetes.io/os
operator: In
values:
- linux
datasource:
url: jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT}/mysql
username: root
password: ${mysql-root-password}
driverClassName: org.mariadb.jdbc.Driver
testOnBorrow: true
validationQuery: "SELECT 1"
通過 Spring Cloud Data Flow
發佈 Task
,報錯如下:
Pods in namespace pkslow can only map to specific nodes, status=Failure
查看官網,按照 官方的格式 修改配置:
修改如下:
spring:
cloud:
dataflow:
task:
platform:
kubernetes:
accounts:
default:
limits:
memory: 1024Mi
affinity:
nodeAffinity: { requiredDuringSchedulingIgnoredDuringExecution: { nodeSelectorTerms: [ { matchExpressions: [ { key: 'beta.kubernetes.io/os', operator: 'In', values: [ 'linux']}]}]}}
依舊報錯。改成 affinity.nodeAffinity=xxx
,還是報錯。加引號,也沒用。
查看日誌,也沒有太多信息。
折騰了許久,也沒太大進展。於是就查看源碼了。
3 查看源碼
3.1 源碼下載
下載了 Spring Cloud Data Flow 的源碼,看了一下,沒有多大用處,最終發佈到 Kubernetes
是通過 Spring Cloud Deployer Kubernetes
來發布的,於是又下載了 它的源碼 。要注意不要下載錯了版本,我們用的是 2.4.0
版本。或者直接下載所有,然後切換到對應分支:
$ git clone https://github.com/spring-cloud/spring-cloud-deployer-kubernetes.git
Cloning into 'spring-cloud-deployer-kubernetes'...
remote: Enumerating objects: 65, done.
remote: Counting objects: 100% (65/65), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 4201 (delta 26), reused 42 (delta 8), pack-reused 4136
Receiving objects: 100% (4201/4201), 738.79 KiB | 936.00 KiB/s, done.
Resolving deltas: 100% (1478/1478), done.
$ cd spring-cloud-deployer-kubernetes/
$ git branch
* master
$ git checkout 2.4.0
Branch '2.4.0' set up to track remote branch '2.4.0' from 'origin'.
Switched to a new branch '2.4.0'
$ git branch
* 2.4.0
master
先 build
一下,確保成功:
$ mvn clean install -DskipTests
3.2 添加日誌
查看源碼,也看不出爲何配置沒有生效,於是在關鍵點打些日誌出來看看。找到發佈 Task
的入口:
KubernetesTaskLauncher#launch(AppDeploymentRequest)
即類 KubernetesTaskLauncher
的 launch
方法。開始追蹤創建 Kubernetes Pod
的過程。
KubernetesTaskLauncher#launch(AppDeploymentRequest)
KubernetesTaskLauncher#launch(String, AppDeploymentRequest)
AbstractKubernetesDeployer#createPodSpec
DeploymentPropertiesResolver#getAffinityRules
然後在整個調用鏈增加日誌打印,注意日誌要加上特殊字符串,增加識別性,如:
logger.info("***pkslow log***:" + affinity.toString());
追加了日誌後,重新 build
包,替換掉 Data Flow
引入的 jar
包,重新發布即可測試。
通過新加的日誌,發現設置的 Properties
一直就是沒有生效的,但爲何沒生效尚未得知。
4 修改源碼
折騰了一圈還是沒解決,但項目又要急着使用,於是想了個辦法,先修改源碼,自己根據屬性使其生效:
如果沒有讀取到 Affinity
,就自己生成一個。
重新打包、替換、部署後,不再報錯,能正常執行 Task
了。
5 最終解決
之前的方案只是暫時解決,並不是一個好的辦法,還是要搞清楚爲何配置沒有生效。於是再次查看源碼。在查看類 KubernetesDeployerProperties
的時候,發現了一點端倪:
這裏的字段是沒有 Affinity
的。
另外,從測試用例入手(這是一個很好的思維,測試用例能告訴你很多信息),看到了 DataFlow
配置用例,如下:
所以,應該是不用配置前綴 Affinity
的,修改後配置如下:
spring:
cloud:
dataflow:
task:
platform:
kubernetes:
accounts:
default:
limits:
memory: 1024Mi
nodeAffinity: { requiredDuringSchedulingIgnoredDuringExecution: { nodeSelectorTerms: [ { matchExpressions: [ { key: 'beta.kubernetes.io/os', operator: 'In', values: [ 'linux']}]}]}}
重新部署後,可以了!!!
6 總結
這一次確實是被 Spring
坑了一把,沒有明確給出配置的示例,然後官方文檔給的提示也是極其誤導。一開始很難想到是不用前綴 Affinity
的,因爲 Kubernetes
的標準配置是有的,而 Spring
的官方文檔提示也是有的。實在太坑了!
還好,通過查看源碼及調試,終於解決了這個問題。