縮放 Scala:如何使用 Kubernetes 進行 Dockerize
已發表: 2022-03-11Kubernetes 是新來的,承諾幫助將應用程序部署到雲中並更快地擴展它們。 今天,在為微服務架構開發時,選擇 Scala 來創建 API 服務器是相當標準的。
如果您的計劃中有一個Scala應用程序,並且您想將其擴展到雲中,那麼您來對地方了。 在本文中,我將逐步展示如何採用通用 Scala 應用程序並使用 Docker 實現 Kubernetes 以啟動應用程序的多個實例。 最終結果將是單個應用程序部署為多個實例,並由 Kubernetes 進行負載平衡。
所有這一切都將通過在您的 Scala 應用程序中簡單地導入 Kubernetes 源工具包來實現。 請注意,該套件隱藏了許多與安裝和配置相關的複雜細節,但如果您想分析它的作用,它足夠小,易於閱讀和理解。 為簡單起見,我們將在您的本地計算機上部署所有內容。 但是,相同的配置適用於 Kubernetes 的真實雲部署。
什麼是 Kubernetes?
在深入了解實現的細節之前,讓我們討論一下 Kubernetes 是什麼以及它為何如此重要。
您可能已經聽說過 Docker。 從某種意義上說,它是一個輕量級的虛擬機。
由於這些原因,它已經是在雲中部署應用程序的更廣泛使用的工具之一。 Docker 映像的構建和復制非常簡單快捷,比 VMWare、VirtualBox 或 XEN 等傳統虛擬機容易得多。
Kubernetes 補充了 Docker,為管理 dockerized 應用程序提供了一個完整的環境。 通過使用 Kubernetes,您可以輕鬆地部署、配置、編排、管理和監控數百甚至數千個 Docker 應用程序。
Kubernetes 是由 Google 開發的開源工具,已被許多其他供應商採用。 Kubernetes 可在 Google 雲平台上本地使用,但其他供應商也將其用於 OpenShift 雲服務。 它可以在 Amazon AWS、Microsoft Azure、RedHat OpenShift 甚至更多雲技術上找到。 可以說,它非常適合成為部署雲應用程序的標準。
先決條件
現在我們已經介紹了基礎知識,讓我們檢查您是否安裝了所有必備軟件。 首先,你需要 Docker。 如果您使用的是 Windows 或 Mac,則需要 Docker Toolbox。 如果您使用的是 Linux,則需要安裝您的發行版提供的特定軟件包,或者只需按照官方說明進行操作。
我們將使用 Scala 編寫代碼,這是一種 JVM 語言。 當然,您需要在全局路徑中安裝並提供 Java 開發工具包和 scala SBT 工具。 如果您已經是 Scala 程序員,那麼您很可能已經安裝了這些工具。
如果你使用的是 Windows 或 Mac,Docker 默認會創建一個名為default
的虛擬機,只有 1GB 內存,這對於運行 Kubernetes 來說可能太小了。 根據我的經驗,我遇到了默認設置的問題。 我建議您打開 VirtualBox GUI,選擇您的虛擬機default
,並將內存更改為至少 2048MB。
集群化應用
本教程中的說明適用於任何 Scala 應用程序或項目。 為了讓本文有一些“內容”,我選擇了一個經常用於演示 Scala 中的簡單 REST 微服務的示例,稱為 Akka HTTP。 我建議您先嘗試將源工具包應用於建議的示例,然後再嘗試在您的應用程序中使用它。 我已經針對演示應用程序測試了該套件,但我不能保證不會與您的代碼發生衝突。
所以首先,我們首先克隆演示應用程序:
git clone https://github.com/theiterators/akka-http-microservice
接下來,測試一切是否正常:
cd akka-http-microservice sbt run
然後,訪問http://localhost:9000/ip/8.8.8.8
,您應該會看到如下圖所示的內容:
添加源工具包
現在,我們可以使用一些 Git 魔法來添加源工具包:
git remote add ScalaGoodies https://github.com/sciabarra/ScalaGoodies git fetch --all git merge ScalaGoodies/kubernetes
有了這個,你就有了包含源工具包的演示,你可以嘗試了。 或者您甚至可以將代碼從那裡複製並粘貼到您的應用程序中。
合併或複制項目中的文件後,您就可以開始了。
啟動 Kubernetes
下載工具包後,我們需要通過運行以下命令下載必要的kubectl
二進製文件:
bin/install.sh
這個安裝程序足夠聰明(希望如此),可以根據您的系統為 OSX、Linux 或 Windows 下載正確的kubectl
二進製文件。 請注意,安裝程序在我擁有的系統上工作。 請報告任何問題,以便我修復套件。
安裝kubectl
二進製文件後,您可以在本地 Docker 中啟動整個 Kubernetes。 趕緊跑:
bin/start-local-kube.sh
第一次運行時,此命令將下載整個 Kubernetes 堆棧的圖像,以及存儲圖像所需的本地註冊表。 這可能需要一些時間,所以請耐心等待。 另請注意,它需要直接訪問互聯網。 如果您使用代理,這將是一個問題,因為該套件不支持代理。 要解決這個問題,您必須配置 Docker、curl 等工具才能使用代理。 這很複雜,我建議獲得臨時的無限制訪問。
假設您能夠成功下載所有內容,要檢查 Kubernetes 是否運行良好,您可以鍵入以下命令:
bin/kubectl get nodes
預期的答案是:
NAME STATUS AGE 127.0.0.1 Ready 2m
請注意,當然,年齡可能會有所不同。 此外,由於啟動 Kubernetes 可能需要一些時間,您可能需要多次調用該命令才能看到答案。 如果這裡沒有出現錯誤,那麼恭喜,您已經在本地機器上啟動並運行了 Kubernetes。
Docker 化你的 Scala 應用程序
現在您已經啟動並運行了 Kubernetes,您可以在其中部署您的應用程序。 在過去,在 Docker 之前,您必須部署整個服務器來運行您的應用程序。 使用 Kubernetes,部署應用程序所需要做的就是:
- 創建 Docker 映像。
- 將其推送到可以啟動它的註冊表中。
- 使用 Kubernetes 啟動實例,這將從註冊表中獲取圖像。
幸運的是,它看起來沒有那麼複雜,特別是如果您像許多人一樣使用 SBT 構建工具。
在工具包中,我包含了兩個文件,其中包含創建能夠運行 Scala 應用程序的映像的所有必要定義,或者至少是運行 Akka HTTP 演示所需的定義。 我不能保證它可以與任何其他 Scala 應用程序一起使用,但它是一個很好的起點,並且應該適用於許多不同的配置。 用於構建 Docker 映像的文件是:
docker.sbt project/docker.sbt
讓我們看看它們裡面有什麼。 文件project/docker.sbt
包含導入sbt-docker
插件的命令:
addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.4.0")
該插件為您管理使用 SBT 構建 Docker 映像。 Docker 定義位於docker.sbt
文件中,如下所示:
imageNames in docker := Seq(ImageName("localhost:5000/akkahttp:latest")) dockerfile in docker := { val jarFile: File = sbt.Keys.`package`.in(Compile, packageBin).value val classpath = (managedClasspath in Compile).value val mainclass = mainClass.in(Compile, packageBin).value.getOrElse(sys.error("Expected exactly one main class")) val jarTarget = s"/app/${jarFile.getName}" val classpathString = classpath.files.map("/app/" + _.getName) .mkString(":") + ":" + jarTarget new Dockerfile { from("anapsix/alpine-java:8") add(classpath.files, "/app/") add(jarFile, jarTarget) entryPoint("java", "-cp", classpathString, mainclass) } }
要完全理解這個文件的含義,需要對Docker有足夠的了解才能理解這個定義文件。 但是,我們不會深入了解 Docker 定義文件的詳細信息,因為您無需深入了解它即可構建映像。

