如果你一直在考虑将你的Spring Boot应用部署到云端,但却觉得各种复杂的步骤让人感到无从下手,不用担心,你并不孤单。

Kubernetes乍看之下可能会让人感到有些畏惧,但Amazon EKS(弹性Kubernetes服务)使得它变得容易上手多了,尤其是当你有详细的操作指南可以参考时。

在这个教程中,我们将详细讲解如何将一个使用MySQL数据库的Spring Boot应用部署在Amazon EKS上。我会带你从将应用容器化开始,到将其连接到托管数据库,最终再到在云端直接访问该应用。让我们开始吧。

目录

先决条件

在开始之前,请确保你具备以下条件:

  • 对AWS有基本了解(能够使用AWS控制台)。

  • 具备容器化技术的基本知识。

  • 熟悉Kubernetes的使用方法。

  • 对数据库有基本的了解。

  • 已安装Helm

  • 已安装Kubectl

  • 已安装Eksctl

  • 拥有一款集成开发环境(IDE)。

应用程序概述

该应用程序运行在覆盖两个可用区域的AWS VPC中,以此来实现高可用性。当用户发起请求时,这些请求会通过互联网网关进入位于公共子网中的AWS应用负载均衡器,而该负载均衡器会根据相应的规则来处理传入的流量。

负载均衡器会将请求路由到App Service,而App Service则会将这些请求分配给运行在私有子网中的多个App Pod,这些Pod实际上是在AWS EKS(弹性Kubernetes服务)上运行的。

这些Pod所使用的Docker镜像是从AWS ECR(弹性容器注册库)中获取的。为了实现数据持久化,这些App Pod会通过MySQL外部服务与Amazon RDS MySQL数据库进行连接;每个可用区域都部署有一个RDS实例,以此来确保数据的冗余性。

公共子网中的NAT网关使得私有资源能够发起出站互联网请求,而无需直接暴露在互联网环境中。

什么是Amazon EKS?

如果你曾经尝试过手动管理容器,那么你应该知道这样做会很快变得非常繁琐:需要跟踪哪些容器正在运行、重启那些发生故障的容器、在流量激增时进行扩展……这些工作确实很麻烦。

而Kubernetes正是为了解决这类问题而开发的。它能够自动化地完成容器的部署、扩展和管理工作。但是,如果要从零开始搭建和维护自己的Kubernetes集群的话,那无疑又是一项巨大的挑战。

这时,Amazon EKS就派上了用场。EKS是由AWS提供的全托管型Kubernetes服务,这意味着AWS会负责所有与设置、安全保障以及维护Kubernetes控制平面相关的工作,而你只需要专注于部署自己的应用程序即可。

如何在Amazon EKS上部署带有MySQL的Spring Boot应用

在本节中,我们将详细介绍在Amazon EKS上部署带有MySQL的Spring Boot应用所需遵循的步骤。

步骤1:创建VPC

要创建一个VPC,请登录到AWS IAM控制台,搜索“VPC”,然后点击“创建VPC”按钮。

vpc interface

选择“VPC及其他选项”,为你的项目指定一个名称,例如“spring-demo”。将IPv4 CIDR块设置为10.4.0.0/16。在配置NAT网关时,请选择“区域型”选项,并选择“位于同一可用区域内”。

NAT网关配置

如果不需要为VPC端点进行配置,可以选择“无”。接下来,点击“创建VPC”,然后再点击“查看VPC”,这样就能进入VPC资源管理界面。

步骤2:在私有子网中设置MySQL数据库

首先,你需要为MySQL实例和EC2实例的部署创建安全组。具体操作方法是:进入“EC2”>“安全组”。对于入站规则,选择“类型:所有流量”和“来源:任意IPv4地址”,然后点击“创建安全组”。

接下来,我们需要为数据库创建子网组。操作步骤如下:进入“Aurora and RDS”>“子网组”,然后点击“创建DB子网组”。接着配置该子网组,具体设置内容如下:

  • 名称:private-subnet-db

  • 描述:private-subnet-db

  • VPC:选择相应的VPC

  • 添加子网:选择可用区us-east-1aus-east-1b,然后选中对应的私有子网和公共子网

点击“创建”。

