在Azure上使用Cosmos DB的Kubernetes微服务的教程

339 阅读26分钟

在本教程中,你将学习如何将一个基于JHipster的反应式微服务部署到Azure Kubernetes Service(AKS)。你将使用Azure的Cosmos DB作为其中一个服务的持久化存储。在安全方面,你将使用Okta作为OAuth 2.0和OpenID Connect(OIDC)提供者。你还将使用Kubernetes secrets和kubeseal ,对项目配置文件中的所有秘密进行安全加密。本教程的重点是将已经生成的项目部署到Azure AKS。它并没有详细介绍项目的生成过程。要想了解该项目是如何使用JHipster生成的,请看《使用Spring Boot和JHipster的反应型Java微服务》。

该项目有几个不同的部分:

  • JHipster注册中心:一个用于服务发现的Eureka服务器和一个用于集中配置管理的Spring Cloud Config服务器
  • 网关:使用Vue的公共Spring云网关应用
  • 商店:使用Azure的MongoDB的Cosmo DB API的Spring Boot微服务
  • 博客:使用Neo4J数据库的Spring Boot微服务

本教程中包含了很多不同的技术。我试图让它尽可能简单明了,但在开始之前,掌握一些Docker和Kubernetes的基本知识可能会有所帮助。

如果你已经熟悉了本教程中的所有技术,你可以跳到先决条件部分。如果不是,在我们继续之前,我将对它们进行一些解释。

JHipster微服务架构概述

JHipster 是一个开发平台,它简化了单体和微服务应用程序的生成、开发和部署。它支持一系列令人眼花缭乱的前端(Angular、React和Vue)和后端(Spring Boot、Micronaut、Quarkus、Node.js和.NET)技术。它被设计为使用Docker和Kubernetes进行部署,可以很容易地部署到所有主要的云平台,如AWS、Azure、Heroku、Cloud Foundry、Google Cloud Platform和OpenShift。

本教程中的项目使用Spring Boot与Java资源服务器和Vue前端。它是用JHipster生成器构建的,该生成器可以根据交互式shell或DSL文件快速搭建一个新的应用程序。你可以在他们的文档中阅读更多关于用JHipster生成微服务的信息。JHipster生成器的一个巧妙的功能是,你可以和应用程序一起生成数据实体。

与微服务一起生成的 JHipster注册表 包括两个重要的功能:一个Eureka服务器和一个Spring Cloud Config服务器。Eureka服务器允许微服务动态地找到对方,而不必使用硬编码的URI。这意味着微服务可以扩展,服务可以被替换而不产生问题。这有点像微服务的电话簿或DNS服务。Spring Cloud Config服务器允许项目配置集中化,并分布到所有不同的服务中。在本教程中,你将使用这一功能,在一个地方配置Okta OAuth的所有服务。

JHipster API网关 是你的微服务的公共窗口。所有的公共流量都要通过这个服务,其中也包括Vue前端。网关是JHipster生成器DSL所能创建的三种应用类型之一。其他两个是单体和微服务。单片机是一个具有单一服务的非微服务应用程序。

商店服务和博客服务都是微服务应用类型的例子。这意味着每个服务都是一个Spring Boot资源服务器,具有某种类型的SQL或NoSQL后端。

生成器创建了四个应用程序。它们被设计为以docker容器的形式构建和运行,这使得它们很容易被打包到 Kubernetes pods中。Kubernetes是一个容器编排器,专门用于管理微服务网络。它类似于Docker Compose,但专为微服务设计,具有很多伟大的功能,如服务发现、负载平衡、自动推出和重新启动、资源管理和存储安装。

前提条件

本教程有很多内容。安装以下所需软件,并注册一个Azure云账户。你需要一个免费的Okta账户,但你可以在本教程后面使用Okta CLI来注册它。

  • Docker:你需要同时安装Docker EngineDocker Compose(如果你安装了Docker桌面,这将自动安装这两个软件。在Linux上,如果你单独安装了Docker Engine,你还必须安装Docker Compose)分开。
  • Docker Hub:你需要一个Docker Hub来托管docker镜像,以便Azure可以拉动它们。
  • Java 11:本教程需要Java 11。如果你需要管理多个Java版本,SDKMAN!是一个不错的解决方案。请看他们的文档来安装它
  • Okta CLI:你将使用Okta来为微服务网络添加安全性。你可以从CLI上注册一个免费账户。
  • Azure云账户:他们提供了一个免费级别的账户,开始时有200美元的信用额度。
  • Azure CLI:你将使用Azure CLI来管理Kubernetes集群。
  • kubectl。用于管理Kubernetes集群的CLI。

