首页 > 解决方案 > 从 GKE 连接到 AWS 数据库

问题描述

我无法将 Google Cloud Platform Kubernetes pod 连接到在 AWS 上运行的外部 MySQL。

这是我的部署文件(一些敏感部分替换为***):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: watches-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: watches-v1
  template:
    metadata:
      labels:
        app: watches-v1
    spec:
      containers:
      - name: watches-v1
        image: silasberger/watches:1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
        env:
        - name: MYSQL_HOST
          value: "***.eu-west-1.rds.amazonaws.com"
        - name: MYSQL_DB
          value: "***"
        - name: MYSQL_USER
          value: "***"
        - name: MYSQL_PASS
          value: "***"
        - name: API_USER
          value: "***"
        - name: API_PASS
          value: "***"

这是我构建并推送到 Dockerhub 的 Dockerfile watches:1.0

FROM node:8

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

ENV MICROSERVICE="watches"
ENV WATCHES_API_VERSION="1"

CMD [ "npm", "start" ]

以下事情有效:

但是,一旦我在 Kubernetes 集群中应用部署,Pod 就无法连接到 AWS 数据库。应用程序启动,我可以访问 swagger 页面,但是当我运行kubectl logs <pod-name>命令时,我总是得到这个错误:

Unable to connect to the database: { SequelizeConnectionError: connect ETIMEDOUT
    at Utils.Promise.tap.then.catch.err (/usr/src/app/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:149:19)
    at tryCatcher (/usr/src/app/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/usr/src/app/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/usr/src/app/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/usr/src/app/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/usr/src/app/node_modules/bluebird/js/release/promise.js:690:18)
    at _drainQueueStep (/usr/src/app/node_modules/bluebird/js/release/async.js:138:12)
    at _drainQueue (/usr/src/app/node_modules/bluebird/js/release/async.js:131:9)
    at Async._drainQueues (/usr/src/app/node_modules/bluebird/js/release/async.js:147:5)
    at Immediate.Async.drainQueues (/usr/src/app/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:810:20)
    at tryOnImmediate (timers.js:768:5)
    at processImmediate [as _immediateCallback] (timers.js:745:5)
  name: 'SequelizeConnectionError',
  parent: 
   { Error: connect ETIMEDOUT
    at Connection._handleTimeoutError (/usr/src/app/node_modules/mysql2/lib/connection.js:192:13)
    at ontimeout (timers.js:498:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:290:5)
     errorno: 'ETIMEDOUT',
     code: 'ETIMEDOUT',
     syscall: 'connect',
     fatal: true },
  original: 
   { Error: connect ETIMEDOUT
    at Connection._handleTimeoutError (/usr/src/app/node_modules/mysql2/lib/connection.js:192:13)
    at ontimeout (timers.js:498:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:290:5)
     errorno: 'ETIMEDOUT',
     code: 'ETIMEDOUT',
     syscall: 'connect',
     fatal: true } }

它选择了正确的主机、数据库名称和凭据(如此处未显示的日志的前一部分所示),但显然无法连接到它。如您所见,该应用程序是用 Node.js 编写的并使用 Sequelize。

到目前为止,我所做的所有研究都指向防火墙问题,因此我在 Google Cloud Platform 上为该项目设置了以下 VPC 规则:

$ gcloud compute firewall-rules describe allow-all-outbound
allowed:
- IPProtocol: all
creationTimestamp: '2018-11-14T02:51:20.808-08:00'
description: Allow all inbound connections
destinationRanges:
- 0.0.0.0/0
direction: EGRESS
disabled: false
id: '7178441953737326791'
kind: compute#firewall
name: allow-mysql-outbound
network: https://www.googleapis.com/compute/v1/projects/adept-vine-222109/global/networks/default
priority: 1000
selfLink: https://www.googleapis.com/compute/v1/projects/adept-vine-222109/global/firewalls/allow-mysql-outbound

由于这并没有改变任何东西,我也尝试再次添加相同的规则,使用direction INGRESS,但这也不起作用(正如我所料)。

我对谷歌云平台和 Kubernetes 完全陌生,所以也许这只是一个愚蠢的错误,但我真的不知道如何让它工作。

标签: mysqlamazon-web-serviceskubernetesgoogle-cloud-platformsequelize.js

解决方案


事实证明,问题出在 AWS 方面。感谢雅各布汤姆林森的建议。

虽然为 AWS MySQL 实例激活了公共可访问性,但它显然不允许从所有来源进行访问。我不确定为什么它可以在我的本地机器上工作,但无论如何。

我能够通过在 AWS 中添加一个安全组来解决它,该安全组允许所有端口上的入站流量以及源 0.0.0.0/0 的所有协议。然后我将此安全组与我的 MySQL 实例相关联(转到实例,单击修改,转到网络和安全设置,选择新创建的组,保存更改)。我仍然需要从安全角度调整这条规则,但至少现在一切正常。


推荐阅读