现在,进入“数据库”页面,点击“创建数据库”,并选择“完整配置”。将引擎类型设置为MySQL。

在选择模板时,请选择免费 tier。接下来,为数据库设置用户名和强密码,并选择实例类型db.t3.micro

选择你的VPC以及相关的私有子网。然后,在“附加配置”选项中取消选中“启用自动minor版本升级”选项,最后点击“创建数据库”。

在数据库初始化期间,我们可以为将在公共子网中启动的EC2实例创建一对密钥对。操作方法是:进入“EC2”>“网络与安全”>“密钥对”,然后点击“创建密钥对”。

给这対密钥对起个名字,比如“ece-db-key-pair”。其他设置保持不变,然后点击“创建密钥对”。系统会自动将密钥对下载到你的本地机器上。

步骤3:在公共子网中部署EC2实例

现在可以创建EC2实例了。操作方法是:进入“EC2”>“实例”,然后点击“启动实例”。在密钥对选项中,选择你刚刚创建的那対密钥对。

接下来,在“网络”设置中,选择之前为该项目创建的VPC。对于“自动分配公共IP地址”的选项,选择“启用”。接着,选择“使用现有的安全组”,并选中之前创建的“all-access-sg”安全组。最后点击“启动实例”。

步骤4:为数据库创建SSH隧道

在这一步中,打开终端,进入存放密钥对的文件夹。运行ls命令,你应该能看到那対密钥对文件。

接下来,你需要更改密钥对文件的权限。请使用以下命令:

chmod 0400 ece-db-key-pair.pem

现在,运行以下的SSH隧道建立命令:

ssh -i .pem -f -N -L :: @ -v
  • .pem:你下载到的密钥对文件的名称

  • :你的笔记本电脑上的端口号(MySQL使用3306,PostgreSQL使用5432)

  • :可以在AWS控制台 > RDS > 你的数据库 > 连接性与安全性 > 端点中找到该地址

  • :与本地端口号相同(MySQL使用3306,PostgreSQL使用5432)

  • :对于Amazon Linux来说通常是“ec2-user”,对于Ubuntu来说则是“ubuntu”

  • :可以在AWS控制台 > EC2 > 你的实例 > 公共IPv4 DNS中找到该地址

这条命令可以让你的笔记本电脑或本地机器直接与远程数据库进行通信,就像这个数据库就在你的电脑上一样。

运行完这条命令后,你可以在笔记本电脑上打开一个数据库工具(比如MySQL Workbench、DBeaver或TablePlus),然后连接到以下地址:

  • 主机:localhost

  • 端口:3306

在本教程中,我将使用DBeaver的社区版。你也可以使用其他类似的工具,但如果你希望按照本指南的步骤来操作,可以从官方DBeaver下载页面下载社区版并进行安装。

下载并安装完成后,打开DBeaver客户端,然后点击应用程序左上角的“连接数据库”图标。

选择MySQL,然后点击“下一步”。在下一个窗口中,输入你的数据库用户名和密码,并将“服务器主机”设置为127.0.0.1。

点击“测试连接”。

你应该会看到一个提示窗口,说明连接已经成功建立。

点击“确定”并完成设置。

现在,在左侧面板中,你应该能够看到自己的连接信息。展开该连接信息,就可以查看数据库的结构了。

database structure

现在,你已经成功地为你的数据库建立了SSH隧道。

故障排除

在尝试测试数据库连接时,我最初遇到了“插件‘mysql_native_password’未加载”的错误。如果你也遇到了这个错误,请按照以下步骤进行解决。

  1. 在“连接设置”窗口中,进入“驱动程序属性”选项卡。

  2. 找到“允许公钥检索”选项,并将其设置为“FALSE”。

  3. 返回“主”选项卡,然后点击“测试连接”。

现在一切都应该可以正常运行了。

步骤 5:设置简单的 SpringBoot 应用开发环境

要开始操作,请访问 Spring Initializr 网站。将项目名称更改为“springboot-mysql-eks”,然后点击“添加依赖项”……为 REST API 添加所需的依赖项。请搜索以下依赖项:

  • Spring Web: 使用 Spring MVC 构建网页应用,包括 RESTful 应用程序。默认使用 Apache Tomcat 作为嵌入式容器。

  • Spring Data JPA: 利用 Spring Data 和 Hibernate 通过 Java Persistence API 将数据存储在 SQL 数据库中。

  • IBM DB2 驱动程序: 一种 JDBC 驱动程序,用于访问 IBM DB2 数据库。

  • Lombok: 一个 Java 注解库,可帮助减少冗余代码。