如果你以前从未有过Azure账户,你可以创建一个新的账户,它将允许自由层访问,并有200美元的信用额度分配给它。这对完成本教程来说是绰绰有余的。但是,信用额度在30天后就会失效。如果你没有剩余的信用额度,或者你的信用额度已经过期,如果你在不工作的时候停止和启动AKS集群,这个教程应该只花费几美元。你可以使用Azure门户中的成本资源管理器来关注你的成本,如果你担心的话,可以设置警报。升级到现收现付也可以缓解围绕测试AKS集群的一些资源节流问题。

用于Azure和Cosmos DB的Spring Boot微服务

这个项目是基于Matt Raible的两个教程。使用Spring Boot和JHipster的反应式Java微服务使用Spring Boot和JHipster的Kubernetes到云。在这些教程中,他构建了一个反应式Java微服务架构,并展示了如何将其部署到谷歌云(GCP)。我对该项目进行了修改,以便与Azure和Cosmos DB一起工作。

你将首先使用Docker Compose运行该项目。一旦你有了这个工作,你将在Azure上作为Kubernetes集群运行该项目。我的修改相对较小,包括删除不必要的MongoDB实例(从docker-compose.yml 文件和Kubernetes描述符中),以及更新环境值,将store 服务指向Cosmos DB实例而不是MongoDB实例。

简而言之,我根据Matt Raible的帖子所做的修改,使其在Azure和Cosmos DB上运行,具体如下。你可以跳过这个列表(和下一节),直接去克隆Git仓库,如果你愿意的话,但由于这记录了如何更新JHipster生成的项目以使用Cosmos DB,我认为这值得包括在内。

docker-compose/docker-compose.yml 文件中:

  • 删除了MongoDB服务
  • 更新了store 服务属性SPRING_DATA_MONGODB_URI ,以通过.env 文件指向Cosmos DB实例。
  • 删除了Keycloak服务和配置auth使用Keycloak的环境变量(不是严格意义上的必要,但是清理了事情)。

k8s/store-k8s 目录中:

  • 删除了store-mongodb.yml 文件(这创建了我们项目不需要的MongoDB Kubernetes服务。)
  • instore-deployment.yml:
    • 删除了initContainers (init容器等待MongoDB实例,该实例已被删除)。
    • store-app 容器的SPRING_DATA_MONGODB_URI env 值更新为 Cosmos DB URI(这将使存储指向 Cosmos DB 实例。)
    • 使用 Kubernetes secrets 妥善保护 Cosmos DB 连接字符串和kubeseal

为Eureka设置商店应用程序的初始状态

在创建这个教程时,我遇到了一个问题,商店应用程序被卡在了OUT_OF_SERVICE 。当我检查日志时,我发现该服务以UP 开始,很快就变成了DOWN ,然后是OUT_OF_SERVICE 。后来,它又回到了UP ,但Eureka服务器从未登记这一变化。

Spring Cloud NetflixNetflix Eureka上有一个记录这个问题的公开问题。

从GitHub上的问题中得到的一个临时解决方案是覆盖健康报告的实现,以便在程序仍在启动时返回DOWN 而不是OUT_OF_SERVICE 。这可以阻止它报告OUT_OF_SERVICE 。你可以在商店应用程序的 EurekaFix.java文件中看到。

克隆GitHub上的微服务项目

从GitHub上克隆修改后的JHipster反应式微服务项目,并检查start 标签。

git clone https://github.com/oktadev/okta-azure-kubernetes-cosmosdb-example.git \
  azure-k8s-cosmosdb
cd azure-k8s-cosmosdb
git fetch --all --tags
git checkout tags/start -b working

为MongoDB创建带有API的Azure Cosmos DB

你需要创建一个Azure Cosmos DB实例。你可以使用Azure门户或CLI来创建一个新的Cosmos DB实例。请确保你创建的是Azure Cosmos DB API for MongoDB(Cosmos DB支持各种数据库类型)。如果你使用门户网站,那就不言自明了,但别忘了启用免费层和启用公共网络。

以下是使用CLI的说明。

使用Bash shell登录到Azure CLI。这将把你重定向到一个浏览器,以登录到Azure门户。