SBT 將負責為您收集所有文件。
請注意,類路徑是由以下命令自動生成的:
val classpath = (managedClasspath in Compile).value
通常,收集所有 JAR 文件以運行應用程序是相當複雜的。 使用 SBT,Docker 文件將使用add(classpath.files, "/app/")
生成。 這樣,SBT 會為您收集所有 JAR 文件並構造一個 Dockerfile 來運行您的應用程序。
其他命令收集缺失的部分以創建 Docker 映像。 該映像將使用現有映像 APT 構建以運行 Java 程序( anapsix/alpine-java:8
,可在互聯網上的 Docker Hub 中獲得)。 其他說明正在添加其他文件以運行您的應用程序。 最後,通過指定入口點,我們可以運行它。 另請注意,名稱故意以localhost:5000
開頭,因為localhost:5000
是我在start-kube-local.sh
腳本中安裝註冊表的位置。
使用 SBT 構建 Docker 映像
要構建 Docker 映像,您可以忽略 Dockerfile 的所有詳細信息。 您只需要輸入:
sbt dockerBuildAndPush
然後sbt-docker
插件將為您構建一個 Docker 映像,從互聯網下載所有必要的部分,然後它將推送到之前啟動的 Docker 註冊表,以及localhost
中的 Kubernetes 應用程序。 因此,您只需要再等一會兒,讓您的圖像熟透並準備就緒。
請注意,如果您遇到問題,最好的辦法是通過運行以下命令將所有內容重置為已知狀態:
bin/stop-kube-local.sh bin/start-kube-local.sh
這些命令應該停止所有容器並正確重新啟動它們,以使您的註冊表準備好接收由sbt
構建和推送的映像。
在 Kubernetes 中啟動服務
現在應用程序已打包在容器中並推送到註冊表中,我們可以使用它了。 Kubernetes 使用命令行和配置文件來管理集群。 由於命令行可能會變得很長,並且還可以復制這些步驟,所以我在這裡使用配置文件。 源工具包中的所有示例都在文件夾kube
中。
我們的下一步是啟動圖像的單個實例。 運行中的鏡像在 Kubernetes 語言中稱為pod 。 因此,讓我們通過調用以下命令來創建一個 pod:
bin/kubectl create -f kube/akkahttp-pod.yml
您現在可以使用以下命令檢查情況:
bin/kubectl get pods
你應該看到:
NAME READY STATUS RESTARTS AGE akkahttp 1/1 Running 0 33s k8s-etcd-127.0.0.1 1/1 Running 0 7d k8s-master-127.0.0.1 4/4 Running 0 7d k8s-proxy-127.0.0.1 1/1 Running 0 7d
狀態實際上可以不同,例如“ContainerCreating”,它可能需要幾秒鐘才能變為“Running”。 此外,如果您之前忘記創建圖像,您可能會得到另一個狀態,例如“錯誤”。
您還可以使用以下命令檢查您的 pod 是否正在運行:
bin/kubectl logs akkahttp
您應該會看到以如下內容結尾的輸出:
[DEBUG] [05/30/2016 12:19:53.133] [default-akka.actor.default-dispatcher-5] [akka://default/system/IO-TCP/selectors/$a/0] Successfully bound to /0:0:0:0:0:0:0:0:9000
現在您已經在容器內啟動並運行了服務。 但是,該服務尚無法訪問。 這種行為是 Kubernetes 設計的一部分。 您的 pod 正在運行,但您必須明確地公開它。 否則,該服務將是內部的。
創建服務
創建服務並檢查結果是一個執行問題:
bin/kubectl create -f kube/akkahttp-service.yaml bin/kubectl get svc
您應該看到如下內容:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE akkahttp-service 10.0.0.54 9000/TCP 44s kubernetes 10.0.0.1 <none> 443/TCP 3m
請注意,端口可以不同。 Kubernetes 為該服務分配了一個端口並啟動它。 如果您使用的是Linux,您可以直接打開瀏覽器並輸入http://10.0.0.54:9000/ip/8.8.8.8
來查看結果。 如果您使用 Windows 或 Mac 和 Docker Toolbox,IP 是運行 Docker 的虛擬機的本地 IP,不幸的是它仍然無法訪問。
我想在這裡強調一下,這不是 Kubernetes 的問題,而是 Docker Toolbox 的限制,而這又取決於 VirtualBox 等虛擬機所施加的限制,它們就像另一台計算機中的計算機一樣。 為了克服這個限制,我們需要創建一個隧道。 為了讓事情變得更簡單,我包含了另一個腳本,它在任意端口上打開一個隧道以訪問我們部署的任何服務。 您可以鍵入以下命令:
bin/forward-kube-local.sh akkahttp-service 9000
請注意,隧道不會在後台運行,您必須在需要時保持終端窗口打開,並在不再需要隧道時關閉。 在隧道運行的同時,您可以打開: http://localhost:9000/ip/8.8.8.8
最終看到在 Kubernetes 中運行的應用程序。
最後的接觸:規模
到目前為止,我們已經“簡單地”將我們的應用程序放到了 Kubernetes 中。 雖然這是一項令人興奮的成就,但它並沒有為我們的部署增加太多價值。 我們省去了在服務器上上傳和安裝以及為其配置代理服務器的工作。
Kubernetes 的亮點在於擴展。 您可以通過僅更改配置文件中的副本數來部署我們應用程序的兩個、十個或一百個實例。 所以讓我們去做吧。
我們將停止單個 pod 並開始部署。 所以讓我們執行以下命令:
bin/kubectl delete -f kube/akkahttp-pod.yml bin/kubectl create -f kube/akkahttp-deploy.yaml
接下來,檢查狀態。 同樣,您可以嘗試幾次,因為部署可能需要一些時間才能執行:
NAME READY STATUS RESTARTS AGE akkahttp-deployment-4229989632-mjp6u 1/1 Running 0 16s akkahttp-deployment-4229989632-s822x 1/1 Running 0 16s k8s-etcd-127.0.0.1 1/1 Running 0 6d k8s-master-127.0.0.1 4/4 Running 0 6d k8s-proxy-127.0.0.1 1/1 Running 0 6d
現在我們有兩個 pod,而不是一個。 這是因為在我提供的配置文件中,有一個值replica: 2
,系統生成了兩個不同的名稱。 我不會詳細介紹配置文件,因為本文的範圍只是介紹 Scala 程序員快速入門 Kubernetes。
無論如何,現在有兩個 pod 處於活動狀態。 有趣的是服務和以前一樣。 我們將服務配置為在所有標記為akkahttp
的 pod 之間進行負載平衡。 這意味著我們不必重新部署服務,但我們可以用複制的實例替換單個實例。
我們可以通過再次啟動代理來驗證這一點(如果您在 Windows 上並且您已關閉它):
bin/forward-kube-local.sh akkahttp-service 9000
然後,我們可以嘗試打開兩個終端窗口並查看每個 pod 的日誌。 例如,在第一種類型中:
bin/kubectl logs -f akkahttp-deployment-4229989632-mjp6u
在第二種類型中:
bin/kubectl logs -f akkahttp-deployment-4229989632-s822x
當然,使用系統中的值相應地編輯命令行。
現在,嘗試使用兩種不同的瀏覽器訪問該服務。 您應該會看到請求在多個可用服務器之間進行拆分,如下圖所示:
結論
今天我們幾乎沒有觸及表面。 Kubernetes 提供了更多的可能性,包括自動擴展和重啟、增量部署和卷。 此外,我們用作示例的應用程序非常簡單,無狀態,各種實例不需要相互了解。 在現實世界中,分佈式應用程序確實需要相互了解,並且需要根據其他服務器的可用性來更改配置。 事實上,Kubernetes 提供了一個分佈式密鑰庫( etcd
),以允許不同的應用程序在部署新實例時相互通信。 但是,此示例故意足夠小並進行了簡化,以幫助您開始工作,並專注於核心功能。 如果您遵循本教程,您應該能夠在您的機器上為您的 Scala 應用程序獲得一個工作環境,而不會被大量的細節所迷惑並迷失在復雜性中。
- 在雲中為雲開發:在 AWS 中使用 Docker 進行大數據開發
- K8s/Kubernetes:AWS 與 GCP 與 Azure
- Kubernetes 服務網格比較