接下来,请点击页面底部中间的“生成”按钮。此操作会将在本地计算机上下载一个 zip 文件。请在 VSCode 或 IntelliJ IDEA 等集成开发环境中打开该文件。在本教程中,我使用的是 VSCode。在 `build.gradle` 文件中,您可以看到所有添加的依赖项:

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-webmvc'
   compileOnly 'org.projectlombok:lombok'
   runtimeOnly 'com.ibm.db2:jcc'
   annotationProcessor 'org.projectlombok:lombok'
   testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
   testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
   testCompileOnly 'org.projectlombok:lombok'
   testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
   testAnnotationProcessor 'org.projectlombok:lombok'
}

我们正在构建什么

这个 Spring Boot 应用程序是一个用于查询和转换货币汇率的应用程序:

图片

我们会将汇率数据插入数据库表中。

为了继续学习本教程,您可以直接 在这里 克隆项目代码库,以节省时间。

在 `main` > `java` > `com..` > `model` > `ExchangeRate` 目录下,您会看到以下代码:

package com.example.springbootmysqleks.model;

import jakarta.persistence.*;
import lombokgetter;
import lomboksetter;

import java.sql.Date;

getter
setter
@Entity
@Table(name = "exchange-rate")
public class ExchangeRate {
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   private Integer transactionId;
   private String sourceCurrency;
   private String targetCurrency;
   private double amount;
   private Date lastUpdated;
}

这个类实际上是我们数据库中存储货币汇率数据的一个蓝图。它使用了之前添加的各种库和依赖项。Lombok会处理所有重复出现的getter/setter代码,因此你无需自己编写这些代码;而像〈code>@Entity@Table这样的JPA注解则会告诉Spring:“这个类对应于数据库中名为‘exchange-rate’的表。”

在这个类中,有五个字段会成为数据库中的列:

  • 一个自增型的transactionId作为主键。

  • sourceCurrency和targetCurrency,用于记录哪些货币正在被转换。

  • amount字段用于存储实际的汇率数值。

  • lastUpdated字段用于记录数据最后一次更新的时间,这样你就能知道这些数据的时效性如何。

要存储这些数据,请在main > java > com.. > repository目录下创建一个名为ExchangeRateRepository的文件:

package com.example.springbootmysqleks.repository;

import com.example.sparkbootmysqleks.model.ExchangeRate;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ExchangeRateRepository extends JpaRepository {
   ExchangeRate findBySourceCurrencyAndTargetCurrency(String sourceCurrency, String targetCurrency);
}

这个文件充当了你的代码与数据库之间的桥梁。只需继承JpaRepository,你就能立即获得一整套内置的数据库操作功能(如保存、删除、查找所有数据等),而且完全不需要编写任何SQL语句。

该接口被设计为可以与我们刚才看到的〈code>ExchangeRate模型配合使用,其中主键类型被设置为Integer。

其中的自定义方法〈code>findBySourceCurrencyAndTargetCurrency正是Spring的强大之处所在。只要遵循一定的命名规则,Spring就会自动生成所需的SQL查询语句;因此你只需传入两个货币代码(比如“USD”和“EUR”),就能获取相应的汇率信息,而完全不需要自己编写任何查询逻辑。

要使用〈code>findBySourceCurrencyAndTargetCurrency方法,请在main > java > com.. > service目录下创建一个名为ExchangeRateService的服务类,并编写如下代码:

package com.example.sparkbootmysqleks.service;

import com.example.sparkbootmysqleks.model.ExchangeRate;
import com.example.sparkbootmysqleks.repository.ExchangeRateRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ExchangeRateService {

   @Autowired
   private ExchangeRateRepository exchangeRateRepository;

   public ExchangeRate addExchangeRate(ExchangeRate exchangeRate) {
       return exchangeRateRepository.save(exchangeRate);
   }

   public double getAmount(String sourceCurrency, String targetCurrency) {
       ExchangeRate exchangeRate = exchangeRateRepository.findBySourceCurrencyAndTargetCurrency(sourceCurrency, targetCurrency);
       return exchangeRate == null ? 0 : exchangeRate.amount();
   }
}