az login

这应该会显示你的账户的订阅情况。

[
  {
    "cloudName": "AzureCloud",
    "homeTenantId": "21c44b6d-a007-4d48-80cb-c45966ca1af9",
    "id": "90eb9f51-b4be-4a9f-a69f-11b7668a874d",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Azure subscription 1",
    "state": "Enabled",
    "tenantId": "21c44b6d-a007-4d48-80cb-c45966ca1af9",
    "user": {
      "name": "andrewcarterhughes@outlook.com",
      "type": "user"
    }
  }
]

在shell中设置订阅。你的订阅可能是Azure subscription 1 ,因为那是默认的。确保你使用的是你注册免费账户时创建的订阅(如果你已经有一个账户,则使用你想要的任何订阅)。

az account set --subscription <you-subscription-name>

打开一个Bash shell。用下面的命令创建一个资源组。

az group create --name australia-east --location australiaeast

在资源组中创建Cosmos DB账户。在下面的命令中替换你的Azure订阅名称(可能是Azure subscription 1 ,这是我的默认名称)。

az cosmosdb create --name jhipster-cosmosdb --resource-group australia-east \
  --kind MongoDB --subscription <you-subscription-name> --enable-free-tier true \
  --enable-public-network true

一旦该命令返回(可能需要几分钟),它应该列出大量的JSON,显示创建的Cosmos DB账户的属性。

如果你得到一个错误,说:

(BadRequest) DNS record for cosmosdb under zone Document is already taken.

那么你需要把--name 参数改成其他的东西。因为这被用来生成数据库的公共URI,它需要在整个Azure中是唯一的。试着加入你的名字或一些随机数字。

我使用澳大利亚东部的位置,因为在我写这个教程时,那里有免费的AKS节点。你可以使用任何你想要的资源组,只要它允许你在本教程的后面创建AKS集群。即使你不能使用免费层或免费点数,如果你在编写教程的间隙停止和启动AKS集群,成本应该非常小(我的成本不到几美元)。如果Cosmos DB数据库在不同的资源组和地区,应用程序应该仍然工作,因为数据库URI被配置为可公开访问。

使用以下命令列出Cosmos DB API for MongoDB端点的连接字符串。如果你改变了上面的数据库名称,你需要在下面的命令中更新它。

az cosmosdb keys list --type connection-strings --name jhipster-cosmosdb \
  --resource-group australia-east

这将列出四个连接字符串。你需要保存(复制并粘贴到某个地方)第一个,即主连接字符串。(为了简洁起见,下面使用了省略号)。

{
  "connectionStrings": [
    {
      "connectionString": "mongodb://jhipster-cosmosdb:XBq5KZ81V8hM63KjCOezi1arq...",
      "description": "Primary MongoDB Connection String"
    },
    ...
  ]
}

编辑docker-compose 子目录中的.env 文件。在其中添加以下变量,用你的连接字符串代替占位符。请确保连接字符串用引号括起来。这个值被docker-compose.yml 文件引用并传递给store 服务,将其指向Cosmos DB MongoDB数据库。

ENCRYPT_KEY 将被用作加密存储在Spring Cloud Config中的敏感值的密钥,并由JHipster注册表使用。你可以把你想要的任何值放在那里。一个UUID很好用,但任何字符串值都可以使用。越长越好。

docker-compose/.env

SPRING_DATA_MONGO_URI=<your-connection-string>
ENCRYPT_KEY=<your-encryption-key>

用Okta配置身份

在你开始之前,你需要一个免费的Okta开发者账户。安装Okta CLI,运行okta register ,注册一个新账户。如果你已经有一个账户,运行okta login 。然后,运行okta apps create jhipster 。选择默认的应用程序名称,或根据您的需要进行更改。 接受为您提供的默认重定向URI值。

Okta CLI是做什么的?

Okta CLI简化了对JHipster应用程序的配置,并为您做了几件事:

  1. 创建一个具有正确重定向URI的OIDC应用程序。
    • 登录:http://localhost:8080/login/oauth2/code/oidchttp://localhost:8761/login/oauth2/code/oidc
    • 注销:http://localhost:8080http://localhost:8761
  2. 创建JHipster期望的ROLE_ADMINROLE_USER
  3. 将你的当前用户添加到ROLE_ADMINROLE_USER 组中。
  4. 在你的默认授权服务器中创建一个groups ,并将用户的组添加到其中。

