本文概述
Kubernetes是新兴技术, 有望帮助将应用程序部署到云中并更快地扩展它们。如今, 在开发微服务架构时, 选择Scala创建API服务器已成为一种标准。
微服务正在用相互之间相互通信并具有自己的进程和资源的多个独立服务代替经典的单片后端服务器。
如果你的计划中有一个Scala应用程序, 并且你想将其扩展到云中, 那么你来对地方了。在本文中, 我将逐步展示如何使用通用Scala应用程序以及如何通过Docker实现Kubernetes, 以启动该应用程序的多个实例。最终结果将是将单个应用程序部署为多个实例, 并由Kubernetes进行负载均衡。
所有这些都可以通过简单地在Scala应用程序中导入Kubernetes源工具包来实现。请注意, 该工具包隐藏了许多与安装和配置有关的复杂细节, 但是如果你想分析它的作用, 那么它足够小以至于易于阅读和理解。为简单起见, 我们将所有内容部署在你的本地计算机上。但是, 相同的配置适用于Kubernetes的实际云部署。
保持精明并入睡, 使用Kubernetes扩展Docker。
鸣叫
什么是Kubernetes?
在详细讨论实施之前, 让我们讨论一下Kubernetes是什么以及为什么它很重要。
你可能已经听说过Docker。从某种意义上讲, 它是一个轻量级的虚拟机。
Docker具有将每个服务器部署在与独立虚拟机非常相似的隔离环境中的优势, 而无需管理完整的虚拟机。
由于这些原因, 它已经是在云中部署应用程序的更广泛使用的工具之一。与传统的虚拟机(如VMWare, VirtualBox或XEN)相比, Docker镜像非常易于构建和复制。
Kubernetes是Docker的补充, 为管理Docker化的应用程序提供了完整的环境。通过使用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, 选择默认的虚拟机, 然后将内存至少更改为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构建Docker映像的好处在于
SBT将负责为你收集所有文件。
请注意, 以下命令会自动生成类路径:
val classpath = (managedClasspath in Compile).value
通常, 收集所有JAR文件以运行应用程序非常复杂。使用SBT, 将使用add(classpath.files, ” / app /”)生成Docker文件。这样, SBT会为你收集所有JAR文件, 并构造一个Dockerfile来运行你的应用程序。
其他命令收集缺少的部分以创建Docker映像。该映像将使用现有的映像APT构建, 以运行Java程序(anapsix / alpine-java:8, 可从Docker Hub的Internet上获得)。其他说明正在添加其他文件以运行你的应用程序。最后, 通过指定入口点, 我们可以运行它。还要注意, 该名称故意以localhost:5000开头, 因为localhost:5000是我在start-kube-local.sh脚本中安装注册表的位置。
使用SBT构建Docker映像
要构建Docker映像, 你可以忽略Dockerfile的所有详细信息。你只需要输入:
sbt dockerBuildAndPush
然后, sbt-docker插件将为你构建一个Docker映像, 从互联网上下载所有必需的片段, 然后它将与本地主机中的Kubernetes应用程序一起推送到之前启动的Docker注册表中。因此, 你所需要做的就是再等一会儿, 以准备好图像并准备就绪。
请注意, 如果遇到问题, 最好的办法是通过运行以下命令将所有内容重置为已知状态:
bin/stop-kube-local.sh
bin/start-kube-local.sh
这些命令应停止所有容器并正确地重新启动它们, 以使注册表准备好接收sbt构建和推送的映像。
在Kubernetes中启动服务
现在, 该应用程序已打包在容器中并推送到注册表中, 我们可以使用它了。 Kubernetes使用命令行和配置文件来管理集群。由于命令行可能变得很长, 并且也能够复制这些步骤, 因此我在这里使用配置文件。试剂盒中的所有样品均在kube文件夹中。
我们的下一步是启动图像的单个实例。用Kubernetes语言将运行中的映像称为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的虚拟机而言是本地的, 不幸的是它仍然无法访问。
我想在这里强调, 这不是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
现在我们有两个吊舱, 而不是一个。这是因为在我提供的配置文件中, 存在值副本:2, 系统生成了两个不同的名称。我不会讨论配置文件的细节, 因为本文的范围只是Scala程序员入门Kubernetes的介绍。
无论如何, 现在有两个吊舱处于活动状态。有趣的是, 该服务与以前相同。我们将服务配置为在所有标记为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进行大数据开发