云计算的采用在全球范围内继续快速增长,而不仅仅是在软件行业。每年都有越来越多的公司将其应用程序转移到云端。在2021年12月的最后一次JHipster社区调查中,参与者重视JHipster能够让他们更快地投入生产,并要求提供更多关于部署到云平台的教程。根据一些调查,DigitalOcean是最受欢迎的 "其他 "云供应商之一。这篇文章是一个快速演练,介绍了将JHipster微服务架构部署到DigitalOcean的云中的Kubernetes集群。
本教程是用以下框架和工具创建的:
- JHipster 7.8.1
- Java OpenJDK 11
- Okta CLI 0.10.0
- doctl 1.72.0-release
- kubectl 1.23
- minikube v1.25.2
- k9s v0.25.18
- Docker 20.10.12
目录
- 关于DigitalOcean
- 为Kubernetes建立一个微服务架构
- 使用OpenID Connect配置认证
- 使用minikube在本地运行
- 部署到DigitalOcean Kubernetes上
- 用HTTPS保护网络流量
- 检查和管理集群资源
- 了解更多关于JHipster和Kubernetes的信息
关于DigitalOcean
DigitalOcean是一家云服务公司,由Ben和Moisey Uretsky兄弟在2011年创立。他们的总部位于美国纽约市,在马萨诸塞州和班加罗尔也有办事处。去年3月2022年,DigitalOcean达到IPO(首次公开募股),一些媒体文章将其描述为小企业的云服务提供商。"小人物的云服务"。
DigitalOcean Kubernetes(DOKS)是一个可管理的Kubernetes服务,让你部署Kubernetes集群,而不需要处理控制窗格和容器化基础设施的复杂问题。集群与标准的Kubernetes工具链兼容,并与DigitalOcean负载均衡器和块存储卷原生集成。DOKS提供快速配置和部署,并提供一个免费的高可用性控制窗格,用于可靠性管理。它还可以提供一个集群自动调节器,通过根据集群的容量增加或删除节点来自动调整集群的规模,以安排吊舱。Kubernetes工作负载的定价是基于集群、液滴、块存储和负载平衡器所需的资源。
该公司在其网站上公布了其数据中心的认证报告,所有的数据中心都批准了以下两个或更多的认证。SOC(系统和组织控制)1型II,SOC 2型II,SOC 3型II,以及ISO/IEC 27001:2013(安全技术-信息安全管理系统)。所有数据中心都通过了PCI-DSS(支付卡行业-数据安全标准)的认证。
为Kubernetes设置一个微服务架构
在进行应用工作之前,你需要安装JHipster。使用JHipster的经典方式是用NPM进行本地安装。
npm install -g generator-jhipster@7
如果你愿意使用Yarn或Docker,请按照jhipster.tech上的说明进行。
对于这个测试,从GitHub上的java-microservices-examples 仓库中的reactive-jhipster 示例开始。这个例子是一个JHipster反应式微服务架构,采用Spring Cloud Gateway和Spring WebFlux,Vue作为客户端框架,Gradle作为构建工具。你可以在Reactive Java Microservices with Spring Boot and JHipster中阅读它是如何构建的。
git clone https://github.com/oktadev/java-microservices-examples.git
cd java-microservices-examples/reactive-jhipster
如果你检查项目文件夹,你会发现gateway 服务的子文件夹,它将作为前端应用程序,以及通往store 和blog 微服务的网关,它们也有各自的子文件夹。一个docker-compose 子文件夹包含运行应用程序容器的服务定义。
下一步是生成Kubernetes部署描述符。在项目根文件夹中,创建一个kubernetes 目录并运行k8s JHipster子生成器。
mkdir kubernetes
cd kubernetes
jhipster k8s
在提示时选择以下选项:
- 应用程序的类型。微服务应用
- 根目录:.../
- 哪些应用程序?(选择所有)
- 是否设置了监控?没有
- 哪些应用有集群数据库? 选择存储
- JHipster注册表的管理密码:(生成一个)。
- Kubernetes命名空间:Demo
- Docker仓库名称:(你的docker hub用户名)
- 推送Docker镜像的命令。
docker push - 启用Istio?没有
- Kubernetes服务类型?负载平衡器
- 使用动态存储配置?是
- 使用特定的存储类别? (留空)。
注意:在本地运行Kubernetes时,你可以不填Docker仓库名称,但在云端部署时需要一个仓库,所以继续创建一个DockerHub个人账户,镜像拉动配置将为本地和云端部署做准备。
用Jib构建gateway,store, 和blog 服务容器镜像。由于Jib将推送镜像到DockerHub,你首先需要做一个docker login 。
docker login
如果你启用了双因素认证,你必须生成一个令牌,并将其作为登录的密码。在Docker网页中,进入用户菜单,选择账户设置。然后在左边的菜单中选择安全和新访问令牌。
例如,用于构建gateway 服务镜像。
cd ../gateway
./gradlew bootJar -Pprod jib -Djib.to.image=<docker-repo-name>/gateway
重要提示:不幸的是,在写这篇文章的时候,这个应用实例并没有用Java 17构建。正如介绍中所述,这个例子是用Java 11构建的。
检查镜像是否上传到了DockerHub,并在终端中导航到项目根目录进行下一步操作。
用OpenID Connect配置认证
在本地运行架构之前还有一个配置步骤,让我们配置Okta进行认证。
在你开始之前,你需要一个免费的Okta开发者账户。安装Okta CLI并运行okta register ,以注册一个新账户。如果你已经有一个账户,运行okta login 。然后,运行okta apps create jhipster 。选择默认的应用程序名称,或根据您的需要进行更改。 接受为您提供的默认重定向URI值。
Okta CLI是做什么的?
Okta CLI简化了对JHipster应用程序的配置,并为您做了几件事。
- 创建一个具有正确重定向URI的OIDC应用程序。
- 登录:
http://localhost:8080/login/oauth2/code/oidc和http://localhost:8761/login/oauth2/code/oidc - 注销:
http://localhost:8080和http://localhost:8761
- 登录:
- 创建JHipster期望的
ROLE_ADMIN和ROLE_USER组 - 将你的当前用户添加到
ROLE_ADMIN和ROLE_USER组中。 - 在你的默认授权服务器中创建一个
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.env 中的设置添加到kubernetes/registry-k8s/application-configmap.yml 。
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: <client-secret>
通过在kubernetes/registry-k8s/jhipster-registry.yml 文件中添加oauth2 配置文件,在jhipster-registry 服务中启用OIDC认证。
- name: SPRING_PROFILES_ACTIVE
value: prod,k8s,oauth2
用minikube在本地运行
对于minikube,你将需要至少2个CPU。用你的CPU数量启动minikube。
cd kubernetes
minikube --cpus <ncpu> start
minikube会在启动时记录Kubernetes和Docker版本。
Preparing Kubernetes v1.23.3 on Docker 20.10.12 ...
为了使store-mongodb 部署工作,需要属性Service.spec.publishNotReadyAddresses ,而不是注释service.alpha.kubernetes.io/tolerate-unready-endpoints ,因为后者在Kubernetes 1.11版本中被废弃。
编辑kubernetes/store-k8s/store-mongodb.yml ,将publishNotReadyAddresses: true 属性添加到文件底部附近的spec 关键中。
...
# Headless service for DNS record
apiVersion: v1
kind: Service
metadata:
name: store-mongodb
namespace: demo
spec:
type: ClusterIP
clusterIP: None
publishNotReadyAddresses: true
ports:
- name: peer
port: 27017
selector:
app: store-mongodb
然后将该应用程序部署到minikube。 在kubernetes 目录中,运行。
./kubectl-apply.sh -f
现在是安装k9s的好时机,这是一个基于终端的UI,用于与Kubernetes集群互动。然后运行k9s与。
k9s -n demo