注意http://localhost:8761* 重定向URI是为JHipster注册处准备的,在用JHipster创建微服务时经常使用。Okta CLI默认会添加这些。

完成后,你会看到如下的输出:

Okta application configuration has been written to: /path/to/app/.okta.env

运行cat .okta.env (或Windows上的type .okta.env ),查看你的应用程序的发行者和凭证。它将看起来像这样(除了占位符的值将被填充)。

export SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI="/oauth2/default"
export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID="{clientId}"
export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET="{clientSecret}"

注意:您也可以使用Okta管理控制台来创建您的应用程序。请参阅在Okta上创建JHipster应用程序以了解更多信息。

注意这个名字,因为你需要在Okta管理控制台找到这个应用,并在稍后更新重定向URI。okta apps 命令创建一个名为.okta.env 的配置文件。它看起来就像下面这样。它很有帮助地列出了你在下一步需要的值。

export SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI="https://dev-13337.okta.com/oauth2/default"
export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID="2989u928u383..."
export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET="09328uu098u4..."

Docker Compose项目和Kubernetes项目都使用Spring Cloud Config来集中配置。JHipster注册表服务使这些配置值对集群中的所有其他服务可用。

.okta.env 打开docker-compose/central-server-config/application.yml ,在结尾处添加以下内容,填入取自issuer-uriclient-idclient-secret 的文件。这就是Docker Compose项目的Spring Cloud配置文件。

docker-compose/central-server-config/application.yml

spring:
  security:
    oauth2:
      client:
        provider:
          oidc:
            issuer-uri: https://<your-okta-domain>/oauth2/default
        registration:
          oidc:
            client-id: <client-id>
            client-secret: <client-secret>

构建Docker镜像并使用Docker Compose运行该应用

你已经准备好使用Docker和Docker Compose在本地运行该应用了。你需要为每个项目构建docker镜像。gateway,store, 和blog (你不必构建registry ,因为它使用了一个镜像)。

在这三个不同的应用目录中,运行以下Gradle命令。

./gradlew -Pprod bootJar jibDockerBuild

默认的Docker资源设置可能不足以运行这个项目。你可能需要对它们进行修改。这些设置对我有用:

  • CPU。8
  • 内存:25 GB
  • 交换机:2 GB
  • 磁盘镜像大小:120 GB

导航到docker-compose 目录并运行该应用程序。你可以使用-d 参数将其作为一个守护程序运行,但目前我喜欢看日志。反正你只是在Docker Compose中运行这个,作为Azure部署的热身。

docker-compose up

给它一两分钟时间来完成所有服务的运行。

打开网关服务:http://localhost:8080

进入账户登录。你应该被引导到Okta登录表。

Okta Login

你应该能够用你的Okta凭证进行认证。

Authenticated

确保应用程序的所有部分都在工作。首先,测试商店(使用Cosmos DB Mongo数据库),进入实体产品。确保你可以添加一个新产品,并在产品列表中看到它。接下来,创建一个博客 (EntitiesandBlog)。

如果成功了,你可以看一下管理菜单。那里有很多有用的信息。

你也可以查看JHipster注册表,网址是http://localhost:8761

Authenticated

加密客户端的秘密

在存储库中以纯文本形式留下秘密是一种安全风险。这个应用程序中有两个值是敏感的:包括用户名和密码的Cosmos DB连接字符串和Okta OIDC应用程序的客户秘密。你能够通过使用.env 文件来避免暴露数据库的凭证。然而,Okta客户端秘密在Spring Cloud配置文件(docker-compose/central-server-config/application.yml )中以纯文本形式曝光。这可以使用JHipster注册表进行加密。

