雲原生的概念愈來愈深刻人心,做爲典型技術之一的微服務架構,過去咱們還說它是一把雙刃劍,帶來必定好處的同時,對服務團隊的技術要求也提升了不少。可是,隨着開源技術的不斷髮展,愈來愈多優秀的技術和工具涌現出來,讓雲原生落地再也不困難。爲此,博雲研究院後續將不按期的總結整理雲原生相關的開發、測試、運維等方面的最佳實踐,藉助博雲和開源社區共同的力量,幫助客戶更加標準化、簡單化開啓雲原生之路。spring
基於Spring Boot框架開發微服務,並部署在Kubernetes集羣中,是如今不少企業的實施微服務的技術選型。微服務架構下,開發人員主要關注於所在服務團隊維護的微服務,一般狀況下這些微服務依賴於其它團隊開發的微服務,同時也被另一組微服務所依賴。docker
在微服務開發過程當中,一種傳統的作法是經過單元測試對代碼進行驗證,儘量早的發現問題,待相關服務開發基本完成之後,統一部署到Kubernetes集羣中進行聯調。這種方式下,一方面是開發人員花大量的時間設計測試用例,編寫測試代碼,還要爲每一個依賴的服務打樁;另外一方面,因爲集成的時間點比較晚,大量接口不一致致使的問題可能會在集成測試的過程當中集中爆發,形成人力物力的浪費。數據庫
若是將服務儘早的部署到Kubernetes測試環境中進行聯調測試,能夠提早發現問題。因爲部署的過程在開發過程當中須要反覆執行,因此不少企業搭建了CICD工具,比較常見的流程是:提交代碼 -> Jenkins 拉取源碼 -> Maven編譯 -> Docker鏡像構建 -> 部署 -> 測試。雖然該過程能夠自動完成,可是每次調試均須要經歷該步驟,耗時比較長,效率很低。同時,Kubernetes集羣內部的微服務的特色是,各微服務之間在集羣內能夠互相訪問,集羣外部沒有很好的方法來獲取集羣內部的功能,好比讀寫數據庫中的數據等,因此觀察服務的運行結果也是比較困難的事情,沒法提供像單體應用同樣本地單步調試的體驗。緩存
Telepresence是一款爲Kubernetes微服務框架提供快速本地化開發功能的開源軟件。Telepresence在Kubernetes集羣中運行的Pod中部署雙向網絡代理,該Pod將Kubernetes環境(如TCP鏈接,環境變量,卷)中的數據代理到本地進程。本地進程透明地覆蓋其網絡,以便DNS調用和TCP鏈接經過代理路由到遠程Kubernetes集羣,可以獲取遠端K8S集羣的各項資源。該工具能夠實現:tomcat
安裝kubectl命令行工具,並配置本地能夠訪問Kubernetes集羣。bash
安裝Telepresence工具網絡
在OS X中可以使用以下命令安裝Telepresence工具。架構
# brew cask install osxfuse
# brew install datawire/blackbird/telepresence
複製代碼
在集成測試環境的Kubernetes集羣中部署微服務。app
# kubectl get all
NAME READY STATUS RESTARTS AGE
demo-backend-7bb6cf9994-9qnxp 1/1 Running 0 118s
demo-frontend-84b7f5c75f-8r69n 1/1 Running 0 40h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/demo-backend ClusterIP 10.233.55.68 <none> 8080/TCP 40h
service/demo-frontend NodePort 10.233.17.241 <none> 8081:30001/TCP 40h
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/demo-backend 1 1 1 1 40h
deployment.apps/demo-frontend 1 1 1 1 40h
NAME DESIRED CURRENT READY AGE
replicaset.apps/demo-backend-7bb6cf9994 1 1 1 40h
replicaset.apps/demo-frontend-84b7f5c75f 1 1 1 40h
複製代碼
經過Kubernetes暴露的NodePort訪問應用訪問該應用,驗證服務沒有問題。框架
# curl http://10.20.1.71:30001/
Message from backend is: Hello from demo-backend-7bb6cf9994-9qnxp
複製代碼
# cd spring-cloud-kubernetes/demo-backend/
# telepresence \
--mount /tmp/known \
--swap-deployment demo-backend \
--docker-run \
--rm \
-v $(pwd):/build \
-v $HOME/.m2/repository:/m2 \
-v=/tmp/known/var/run/secrets:/var/run/secrets \
-p 8080:8080 \
-p 5005:5005 \
maven:3.6-jdk-8-alpine \
mvn \
Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005" \
-Dmaven.repo.local=/m2 \
-f /build \
spring-boot:run
複製代碼
參數詳細解析以下。
telepresence:啓動telepresence的命令;
--mount /tmp/known:告訴Telepresence將TELEPRESENCE_ROOT掛載到本地的/tmp/known目錄;
--swap-deployment foo:假設咱們已在集羣中運行名爲foo的Deployment,下一步將使用本地運行的進程進行替換;
--docker-run:告訴Telepresence接下來以Docker容器方式運行;
--rm:告訴Docker終止時丟棄以前建立的容器,不會對本地形成混亂;
-v$(pwd):/build:將當前目錄(pwd命令的結果)掛載到Docker容器內的文件夾/build中,這也是本地源代碼的位置;
-v $HOME/.m2/repository:/m2:安裝Maven緩存文件夾,這樣咱們就沒必要每次運行容器時都下載Maven組件;
-v=/tmp/known/var/run/secrets:/var/run/secrets:將上述的本地/tmp/known目錄下的secrets目錄掛載到本地容器的/var/run/secrets路徑下,相似Fabric8 Kubernetes Client的工具能夠經過該目錄讀取Secretes信息,就像容器是運行在Kubernetes內部同樣;
-p 8080:8080 -p 5005:5005:將本地容器的服務端口暴露出來,能夠在須要直接向服務發出請求時訪問該端口;
maven:3.6-jdk-8-alpine:這是咱們將用於構建和運行咱們的服務的鏡像,它包含了Maven和Java 8等工具;
mvn ... spring-boot:run:要在Docker容器中運行的命令。這裏它使用Spring Boot Maven插件,但您可使用構建工具所需的任何命令。它告訴maven指向已安裝的存儲庫緩存以及源代碼所在的位置
-Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005":表示爲服務打開5005遠程調試端口。在Telepresence的文檔中是經過MAVEN_OPTS參數傳遞Debug配置,該配置其實是對Maven進程開啓Debug模式,並非demo-backend應用,沒法提供遠程單步調試的能力。
-Dmaven.repo.local=/m2:表示本地Maven倉庫的位置;
-f /build:Maven構建時的主目錄,也即源代碼的根目錄;
spring-boot:run:spring-boot-maven-plugin插件發佈的Goal,用於啓動Spring Boot應用。
查看Kubernetes集羣中的Pod信息。能夠看到,以前的Pod demo-backend-7bb6cf9994-9qnxp已經被新的容器替換,使用的是Telepresence提供的鏡像。
# kubectl get pod
NAME READY STATUS RESTARTS AGE
demo-backend-c9df931b5c83411aad5a329ec9ecbcbb-5b4fdd7b-wzz9r 1/1 Running 0 11s
demo-frontend-84b7f5c75f-8r69n 1/1 Running 0 40h
複製代碼
查看本地Docker運行狀況。
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c7c10281a32c maven:3.6-jdk-8-alpine "/usr/local/bin/mvn-…" 35 seconds ago Up 33 seconds telepresence-1555471863-056155-58429
fd94d372f832 datawire/telepresence-local:0.98 "/sbin/tini -v -- py…" 44 seconds ago Up 43 seconds 0.0.0.0:5005->5005/tcp, 0.0.0.0:8080->8080/tcp, 127.0.0.1:64163->38022/tcp telepresence-1555471853-8663979-58429
複製代碼
確認本地開放了8080和5005端口。
# netstat -na | grep -E "5005|8080"
tcp6 0 0 ::1.5005 *.* LISTEN
tcp4 0 0 *.5005 *.* LISTEN
tcp6 0 0 ::1.8080 *.* LISTEN
tcp4 0 0 *.8080 *.* LISTEN
複製代碼
直接經過8080端口訪問本地的demo-backend服務。
# curl localhost:8080
Hello from demo-backend-c9df931b5c83411aad5a329ec9ecbcbb-5b4fdd7b-wzz9r
複製代碼
經過Kubernetes暴露的NodePort訪問應用,能夠看到此時到demo-backend的請求已經被轉發到本地運行的docker中。
# curl http://10.20.1.71:30001
Message from backend is: Hello from demo-backend-80d454f85d8b43118f5740d9f25260ba-854fcd9fbd-lzkb7
複製代碼
在demo-backend項目的pom文件中,配置了devtools的依賴。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
複製代碼
而當IntelliJ IDEA從新構建時,會更新該目錄下的文件demo-backend/target/classes。經過mvn spring-boot:run方式啓動應用時,Devtools監聽的classpath,也即上述目錄,當目錄內的文件發生變化後,會啓動restart,執行新的代碼。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.3.RELEASE) 11:17:44.328 [restartedMain] INFO c.b.s.c.k.b.KubernetesBackendApplication - Starting KubernetesBackendApplication on Waret with PID 58351 (/Users/Waret87/WorkSpace/telepresence/spring-cloud-kubernetes/demo-backend/target/classes started by Waret87 in /Users/Waret87/WorkSpace/telepresence/spring-cloud-kubernetes/demo-backend) 11:17:44.331 [restartedMain] INFO c.b.s.c.k.b.KubernetesBackendApplication - No active profile set, falling back to default profiles: default ... 11:17:45.931 [restartedMain] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' 11:17:45.934 [restartedMain] INFO c.b.s.c.k.b.KubernetesBackendApplication - Started KubernetesBackendApplication in 1.873 seconds (JVM running for 2.282) 11:20:35.483 [Thread-6] INFO o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor' . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
11:20:36.838 [restartedMain] INFO c.b.s.c.k.b.KubernetesBackendApplication - Starting KubernetesBackendApplication on Waret with PID 58351 (/Users/Waret87/WorkSpace/telepresence/spring-cloud-kubernetes/demo-backend/target/classes started by Waret87 in /Users/Waret87/WorkSpace/telepresence/spring-cloud-kubernetes/demo-backend)
11:20:36.838 [restartedMain] INFO c.b.s.c.k.b.KubernetesBackendApplication - No active profile set, falling back to default profiles: default
...
11:20:37.272 [restartedMain] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
11:20:37.272 [restartedMain] INFO c.b.s.c.k.b.KubernetesBackendApplication - Started KubernetesBackendApplication in 0.467 seconds (JVM running for 173.62)
複製代碼
再次訪問服務,能夠看到新的代碼已經生效。
# curl http://10.20.1.71:30001
Message from backend is: Hello World from demo-backend-c9df931b5c83411aad5a329ec9ecbcbb-5b4fdd7b-wzz9r
複製代碼
經過上面的實踐咱們能夠看到,Telepresence項目很好的解決了開發測試和部署上線之間的銜接問題,是對Kubernetes生態環境很好的補充。該項目已捐獻給CNCF基金會,社區的文檔也是比較完善的,更詳細的原理和用法可參考文檔。
本文由博雲研究院原創發表,轉載請註明出處。