查看命令列表,一些有用的命令是:
:namespace:显示所有可用的命名空间:pods:显示所有可用的pods
你可以用ENTER 来浏览pod,用ESC 键返回。
为JHipster注册表设置端口转发。
kubectl port-forward svc/jhipster-registry -n demo 8761
导航到http://localhost:8761 ,用你的Okta凭证登录。当注册表显示所有服务为绿色时,也为网关设置端口转发。
kubectl port-forward svc/gateway -n demo 8080
导航到http://localhost:8080 ,登录,并创建一些实体,以验证一切工作是否正常。
在四处查看后,在云部署前停止minikube。
minikube stop
同时删除minikube集群,为将来的测试提供一个干净的环境。
minikube delete
部署到DigitalOcean Kubernetes上
现在,该架构在本地工作,让我们继续进行云部署。首先,创建一个DigitalOcean账户。注册时需要支付5美元的PayPal,或者提供一张信用卡。
大多数集群任务,如果不是全部,都可以使用doctl,即DigitalOcean API的命令行接口(CLI)来完成。安装该工具,并执行与DigitalOcean的认证。
doctl auth init
你会被提示输入DigitalOcean的访问令牌,你可以在DigitalOcean控制面板中生成。登录,然后在左边的菜单中进入API,点击生成新令牌。输入一个令牌名称,并点击生成令牌。从Tokens/Keys表中复制新的令牌。

