在 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.com
和Value
从上面设置为EXTERNAL-IP。在“保存记录集”后,转到浏览器并输入https://cluster.myapp.com。您应该会看到您的应用正在运行
【讨论】:
以上是关于在 AWS (EKS) 上运行 MySQL 集群支持、支持 HTTPS 的 Spring Boot 应用程序的主要内容,如果未能解决你的问题,请参考以下文章
AWS EKS Cluster Autoscaler - 缩减策略
如何将 GitLab Operator 部署到 AWS EKS 集群?
在 AWS EKS 和 Istio Ingress 上使用 GRPC 的 SSL 提供 StatusCode.UNAVAILABLE