在这里,我们创建了一个 `@Service` 类,该类用于与数据库进行交互。

这个类包含两个方法:`addExchangeRate` 方法接收一个 `ExchangeRate` 对象并将其保存到数据库中;`getAmount` 方法则接受源货币和目标货币作为参数,使用我们自定义的数据库访问逻辑来查找相应的记录,如果找不到记录,则返回0作为默认值。

通过这个简单的三元条件判断 (`exchangeRate == null ? 0 : exchangeRate.amount()`),我们可以确保在查询数据库中还不存在的货币对时,应用程序不会出现异常。

在 `main > java > com.. > controller > ExchangeRateService` 目录下,我们有以下代码:

package com.example.springbootmysqleks.controller;

import com.example.bootmysqleks.modelExchangeRate;
import com.example.bootmysqleks.service.ExchangeRateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class ExchangeRateController {

   @Autowired
   ExchangeRateService exchangeRateService;

   @GetMapping("/getAmount")
   public double getAmount(@RequestParam String sourceCurrency, @RequestParam String targetCurrency) {
       return exchangeRateService.getAmount(sourceCurrency, targetCurrency);
   }

   @PostMapping("/addExchangeRate")
   public ExchangeRate addExchangeRate(@RequestBody ExchangeRate exchangeRate) {
       return exchangeRateService.addExchangeRate(exchangeRate);
   }

   @GetMapping("/")
   public String getHealth() {
       return "up";
   }

}

`@RestController` 注解告诉 Spring 这个类将用于提供 REST API 接口;`@Autowired` 注解则负责自动连接服务层组件。

目前共有三个 API 接口:

  1. 对 `/getAmount` 的 GET 请求,它会接受 `sourceCurrency` 和 `targetCurrency` 作为查询参数,并返回相应的汇率数值。

  2. 对 `/addExchangeRate` 的 POST 请求,它会接收一个完整的 `ExchangeRate` 对象作为 JSON 数据,并将其保存到数据库中。

  3. 还有一个简单的健康检查接口,路径为 `/`,它仅返回 “up” 字符串。这种设计在云部署环境中很常见,用于让负载均衡器和调度工具知道应用程序正在正常运行。

步骤 6:配置 SpringBoot 应用程序以连接数据库

现在,我们需要配置应用程序以使其能够与数据库进行交互。请导航到 `src > main > resources > application.properties` 文件,你会看到以下内容:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://\({MYSQL_HOSTNAME}:\){MYSQL_PORT}/{MYSQL_DATABASE}?createDatabaseIfNotExist=true
spring.datasource.username=${MYSQL_USERNAME}
spring.datasource.password=${MYSQL_PASSWORD}

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql: true

这些配置项能够让您的应用程序与数据库建立连接。

  • spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver:用于连接MySQL数据库的驱动程序类。

  • spring.datasource.url=jdbc:mysql://\({MYSQL_HOSTNAME}:\){MYSQL_PORT}/${MYSQL_DATABASE}?createDatabaseIfNotExist=true:这是数据源的URL,其中包含了MySQL的主机名(127.0.0.1)、端口号以及数据库名称。

  • spring.datasource.username=${MYSQL_USERNAME}:您的数据库用户名。

  • spring.datasource.password=${MYSQL_PASSWORD}:您的数据库密码。

需要注意的一点是:根据您所使用的IDE不同,使用实际凭据来配置环境变量的具体步骤也会有所差异。如果您使用的是IntelliJ IDEA,这个过程会相当简单;而如果使用VS Code,则操作方法会有所不同。

要为env变量配置您的实际凭据,请在项目根目录下创建一个.vscode/launch.json文件,并将以下配置内容粘贴到其中:

{
 "version": "0.2.0",
 "configurations": [
   {
     "type": "java",
     "name": "Spring Boot App",
     "request": "launch",
     "mainClass": "com.example.springbootmysqleks.SpringbootMysqlEksApplication",
     "projectName": "springboot-mysql-eks",
     "env": {
       "MYSQL_HOSTNAME": "localhost",
       "MYSQL_PORT": "3306",
       "MYSQL_DATABASE": "exchangedb",
       "MYSQL_USERNAME": "root",
       "MYSQL_PASSWORD": "CHANGE_ME"
     }
   }
 ]
}