你可以在DigitalOcean找到集群资源定价的详细列表,通过doctl ,你可以快速检索到你的账户可用的节点大小选项列表。
doctl k options sizes
用以下命令行创建集群。
doctl k cluster create do1 -v --size s-4vcpu-8gb-intel
创建集群后,doctl ,将配置上下文添加到kubectl ,并使其处于活动状态,因此你可以立即开始用k9s监控你的集群。首先,将资源配置应用到DigitalOcean集群上。
./kubectl-apply.sh -f
用k9s监控部署。
k9s -n demo

一旦你看到jhipster-registry pods已经建立,再次设置端口转发,这样你也可以在注册表UI中监控服务的状态。
关于DigitalOcean的节点大小和体积的说明
如果你不从一开始就指定足够的容量,在DigitalOcean的云上部署到Kubernetes集群是很棘手的。
起初,我测试了我的账户可用的最高尺寸英特尔节点的集群,s-2vcpu-4gb-intel 。我试图在默认的集群配置中运行该应用程序,即在nyc1区域的一个单节点池的三节点集群,使用最新的Kubernetes版本。当我开始看到pods由于insufficient CPU ,而无法运行时,我增加了节点的数量,并使一切正常。在写这篇文章的时候,DigitalOcean的最新和默认的Kubernetes版本是1.22.8。
如果你需要找出一个pod不运行的原因,你可以用kubectl describe ,比如说jhipster-registry-0 pod,来获取pod的事件。
kubectl describe pod jhipster-registry-0 -n demo
该命令的输出,在事件部分,对于一个由于cpu不足而失败的pod,看起来如下。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal NotTriggerScaleUp 4m30s cluster-autoscaler pod didn't trigger scale-up:
Warning FailedScheduling 69s (x3 over 95s) default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
如果你在k9s 中看到一个 pod 失败了,用kubectl describe pod 检查该 pod 的事件,如上面的例子。
要增加CPU,用doctl 增加节点的数量。
doctl k cluster node-pool update do1 do1-default-pool --count 4
增加节点时,你不需要重新启动pod。
在我增加CPU后(在集群中增加一个节点),一些pod,在有3个副本的store-mongodb 有状态的集合中,由于未绑定即时的PersistentVolumeClaims而不能运行。这在pod事件中,在kubectl describe pod 的输出中,对失败的pod进行了报告。然后我用下面的命令检查了持久性卷要求。
kubectl get pvc -n demo
kubectl describe pvc datadir-store-mongodb-2 -n demo
kubectl describe pvc 命令输出显示配置错误,并指示联系支持。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 3m6s (x10 over 11m) dobs.csi.digitalocean.com_master-do3_cebb3451-5eba-4805-956c-753ec148e2ea External provisioner is provisioning volume for claim "demo/datadir-store-mongodb-2"
Warning ProvisioningFailed 3m5s (x10 over 11m) dobs.csi.digitalocean.com_master-do3_cebb3451-5eba-4805-956c-753ec148e2ea failed to provision volume with StorageClass "do-block-storage": rpc error: code = ResourceExhausted desc = volume limit (10) has been reached. Current number of volumes: 10. Please contact support.
Normal ExternalProvisioning 103s (x43 over 11m) persistentvolume-controller waiting for a volume to be created, either by external provisioner "dobs.csi.digitalocean.com" or manually created by system administrator
按照事件消息的指示,我联系了DigitalOcean的支持,他们修复了它。
最后,由于我首先注册了免费试用账户,我不得不开了第二张支持票,要求提高节点尺寸,这样我就可以使用尺寸s-4vcpu-8gb-intel 。在注册试用后,并不是所有的尺寸选项都可用,但对于标准账户来说,情况并非如此。对于一个简短的Kubernetes服务测试,账单应该在10美元以下。
找到你的网关的外部IP并更新重定向URI
一旦所有的pod都在运行,用kubectl describe 命令找到网关的外部IP。
kubectl describe service gateway -n demo
输出会是这样的:
Name: gateway
Namespace: demo
Labels: app=gateway
Annotations: kubernetes.digitalocean.com/load-balancer-id: e81d2b8c-6c28-430d-8ba8-6dab29a1ba76
service.beta.kubernetes.io/do-loadbalancer-certificate-id: bd0b1d03-0f90-449d-abbe-ac6a4026c133
Selector: app=gateway
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.245.47.51
IPs: 10.245.47.51
LoadBalancer Ingress: 157.230.200.181
Port: http 8080/TCP
TargetPort: 8080/TCP
NodePort: http 31048/TCP
Endpoints: 10.244.1.42:8080
Session Affinity: None
External Traffic Policy: Cluster
更新Okta中的重定向URI,允许网关地址作为有效重定向。运行okta login ,在浏览器中打开返回的URL,并登录到Okta管理控制台。进入应用程序部分,找到你的应用程序,编辑,然后添加
- 签入重定向URI。
http://<load-balancer-ingress-ip>:8080/login/oauth2/code/oidc - 签出重定向URI。
http://<load-balancer-ingress-ip>:8080
导航到http://<load-balancer-ingress-ip>:8080 ,当一切正常时,你会感到欣喜!
用HTTPS保护网络流量
由于网关服务作为应用程序的前端,在k8s描述符中它被定义为LoadBalancer 服务类型。这使得该服务使用云提供商的负载平衡器对外公开。DigitalOcean负载平衡器是一个完全管理的、高度可用的网络负载平衡服务。负载平衡器将流量分配到液滴组,这将后端服务的整体健康状况与单个服务器的健康状况解耦,以确保你的服务保持在线。
标准的做法是用HTTPS来保护你的应用程序的网络流量。对于流量加密,你需要一个TLS(SSL)证书。如果你用DigitalOcean的DNS管理你的域名,DigitalOcean还提供自动证书创建和更新,这是免费的。但不提供域名注册。 要使用DigitalOcean的DNS,你需要在注册商那里注册一个域名,并更新你的域名的NS记录,以指向DigitalOcean的名称服务器。
然后,为了使用DigitalOcean的管理域名和证书,你必须委托域名,更新注册商的NS记录。由于这一要求,你不能使用免费的DNS服务,你不能设置NS记录,如nip.io。
重要提示:在改变注册商的NS记录(nameservers)之前,将你的域名添加到DigitalOcean,以尽量减少服务中断。
你可以在DigitalOcean控制面板中同时创建证书和域名,当你设置负载平衡器的HTTPS转发时。
DigitalOcean负载平衡器支持两个主要配置,用于加密的网络流量。
- SSL终止: 在负载平衡器上解密SSL请求,并将其未加密地发送到Droplets私人IP地址的后端。在负载均衡器上进行较慢的和CPU密集型的解密工作,并简化证书管理。负载均衡器和后端之间的流量通过VPC网络的路由得到保障,但数据在私有网络内是可读的。
- SSL直通: 将加密的SSL请求直接发送到Droplets的私有IP地址的后端,负载平衡器和后端之间的流量是安全的。每个后端服务器都必须有证书,
X-forwarded-*headers中包含的客户信息可能会丢失。
利用简化的证书管理,SSL终止将在以下步骤中通过DigitalOcean控制面板进行配置。
登录到你的DigitalOcean账户,在左边的菜单中选择Kubernetes。然后选择你的集群,在集群页面上,选择资源。在LOAD BALANCERS列表中,选择必须创建的单个负载平衡器。在负载平衡器页面,选择设置标签。在转发规则中点击编辑。在 443 端口添加一个 HTTPS 的转发规则,在证书下拉菜单中,选择新证书。