打开注册表 (http://localhost:8761) 并点击配置加密

Authenticated

将你的客户秘密粘贴在文本框中。点击 "加密"。

顺便说一下,这就是为什么你需要.env 文件中的ENCRYPT_KEY 属性。 那是JHipster注册表用来加密这些值的密钥(所以要保密!)。

你现在可以复制加密后的值并将其粘贴到application.yml 文件中。确保你包括{cipher} 部分。它看起来应该与下面类似。不要忘记引号!

docker-compose/central-server-config/application.yml

...
spring:
  security:
    oauth2:
      client:
        provider:
          oidc:
            issuer-uri: https://dev-123456.okta.com/oauth2/default
        registration:
          oidc:
            client-id: 0oa6ycm987987uy98
            client-secret: "{cipher}88acb434dd088acb434dd088acb434dd0..."

如果你还没有使用control-c ,请停止该应用程序。重新启动它。

docker-compose up

确保你仍然可以在http://localhost:8080 上登录网关。

你可能想知道(就像我最初那样),为什么我不能把客户秘密放在.env 文件中?这是不可行的,因为.env 文件是在容器组成后由Spring Cloud Config和JHipster注册表处理的,而不是在容器创建期间由Docker Compose处理的,而Docker Compose是在.env 文件中处理的。

你已经完成了Docker Compose的实现。为了清理,你可以运行以下命令。这将停止并删除由docker-compose up 创建的容器、网络、卷和镜像。

docker-compose down --remove-orphans

创建Azure Kubernetes集群

该应用程序在本地运行。现在是时候把它部署到Azure Kubernetes集群(AKS)了。第一步是创建一个AKS集群。

使用CLI来创建一个集群是非常容易的。我将向你展示下面的命令。然而,有一个问题。由于资源配额的原因,免费层不能在许多地区创建一个集群。至少,我在做这个教程的时候是这样的。也没有一个简单的方法来快速查看哪些地区将允许你创建一个免费层集群。这就是为什么我使用澳大利亚东部作为区域--它允许我创建一个自由集群。

如果下面的命令不起作用,我建议去Azure门户,在那里创建一个Kubernetes集群。选择创建一个服务Kubernetes服务。你必须选择不同的区域,看看有哪些尺寸(在节点尺寸改变尺寸下),直到你找到一个区域,允许你在免费层创建一些东西。但希望这个命令能起作用,你就不必担心这个问题了。

我在本教程中使用的尺寸是Standard B4ms ,有两个节点。我发现,我需要两个节点来使集群正常启动。

运行下面的命令来创建AKS集群。

az aks create --resource-group australia-east --name jhipster-demo \
  --node-count 2 --enable-addons monitoring --generate-ssh-keys --node-vm-size standard_b4ms

这可能需要几分钟的时间。

顺便提一下,你可以在任何时候停止该集群。这将暂停对集群的计费。

az aks stop --resource-group australia-east --name jhipster-demo 

然后你可以再次启动它。

az aks start --resource-group australia-east --name jhipster-demo 

你也可以从Azure门户网站上停止和启动集群。

下一步是获取集群的凭证,并将其合并到.kube/config ,以便kubectl ,这样就可以使用它们。使用下面的命令。

az aks get-credentials --resource-group australia-east --name jhipster-demo

你应该看到像下面这样的输出结果:

Merged "jhipster-demo" as current context in /home/andrewcarterhughes/.kube/config

你应该能够使用kubectl ,以获得Azure上的节点。

kubectl get nodes
NAME                                STATUS   ROLES   AGE    VERSION
aks-nodepool1-21657131-vmss000000   Ready    agent   105s   v1.22.6
aks-nodepool1-21657131-vmss000001   Ready    agent   108s   v1.22.6

你还可以使用JSON格式列出集群的很多信息。

az aks list --resource-group australia-east

为Okta和Cosmos DB配置Kubernetes

k8s 目录中的Kubernetes文件是用JHipster Kubernetes子生成器创建的(信息见文档)。要看原始项目是如何生成的,请看Matt Raible的JHipster和Kubernetes教程。如上所述,这些文件被修改为与Azure Cosmos DB一起使用,而不是在Kubernetes pod中使用MongoDB(这也是子生成器的假设)。

通过更新k8s/registry-k8s/application-configmap.yml ,在Kubernetes pod中配置Spring OAuth。你可以使用你在Docker Compose部分使用的相同的值,在docker-compose/central-server-config/application.yml

确保你使用加密的客户端秘密,并将其放在引号中,前缀为{cipher} 。你要从Docker Compose配置中复制加密密钥和加密的客户秘密,以避免用新密钥重新加密客户秘密。

data:
  application.yml: |-
    ...
    spring:
      security:
        oauth2:
          client:
            provider:
              oidc:
                issuer-uri: https://<your-okta-domain>/oauth2/default
            registration:
              oidc:
                client-id: <client-id>
                client-secret: "{cipher}<encrypted-client-secret>"

为了配置JHipster注册表使用OIDC进行认证,你必须修改k8s/registry-k8s/jhipster-registry.yml ,以启用oauth2 配置文件。在项目Git仓库中的示例应用程序中已经为你做了这个工作。

- name: SPRING_PROFILES_ACTIVE
  value: prod,k8s,oauth2

同样在k8s/registry-k8s/jhipster-registry.yml ,更新ENCRYPT_KEY 的值,以使用你在Docker Compose部分使用的相同加密密钥,在.env 文件中:

- name: ENCRYPT_KEY
  value: <your-encryption-key>

要配置store 服务以使用Cosmo数据库,你需要在k8s/store-k8s/store-deployment.yml 中放入你的连接字符串:

- name: SPRING_DATA_MONGODB_URI
  value: "<your-connection-string>"

加密密钥和数据库连接字符串都是敏感值,需要进行加密。你将在本教程的稍后部分看到如何做到这一点。

构建Docker镜像并推送至Docker Hub

之前你构建了docker镜像,但你把它们留在了本地仓库中。现在你需要把它们上传到Docker Hub,以便Azure AKS能够找到它们。如果你还没有注册一个Docker Hub账户,请现在就注册。

在这三个目录(blog,store, 和gateway )中,分别运行以下命令。将你的Docker Hub用户名保存在Bash变量中,如下图所示,你可以复制和粘贴这些命令并在每个服务目录中运行它们。

DOCKER_HUB_USERNAME=<docker-hub-username>
# in blog
./gradlew bootJar -Pprod jib -Djib.to.image=$DOCKER_HUB_USERNAME/blog
# in store
./gradlew bootJar -Pprod jib -Djib.to.image=$DOCKER_HUB_USERNAME/store
# in gateway
./gradlew bootJar -Pprod jib -Djib.to.image=$DOCKER_HUB_USERNAME/gateway

为了简单解释这里发生的事情,看一下博客服务的Kubernetes描述符文件。它定义了一个名为blog-app 的容器,使用docker镜像andrewcarterhughes/blog ,这是我的Docker Hub用户名和博客镜像。

k8s/blog-k8s/blog-deployment.yml

containers:
  - name: blog-app
    image: andrewcarterhughes/blog

因此,在k8s 目录中,每个服务(商店、博客、网关和注册中心)都定义了一个容器和一个要在该容器中运行的docker镜像,以及一大堆配置(这实际上是JHipster为你引导的很多东西)。注册表没有项目文件夹,因为它使用的是可以直接从JHipster Docker资源库中提取的库存镜像。

要使用你刚刚创建的Kubernetes镜像,在k8s 目录中进行查找和替换。用你的Docker Hub用户名(<docker-hub-username>)替换所有andrewcarterhughes 的实例。

Kubernetes的一个很好的功能是能够定义init容器。这些是在主容器之前运行的容器,可以用来创建或等待必要的资源,如数据库。我在调试这个应用程序的时候注意到,很多错误都发生在初始容器中。知道这一点很有帮助,因为如果你试图检查主容器的日志,那里不会有任何东西,因为容器甚至还没有启动。你必须检查失败的初始容器的日志。我在下面提到的Kubernetes管理工具在这方面确实很有用。

将你的微服务部署到Azure AKS上

你可以纯粹用kubectl 来管理一个Kubernetes服务。不过,有一些相当有用的工具可以用来监控和记录。k9sKubernetes Lens都很不错。我建议安装其中的一个或两个,用它们来检查和监控你的Kubernetes服务。当事情出错时,它们尤其有帮助(不是说事情曾经出错,我不会知道什么,我只是从朋友那里听说的,我发誓)。Kubernetes Lens是一个完整的桌面应用程序,它将自己描述为一个Kubernetes IDE。相比之下,k9s是一个更轻量级的、基于文本的工具。

打开Bash shell,导航到项目的k8s 子目录。

将你的微服务架构部署到Azure,用:

./kubectl-apply.sh -f

如果你打开这个文件,你会看到它创建了命名空间并应用了项目文件。如果你手动操作,重要的是首先创建命名空间,并且在其他服务之前运行注册表。

...
suffix=k8s
kubectl apply -f namespace.yml
kubectl apply -f registry-${suffix}/
kubectl apply -f blog-${suffix}/
kubectl apply -f gateway-${suffix}/
kubectl apply -f store-${suffix}/
...

你可以用下面的命令来检查你的pod。如果你是免费层,这可能需要几分钟时间。使用 "即用即付 "计划,对我来说,一切几乎都是立即启动和运行。

kubectl get pods -n demo
NAME                                  READY   STATUS    RESTARTS   AGE
blog-6896f6dd58-mbjkn                 1/1     Running   0          3m51s
blog-neo4j-0                          1/1     Running   0          3m48s
gateway-7f6d57765f-2fhfb              1/1     Running   0          3m46s
gateway-postgresql-647476b4d5-jdp5c   1/1     Running   0          3m44s
jhipster-registry-0                   1/1     Running   0          3m52s
store-7889695569-k4wkv                1/1     Running   0          3m41s

下面是一个使用Kubernetes Lens的例子(容器仍在启动)。

K8s Lens screenshot

另一个有用的命令是describe 。我不会在这里复制输出,但如果你想要更详细的信息来进行调试,你也可以运行以下命令。

kubectl describe pods -n demo

要尾随日志,你可以使用pod的名字。

kubectl logs <pod-name> --tail=-1 -n demo

虽然,就像我说的,k9s和Lens才是真正的方法,可以进行更详细的检查。

下面是k9s的截图。你可以深入到不同的豆荚,以获得更详细的信息和检查日志。

Authenticated

你可以使用端口转发来查看JHipster注册表。

kubectl port-forward svc/jhipster-registry -n demo 8761

打开浏览器并导航到http://localhost:8761 。你将被重定向到Okta的登录界面,之后你将被带到注册表。

确保所有东西都是绿色的。如果你有一个错误,检查日志中导致错误的pod。你可以通过删除它并重新应用它来重启一个特定的部署。例如,要重新启动商店,你可以从k8s 目录中使用下面的命令。

kubectl delete -f store-k8s/
kubectl apply -f store-k8s/

一旦一切顺利,control-c ,停止转发注册表。暴露网关并打开它。

kubectl port-forward svc/gateway -n demo 8080

转到http://localhost:8080

用Okta进行认证。确保你可以添加博客、帖子、标签和产品。因为商店服务使用与你在本地使用Docker Compose时相同的Cosmos DB实例,所以你之前创建的任何测试产品仍将存在。

在为下一步做准备时,删除你刚刚部署到AKS的demo 名称空间中的所有东西。

kubectl delete all --all -n demo

第一个all 是指所有的资源类型。第二个--all 是指资源类型中的每一个对象(而不是指定一个对象名称或ID)。因此,通过指定命名空间,你将删除该命名空间中每个资源类型的每个对象。

这就是使用命名空间的好处之一。你可以像这样进行删除。如果你从默认的命名空间这样做,你将有可能删除你无意删除的东西或Kubernetes和Azure为基础设施管理添加的pod。

你也可以直接删除整个命名空间。如果你使用Bash脚本来应用部署,它将被重新创建。这绝对会删除命名空间中的所有东西,但速度会慢一点。如果你这样做,你需要确保你以后重新创建命名空间(我会提醒你)。

kubectl delete namespace demo

加密敏感的配置参数

有两个真正重要的配置值需要被加密:(1)Cosmos DB连接字符串(包含数据库凭证)和(2)OIDC客户秘密。由于这两个值的处理方式不同,你将使用两种略有不同的方法来加密它们。

这里有三个不同的加密层。我发现这有点令人困惑,所以我将简要地解释一下:

  • JHipster注册表对Spring Cloud配置值进行加密(值在k8s/registry-k8s/application-configmap.yml )。
  • Kubernetes "加密"(实际上是混淆),将Kubernetes部署文件中的秘密转移到base64编码的秘密文件中
  • kubeseal 将Kubernetes的秘密强化为适当的加密值

上述第一项仅适用于Spring Cloud配置值。后面两个用于加密Kubernetes描述符文件(k8s 目录中的其他yml 文件)中的值。

当你使用JHipster注册表加密时,你必须定义一个ENCRYPT_KEY 值,由JHipster用来加密秘密。然而,由于该值存储在即将提交到存储库的yml 文件中,因此必须对该值进行适当加密,以确保Spring Cloud Config值的安全性。

Cosmos DB连接字符串(SPRING_DATA_MONGODB_URI env var)是一个Kubernetes部署值,与ENCRYPT_KEY 相同,不是Spring Cloud Config值。

因此,为了加固OIDC客户端秘密,你必须(1)定义一个ENCRYPT_KEY ,以启用JHipster注册表加密,(2)使用JHipster注册表加密客户端ID,并将加密后的值放入application-configmap.yml ,以及(3)使用Kubernetes秘密和kubeseal ,以正确加密ENCRYPT_KEY

确保Cosmos DB连接字符串的安全与ENCRYPT_KEY :使用Kubernetes secrets和kubeseal ,对其进行适当加密。

Matt Raible在他的文章《Kubernetes to the Cloud with Spring Boot and JHipster》中对Kubernetes的秘密管理做了很好的解释。他还链接了很多很棒的资源。我不打算在这里做更详细的解释。请看他的帖子,了解更多信息。

你需要做的第一件事是在AKS集群中安装kubeseal 。你可以看一下 kubeseal GitHub 页面,了解更多信息。

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.17.5/controller.yaml

检索该控制器生成的证书密钥对。

kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml

复制tls.crt 的原始值并对其进行解码。你可以使用命令行,或者在我们的文档中了解更多关于base64编码/解码的信息。

echo -n <paste-value-here> | base64 --decode

把原始值放在一个tls.crt 文件中。

接下来,安装Kubeseal。在macOS上,你可以使用Homebrew。对于其他平台,请看发行说明

brew install kubeseal

加密ENCRYPT_KEYSPRING_DATA_MONGODB_URI (Cosmos DB的连接字符串)。运行下面的命令来做这件事,用你的加密密钥和你的连接字符串替换这两个值

kubectl create secret generic project-secrets \
  --from-literal=ENCRYPT_KEY='<your-encryption-key>' \
  --from-literal=SPRING_DATA_MONGODB_URI='<your-connection-string>' \
  --dry-run=client -o yaml > secrets.yml

如果你之前删除了命名空间,你需要再次创建它(如果你没有删除命名空间,运行这个也无妨)。

kubectl apply -f namespace.yml

现在,使用kubeseal ,将秘密转换为加密的秘密。

kubeseal --cert tls.crt --format=yaml -n demo < secrets.yml > sealed-secrets.yml

删除原始秘密文件并部署你的密封秘密。

rm secrets.yml
kubectl apply -n demo -f sealed-secrets.yml && kubectl get -n demo sealedsecret project-secrets

你需要更新yml 文件,以引用加密后的值。在k8s/registry-k8s/jhipster-registry.ymljhister-registry 容器中添加以下 env 变量(如果ENCRYPT_KEY 已经存在,请替换它)。

env:
  ...
  - name: ENCRYPT_KEY
    valueFrom:
      secretKeyRef:
        name: project-secrets
        key: ENCRYPT_KEY

k8s/store-k8s/store-deployment.yml 中,改变SPRING_DATA_MONGODB_URI 环境变量以使用密封的秘密。

env:
  ...
  - name: SPRING_DATA_MONGODB_URI
    valueFrom:
      secretKeyRef:
        name: project-secrets
        key: SPRING_DATA_MONGODB_URI

部署集群。

./kubectl-apply.sh -f

给群集一点时间来启动。用我提到的一个工具或下面的方法来检查它。

kubectl get pods -n demo

一旦一切准备就绪,端口转发注册表以检查服务。

kubectl port-forward svc/jhipster-registry -n demo 8761

确保你可以登录并且所有的服务都是绿色的。你应该被自动登录并重定向到主页,或者被引导到用Okta登录界面登录。

这就是快乐的舞蹈:

Happy Dance!

转发网关并测试应用程序。

kubectl port-forward svc/gateway -n demo 8080

登录。确保一切正常。踢轮胎。开始一个博客。创造一些产品。影响一些人。恢复民主。占领世界。无论你想要什么。

一旦你完成了一切,你可以删除资源组。这也将删除该资源组中的所有资源,包括Cosmos数据库和AKS集群。如果你有多个订阅,你可能需要添加一个--subscription param。

az group delete --name australia-east

等待这个完成。完成后,最好登录Azure门户,确保AKS集群、Cosmos DB实例和资源组已被删除。

Azure AKS、Kubernetes和Spring Boot微服务已经部署完毕!

感谢Julien Dubois帮助完成这个教程!

在这个项目中,你看到了如何将一个JHipster微服务部署到Azure AKS。你看到了如何在Kubernetes中使用管理的Cosmos DB实例来代替MongoDB pod。你看到了如何先用Docker Compose部署应用程序,然后用kubectl 和Azure CLI部署。最后,你使用JHipster注册表加密、Kubernetes秘密和kubeseal ,对所有的敏感配置值进行了适当的加密。