在 AWS (EKS) 上运行 MySQL 集群支持、支持 HTTPS 的 Spring Boot 应用程序

Posted

技术标签:

【中文标题】在 AWS (EKS) 上运行 MySQL 集群支持、支持 HTTPS 的 Spring Boot 应用程序【英文标题】:Run MySQL cluster backed, HTTPS-enabled Spring boot app on AWS (EKS) 【发布时间】:2019-07-13 16:06:33 【问题描述】:

我正在查看有关如何使用 AWS EKS(Kubernetes 的弹性容器服务)使用现有 SSL 通配符证书运行我的 spring boot、mysql 支持的应用程序的分步教程,但无法找到完整的解决方案。

该应用程序是一个标准的 Spring boot 独立应用程序,由 MySQL 数据库支持,运行在 8080 端口上。我需要以高可用性、高冗余度运行它,包括需要处理大量写入和读取的 MySQL db .

我决定使用 EKS 托管的集群,将自定义 Docker 映像保存到 AWS 自己的 ECR 私有 Docker 存储库,以对抗 EKS 托管的 MySQL 集群。并使用 AWS 颁发的 SSL 证书通过 HTTPS 进行通信。以下是我的解决方案,但我很想知道如何以不同的方式完成它

【问题讨论】:

【参考方案1】:

这是一个分步教程。在上一步完成之前,请不要继续前进。

创建 EKS 集群

关注the standard tutorial创建EKS集群。不要执行第 4 步。完成后,您应该有一个正常工作的 EKS 集群,并且您必须能够使用 kubectl 实用程序与集群通信。从命令行执行时,您应该看到正在使用的工作节点和其他集群元素 kubectl get all --all-namespaces 命令

安装 MYSQL 集群

我使用helm 按照this tutorial 的步骤安装MySQL 集群。以下是步骤

安装 helm

因为我使用带有homebrew 的Macbook Pro,所以我使用了brew install kubernetes-helm 命令

部署 MySQL 集群

请注意,在 MySQL 集群Kubernetes (EKS) 集群 中,“集群”一词指的是 2 个不同的东西。基本上,您将集群安装到集群中,就像俄罗斯套娃娃娃一样,因此您的 MySQL 集群最终会在 EKS 集群节点上运行。

我使用this tutorial 的第二部分(忽略 kops 部分)来准备helm 图表并安装 MySQL 集群。引用 helm 配置:

$ kubectl create serviceaccount -n kube-system tiller

serviceaccount "tiller" created

$ kubectl create clusterrolebinding tiller-crule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller

clusterrolebinding.rbac.authorization.k8s.io "tiller-crule" created

$ helm init --service-account tiller --wait

$HELM_HOME has been configured at /home/presslabs/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!

$ helm repo add presslabs https://presslabs.github.io/charts

"presslabs" has been added to your repositories

$ helm install presslabs/mysql-operator --name mysql-operator

NAME:   mysql-operator
LAST DEPLOYED: Tue Aug 14 15:50:42 2018
NAMESPACE: default
STATUS: DEPLOYED

我完全按照上面引用的方式运行所有命令。

在创建集群之前,您需要一个包含 ROOT_PASSWORD 密钥的密钥。

创建一个名为 example-cluster-secret.yaml 的文件并将以下 YAML 代码复制到其中

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  # root password is required to be specified
  ROOT_PASSWORD: Zm9vYmFy

但是ROOT_PASSWORD 是什么?原来这是您计划与 MySQL root 用户一起使用的 base64 编码密码。假设你想要root/foobar(请不要实际使用foobar)。对密码进行编码的最简单方法是使用诸如https://www.base64encode.org/ 之类的网站之一,它将foobar 编码为Zm9vYmFy

准备好后执行kubectl apply -f example-cluster-secret.yaml,这将创建一个新的秘密

然后您需要创建一个名为example-cluster.yaml 的文件并将以下 YAML 代码复制到其中:

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  replicas: 2
  secretName: my-secret

注意secretName 与您刚刚创建的秘密名称的匹配方式。只要它在两个文件中都匹配,您就可以将其更改为更有意义的内容。现在运行 kubectl apply -f example-cluster.yaml 最终创建一个 MySQL 集群。测试它

$ kubectl get mysql
NAME        AGE
my-cluster  1m

请注意,我没有按照本文其余部分所述配置备份。您无需为数据库操作而执行此操作。但是如何访问您的数据库?此时mysql服务存在,但没有外部IP。就我而言,我什至不希望这样,只要我在同一个 EKS 集群上运行的应用程序可以访问它。

但是,您可以使用kubectl 端口转发从运行kubectl 的开发盒访问数据库。输入此命令:kubectl port-forward services/my-cluster-mysql 8806:3306。现在您可以使用用户root 和非编码密码(foobar)从127.0.0.1:8806 访问您的数据库。在单独的命令提示符中键入:mysql -u root -h 127.0.0.1 -P 8806 -p。有了这个,您还可以使用 MySQL Workbench 来管理您的数据库,只是不要忘记运行port-forward。当然,您也可以将 8806 更改为您选择的其他端口

将您的应用打包为 Docker 映像并部署

要将 Spring Boot 应用程序部署到 EKS 集群中,您需要将其打包到 Docker 映像中并将其部署到 Docker 存储库中。让我们从 Docker 映像开始。这个like this one有很多教程,但是步骤很简单:

将您生成的、自包含的 Spring Boot jar 文件放入一个目录,并在同一目录中创建一个具有此确切名称的文本文件:Dockerfile,并向其中添加以下内容:

FROM openjdk:8-jdk-alpine
MAINTAINER me@mydomain.com
LABEL name="My Awesome Docker Image" 
# Add spring boot jar
VOLUME /tmp
ADD myapp-0.1.8.jar app.jar
EXPOSE 8080
# Database settings (maybe different in your app)
ENV RDS_USERNAME="my_user"
ENV RDS_PASSWORD="foobar"
# Other options
ENV JAVA_OPTS="-Dverknow.pypath=/"
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

现在只需从同一文件夹运行 Docker 命令即可创建映像。当然,这需要在您的开发盒上安装 Docker 客户端。

$ docker build -t myapp:0.1.8 --force-rm=true --no-cache=true .

如果一切顺利,您应该会看到使用docker ps 命令列出的图像

部署到私有 ECR 存储库

将您的新映像部署到 ECR 存储库非常简单,而且 ECR 可以与 EKS 一起使用,开箱即用。登录 AWS 控制台并导航到 the ECR section。我发现这很令人困惑,显然您需要为每个图像创建一个存储库,但是当您单击“创建存储库”按钮时,将您的图像名称(例如 myapp)放入文本字​​段中。现在你需要为你的图片复制丑陋的 URL 并返回到命令提示符

标记并推送您的图片。我以假 URL 为例:901237695701.dkr.ecr.us-west-2.amazonaws.com 你需要从上一步复制你自己的

$ docker tag myapp:0.1.8 901237695701.dkr.ecr.us-west-2.amazonaws.com/myapp:latest
$ docker push 901237695701.dkr.ecr.us-west-2.amazonaws.com/myapp:latest

此时图像应显示在您创建的 ECR 存储库中

将您的应用部署到 EKS 集群

现在您需要为应用的 Docker 映像创建 Kubernetes 部署。创建一个myapp-deployment.yaml文件,内容如下

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  selector:
    matchLabels:
      app: myapp
  replicas: 2
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - image: 901237695701.dkr.ecr.us-west-2.amazonaws.com/myapp:latest
        name: myapp
        ports:
        - containerPort: 8080
          name: server
        env:
        # optional
        - name: RDS_HOSTNAME
          value: "10.100.98.196"
        - name: RDS_PORT
          value: "3306"
        - name: RDS_DB_NAME
          value: "mydb"
      restartPolicy: Always
status: 

请注意我是如何为 image 参数使用完整 URL 的。我还使用了 mysql 集群的私有 CLUSTER-IP,您可以使用 kubectl get svc my-cluster-mysql 命令获得它。这对于您的应用程序(包括任何环境名称)会有所不同,但您必须以某种方式将此信息提供给您的应用程序。然后在您的应用程序中,您可以在application.properties 文件中设置类似的内容:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://$RDS_HOSTNAME:$RDS_PORT/$RDS_DB_NAME?autoReconnect=true&zeroDateTimeBehavior=convertToNull
spring.datasource.username=$RDS_USERNAME
spring.datasource.password=$RDS_PASSWORD

保存myapp-deployment.yaml 后,您需要运行此命令

kubectl apply -f myapp-deployment.yaml

这会将您的应用部署到 EKS 集群中。这将在集群中创建 2 个 pod,您可以使用 kubectl get pods 命令查看它们

与其尝试直接访问其中一个 pod,我们还可以创建一个服务来放置应用程序 pod。使用此内容创建myapp-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  ports:
  - port: 443
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: myapp
  type: LoadBalancer

这就是魔法发生的地方!只需将端口设置为 443 并键入 LoadBalancer,系统就会创建一个 Classic Load Balancer 来放置您的应用程序。

顺便说一句,如果您不需要通过 HTTPS 运行您的应用程序,您可以将端口设置为 80,这样就完成了!

在您运行kubectl apply -f myapp-service.yaml 后,集群中的服务将被创建,如果您转到 AWS 控制台 EC2 部分的负载均衡器部分,您将看到为您创建了一个新的均衡器。您还可以运行kubectl get svc myapp-service 命令,该命令将为您提供EXTERNAL-IP 值,例如bl3a3e072346011e98cac0a1468f945b-8158249.us-west-2.elb.amazonaws.com。复制它,因为我们接下来需要使用它。

值得一提的是,如果您使用端口 80,那么只需将该 URL 粘贴到浏览器中即可显示您的应用

通过 HTTPS 访问您的应用

以下部分假设您拥有 AWS 颁发的 SSL 证书。如果您不这样做,请转到 AWS 控制台“证书管理器”并为您的域创建通配符证书

在您的负载均衡器可以工作之前,您需要访问AWS console -> EC2 -> Load Balancers -> My new balancer -> Listeners 并点击SSL Certificate 列中的“更改”链接。然后在弹出窗口中选择 AWS 颁发的 SSL 证书并保存。

转到 AWS 控制台中的 Route-53 部分并为您的域选择一个托管区域,例如 myapp.com.。然后单击“创建记录集”并创建一个CNAME - Canonical name 记录,其中Name 设置为您想要的任何别名,例如cluster.myapp.comValue 从上面设置为EXTERNAL-IP。在“保存记录集”后,转到浏览器并输入https://cluster.myapp.com。您应该会看到您的应用正在运行

【讨论】:

以上是关于在 AWS (EKS) 上运行 MySQL 集群支持、支持 HTTPS 的 Spring Boot 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

AWS EKS Cluster Autoscaler - 缩减策略

AWS EKS 集群自动扩展

在 AWS EKS 上部署 EMQX MQTT 集群

如何将 GitLab Operator 部署到 AWS EKS 集群?

在 AWS EKS 和 Istio Ingress 上使用 GRPC 的 SSL 提供 StatusCode.UNAVAILABLE

AWS EKS 添加IAM用户角色