在新证书表格中,选择使用Let's Encrypt标签,然后在域名框中,选择添加新域名。然后输入你的域名,并列出要包括的其他子域。为证书添加一个名称,然后点击生成证书。

回到转发规则页面,检查生成的证书是否被选中,并将流量转发到网关运行的dropplet HTTP端口。勾选为所有新Let's Encrypt证书创建DNS记录的复选框,然后保存转发设置。

最后,在设置的SSL部分,勾选重定向HTTP到HTTPS的复选框。

再次,更新Okta中的重定向URI,以允许新配置的域名。添加以下重定向URI。
- 签入重定向URI:
https://<your-domain>/login/oauth2/code/oidc - 签出重定向URI。
https://<your-domain>
通过导航到http://<your-domain> 来测试配置。首先,负载平衡器应该重定向到HTTPs,然后网关应该重定向到Okta的登录页面。
检查和管理集群资源
你可以用下面的doctl 命令来检索集群的相关资源。
doctl k cluster list-associated-resources do1
输出将列出为集群创建的卷和负载均衡器,除了节点的成本外,它们还产生计费。
Volumes Volume Snapshots Load Balancers
[a33dbaba-cb22-11ec-9383-0a58ac145375 a6e18809-cb22-11ec-8723-0a58ac14468c 65fb3778-cb23-11ec-9383-0a58ac145375 ac106c49-cb22-11ec-9383-0a58ac145375 c7122288-cb22-11ec-bd08-0a58ac14467d] [] [8ebbcbf2-1e67-46f5-b38a-eddae17f00f3]
不幸的是,没有办法暂停集群的运行。根据DigitalOcean的说法,你可以关闭一个液滴的电源,但这并不能停止计费。通过对液滴进行快照,然后将其销毁,可以降低计费成本。快照的费用比较低。
在测试平台时,你可以在两次会议之间删除集群,以避免在不积极工作时花费试用信用。
doctl k cluster delete do1
提供给集群的卷不会与集群一起删除,并且每小时都会产生费用。你可以使用控制面板或以下命令来删除卷。
doctl compute volume list
doctl compute volume delete <volume-id>
负载均衡器也不会随集群一起删除。
doctl compute load-balancer list
doctl compute load-balancer delete <load-balancer-id>
在注册期间,必须已经创建了一个项目,允许你组织资源。你可以用下面的命令列出与一个项目相关的所有资源。
doctl projects list
doctl projects resources list <project-id>