首页 > 解决方案 > 在 AWS (EKS) 上运行 MySQL 集群支持、支持 HTTPS 的 Spring Boot 应用程序

问题描述

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

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

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

标签: spring-bootdockerkubernetesamazon-eks

解决方案


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

创建 EKS 集群

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

安装 MYSQL 集群

我曾经按照本教程helm中的步骤安装 MySQL 集群。以下是步骤

安装 helm

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

部署 MySQL 集群

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

我使用本教程的第二部分(忽略 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/之类的网站之一foobarZm9vYmFy

准备就绪时执行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:3306127.0.0.1:8806现在您可以使用用户root和非编码密码 ( foobar)访问您的数据库。将此输入单独的命令提示符:mysql -u root -h 127.0.0.1 -P 8806 -p. 有了这个,您还可以使用 MySQL Workbench 来管理您的数据库,只是不要忘记运行port-forward. 当然,您可以将 8806 更改为您选择的其他端口

将您的应用程序打包为 Docker 映像并进行部署

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

将您生成的、自包含的 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 控制台并导航到ECR 部分。我发现这很令人困惑,显然您需要为每个图像创建一个存储库,但是当您单击“创建存储库”按钮时,将您的图像名称(例如myapp)放入文本字​​段中。现在你需要为你的图片复制丑陋的 URL 并返回到命令提示符

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

$ 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。您应该看到您的应用正在运行


推荐阅读