请使用您的实际凭据来配置这些参数。

现在,当您运行应用程序时,应该能够在DBeaver中看到刚刚创建的exchangedb表:

exchnage db image

您可以使用Postman这样的API测试工具,向数据库发送一个POST请求:

postman request image

接下来,在exchangedb SQL脚本编辑器中运行select * from exchange_rate er这条SQL语句:

sql editor image

在编辑器的底部,您应该能够看到通过Postman请求创建的表格。

现在,请向以下端点发送一个GET请求:

http://localhost:8080/getAmount?sourceCurrency=USD&targetCurrency=EUR&transactionId=1

你应该会收到一个包含货币兑换比率的“200 OK”响应,例如,其数值为0.93。

步骤7:将SpringBoot应用程序容器化

要将您的应用程序进行容器化处理,请创建一个名为Dockerfile的文件,并将以下配置内容粘贴到其中:

FROM eclipse-temurin:17-jre-jammy
WORKDIR /app
COPY build/libs/springboot-mysql-eks.jar /app
EXPOSE 8080
CMD ["java", "-jar", "springboot-mysql-eks.jar"]

我们的Dockerfile首先拉取轻量级的eclipse-temurin:17-jre-jammy基础镜像,以保持容器结构的简洁性;随后将容器内的工作目录设置为/app;接着将编译好的Spring Boot JAR文件从本地的build/libs/文件夹复制到该目录中;同时开放8080端口以接收外部请求;最后,在容器启动时通过java -jar命令来运行应用程序。

接下来,需要构建应用程序以生成.jar文件。为此,请执行以下命令:

./gradlew clean assemble 

执行完成后,系统应会显示成功的构建结果。

bde4395b-bc30-46e4-9687-bd03836f574d

进入build目录,然后查看libs文件夹,您会看到刚刚生成的springboot-mysql-eks文件。

如果遇到“操作无法完成”的错误,请尝试运行相应的命令来解决这个问题。如果您使用的是Mac系统,请执行以下命令:

brew install openjdk@21

接着,再运行以下命令:

export JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home

export PATH=\(JAVA_HOME/bin:\)PATH

之后再次执行./gradlew clean assemble命令即可。

步骤8:将镜像推送到Elastic Container Registry(ECR)

在下一步中,我们将创建一个Amazon ECR账户,并将我们的镜像推送到该注册中心。

首先,请返回AWS控制台并搜索“ECR”。在ECR页面上点击“Create”。接着输入仓库名称,例如“springboot-mysql-eks”,然后再次点击“Create”。

ECR image

接下来,选择该仓库,然后点击页面顶部的“View push commands”按钮。此时会弹出一个窗口,其中列出了可用于将镜像推送到注册中心的各种命令。请在终端中执行这些命令。在执行命令之前,请确保您的本地机器上已经安装了Docker。

命令执行完成后,您应该会看到自己的镜像已经成功被推送到了Elastic Container Registry中。

ECR图像

步骤9:配置AWS应用负载均衡器

在开始执行此步骤之前,请务必查阅项目README文件中提供的安装说明以及相关的AWS文档链接。这些资料将帮助您顺利完成操作。

现在,首先在您的根目录下创建一个名为cluster的新文件夹。您将在该文件夹中下载用于配置负载均衡器的AWS IAM策略。要下载该策略,请进入终端窗口,先使用cd命令切换到cluster文件夹,然后运行以下命令:

curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.14.1/docs/install/iam_policy.json

这个命令的来源是AWS官方文档。执行该命令后,您会在cluster文件夹中看到一个名为iam_policy.json的文件。

接下来,使用以下命令应用这个IAM策略:

aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://iam_policy.json

在终端中,您应该会看到类似以下的输出结果:

终端界面图像

这说明IAM策略已经成功创建。为了确认这一结果,请登录您的控制台,进入IAM管理页面,然后在“ Policies”选项中搜索“AWSLoad…”。您应该能够看到刚刚创建的策略。

