缩放 Scala:如何使用 Kubernetes 进行 Dockerize

已发表: 2022-03-11

Kubernetes 是新来的,承诺帮助将应用程序部署到云中并更快地扩展它们。 今天,在为微服务架构开发时,选择 Scala 来创建 API 服务器是相当标准的。

微服务正在用多个相互通信并拥有自己的流程和资源的独立服务取代经典的单体后端服务器。

如果您的计划中有一个Scala应用程序,并且您想将其扩展到云中,那么您来对地方了。 在本文中,我将逐步展示如何采用通用 Scala 应用程序并使用 Docker 实现 Kubernetes 以启动应用程序的多个实例。 最终结果将是单个应用程序部署为多个实例,并由 Kubernetes 进行负载平衡。

所有这一切都将通过在您的 Scala 应用程序中简单地导入 Kubernetes 源工具包来实现。 请注意,该套件隐藏了许多与安装和配置相关的复杂细节,但如果您想分析它的作用,它足够小,易于阅读和理解。 为简单起见,我们将在您的本地计算机上部署所有内容。 但是,相同的配置适用于 Kubernetes 的真实云部署。

使用 Kubernetes 扩展您的 Scala 应用程序

聪明一点,睡个好觉,用 Kubernetes 扩展你的 Docker。
鸣叫

什么是 Kubernetes?

在深入了解实现的细节之前,让我们讨论一下 Kubernetes 是什么以及它为何如此重要。

您可能已经听说过 Docker。 从某种意义上说,它是一个轻量级的虚拟机。

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。

VirtualBox 内存设置

集群化应用

本教程中的说明适用于任何 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 ,您应该会看到如下图所示的内容:

Akka HTTP 微服务正在运行

添加源工具包

现在,我们可以使用一些 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 构建 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 提供了更多的可能性,包括自动扩展和重启、增量部署和卷。 此外,我们用作示例的应用程序非常简单,无状态,各种实例不需要相互了解。 在现实世界中,分布式应用程序确实需要相互了解,并且需要根据其他服务器的可用性来更改配置。 事实上,Kubernetes 提供了一个分布式密钥库( etcd ),以允许不同的应用程序在部署新实例时相互通信。 但是,此示例故意足够小并进行了简化,以帮助您开始工作,并专注于核心功能。 如果您遵循本教程,您应该能够在您的机器上为您的 Scala 应用程序获得一个工作环境,而不会被大量的细节所迷惑并迷失在复杂性中。

有关的:
  • 在云中为云开发:在 AWS 中使用 Docker 进行大数据开发
  • K8s/Kubernetes:AWS 与 GCP 与 Azure
  • Kubernetes 服务网格比较