负载均衡器策略图像

下一步是创建Kubernetes服务账户。但在执行这一操作之前,您需要按照官方文档中的说明,为您的公共子网和私有子网添加相应的标签。

现在,请登录VPC控制台,进入“Subnets”页面,选择某个子网,然后点击“Tags”选项。接下来,再点击“Manage tags”按钮。

标签设置图像

点击“Add new tag”按钮,然后按照文档中的说明输入键值对信息。

标签设置图像

步骤10:在EKS中创建集群

要在EKS上创建Kubernetes集群,你需要使用eksctl CLI。请按照AWS eksctl文档中的说明来安装该CLI。接下来,你需要一个配置文件模板来创建集群。要使用这个模板,请在集群对应的文件夹中创建一个名为cluster.yaml的新文件。

接下来,将以下配置内容粘贴到该文件中:

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: spring-test-cluster
  region: us-east-1
  version: "1.30"

vpc:
  id: ""
  subnets:
    private:
      us-east-1a:
        id: "" # spring-demo-subnet-private1-us-east-1a
      us-east-1b:
        id: "" # spring-demo-subnet-private2-us-east-1b
    public:
      us-east-1a:
        id: "" # spring-demo-subnet-public1-us-east-1a
      us-east-1b:
        id: "" # spring-demo-subnet-public2-us-east-1b

nodeGroups:
  - name: ng-1
    labels: { role: backend }
    instanceType: t2.micro
    desiredCapacity: 3
    minSize: 3
    maxSize: 5
    privateNetworking: true
    ssh:
      allow: true
      publicKeyName: ""
    iam:
      withAddonPolicies:
        imageBuilder: true
        awsLoadBalancerController: true
        autoScaler: true
iam:
  withOIDC: true
  serviceAccounts:
    - metadata:
        name: aws-load-balancer-controller
        namespace: kube-system
      attachPolicyARNs:
        - arn:aws:iam::policy/AWSLoadBalancerControllerIAMPolicy

eksctl会使用ClusterConfig文件来创建名为spring-test-cluster的Kubernetes集群,该集群位于us-east-1地区,运行的是Kubernetes 1.30版本。这个配置文件会将工作节点分配到us-east-1aus-east-1b这两个可用区中的私有子网中,从而实现高可用性;同时,公共子网也会被用于负载均衡器的配置。

该节点组会创建3台t2.micro类型的EC2实例(必要时最多可扩展到5台),所有这些实例都启用了私有网络功能以确保安全性。此外,该配置还会为AWS负载均衡器控制器、自动扩展机制以及ECR镜像访问设置必要的IAM权限,这样我们的集群就能具备管理流量以及自动下载Docker镜像所需的所有功能。

现在,请使用你的凭据更新配置文件后,运行以下命令:

eksctl create cluster -f cluster.yaml

这个命令会创建集群。在你的终端中,你应该会看到类似的输出结果:

cluster creation image

现在,在您的AWS控制台中,导航到CloudFormation,您会看到集群创建过程正在进行中。

堆栈创建图像

接下来,当您进入EC2实例页面时,应该能够看到已经创建的三个节点。

运行中的集群图像

步骤11:安装AWS负载均衡

下一步是为我们的应用程序安装负载均衡器。首先,请运行以下命令:

 kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller/crds?ref=master"

这条命令会为我们的控制器安装自定义资源定义(CRDs)。接下来,运行以下命令来添加Helm图表仓库。

helm repo add eks https://aws.github.io/eks-charts

更新您的本地仓库,以确保您拥有最新的图表:

helm repo update eks

接下来,安装Helm图表:

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=my-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --version 1.14.0

接下来,验证控制器是否已经安装完成:

kubectl get deployment -n kube-system aws-load-balancer-controller

在终端中,您应该会看到如下结果:

61d954f3-b09d-4691-9b1c-02134c2d8bf1

这表示您的控制器已经安装完成。

步骤12:创建并部署Kubernetes

首先,您需要创建一个Kubernetes配置文件。为此,我们将使用Helm图表

helm create ytchart

上述命令会创建一个名为ytchart的文件夹,其中包含各个组件的模板文件。在这个文件夹中,您需要根据自己的实际需求进行一些配置设置。首先,导航到ytchart > templates目录,然后删除serviceaccount.yaml文件,因为我们已经提前创建过了服务账户。

接下来,请打开 `values.yaml` 文件并进行以下修改:

  • 对于 `repository`,请前往 AWS 控制台的 ECR 服务页面,复制镜像的 URI。

  • 标签应设置为 `latest`。

  • 需要指定数据库名称。

mysql:
 databaseName: exchangedb
  • 将服务账户的创建选项设置为 `false`。

  • 继续向下滚动,将服务的 `type` 更改为 `NodePort`,并将 `port` 设置为 `8080`。

您还需要使用 secrets 文件来存储数据库的用户名和密码。请进入 `templates` 文件夹,找到名为 `secrets.yaml` 的文件,在其中设置数据库的用户名和密码。同时,请在 `deployment.yaml` 文件中取消注释与 liveness 和 readiness probe 相关的配置。

接下来,我们需要创建一个服务来连接数据库。为此,请打开 `mysql.yaml` 文件,找到 `externalName` 配置项;然后前往 AWS 控制台的 RDS 服务页面,复制数据库的端点地址。

现在,在 `deployment.yaml` 文件中,添加以下配置:

          env:
            - name: SPRING_DATASOURCE_URL
              value: jdbc:mysql://spring-mysql:3306/{{ .Values.mysql.databaseName }}?createDatabaseIfNotExist=true&characterEncoding=UTF-8&useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true
            - name: SPRING DATASOURCE_USERNAME
              valueFrom:
                secretKeyRef:
                  name: mysql-username
                  key: username
            - name: SPRING_DATASOURCE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-root-password
                  key: password

您已经成功创建了环境变量,从而保护了数据库的访问凭据。

在 `ingress.yaml` 文件中,添加以下配置:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: "spring-microservice-ingress"
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/load-balancer-name: spring-alb-test
  labels:
    app: spring-microservice
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: {{ include "ytchart.fullname" . }}
                port:
                  number: 8080

这就是您为 ingress 服务配置的内容。

运行以下命令,可以查看所有的配置值:

helm template ytchart/

接下来,运行以下命令来部署该应用:

helm install mychart ytchart

你应该会在终端中看到如下输出:

helm chart image

现在,当你运行 `kubectl get all` 时,应该会看到这样的结果:

deployment image

接下来,进入 EC2 > Load Balancers,复制 DNS 名称,然后在浏览器中输入该地址。你应该会看到 “up” 这一提示信息,这说明你的应用程序运行正常。

现在,如果你使用上述 DNS URL 调用 API,比如:

http://spring-alb-test-260424558.us-east-1.elb.amazonaws.com/addExchangeRate

你应该会收到 200 OK 的响应。恭喜,你已经成功在 Kubernetes 中部署了一个 SpringBoot 应用程序!

步骤 13:删除集群

如果你对 AWS 和云计算有所了解,就应该知道让资源长时间处于运行状态会带来很大的成本负担,尤其是当你并不需要这些资源时。

既然我们已经完成了这个教程的学习,现在是时候删除这些资源了。

需要删除的资源包括:

  • RDS 数据库。

  • 使用命令 `eksctl delete cluster -f cluster.yaml` 来删除集群。

  • 进入 VPC 并删除 NAT Gateway。

总结

在 Amazon EKS 上部署使用 MySQL 的 Spring Boot 应用程序涉及很多环节,但每个步骤都是在前一个步骤的基础上逻辑性地进行的。

通过这个教程,你从配置 VPC、准备管理型数据库,到将应用程序容器化、将其上传到 ECR,最后利用 Kubernetes 和应用负载均衡器来协调所有这些流程,完成了整个部署过程。

最终得到的是一个具备高可用性、私有网络支持、安全凭证管理功能以及自动扩展机制的生产级基础设施。如果没有像 EKS 和 RDS 这样的托管服务,要构建这样的基础设施需要耗费大量的人工精力。

作为下一步,你可以考虑通过 AWS Certificate Manager 添加 HTTPS 支持,设置水平 Pod 自动扩展功能,或者集成 CI/CD 流程来自动化未来的部署工作。另外,在完成实验后记得及时清理你的 AWS 资源,这样才能节省成本。

Comments are closed.