У меня проблемы с подключением модуля облачной платформы Google Kubernetes к внешнему MySQL, работающему на AWS.
Вот мой файл развертывания (некоторые важные части заменены на ***
):
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: "***"
Это Dockerfile, который я создаю и отправляю в Dockerhub как 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" ]
Следующие вещи работают:
mysql
Однако, как только я применяю развертывание в моем кластере Kubernetes, модули не могут подключиться к базе данных AWS. Приложение запускается, я могу получить доступ к странице kubectl logs <pod-name>
, но когда я запускаю команду 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.
Все исследования, которые я до сих пор проводил, указывали на проблему с брандмауэром, поэтому я установил следующее правило VPC для облачной платформы Google для этого проекта:
$ 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
, но это тоже не сработало (как я и ожидал).
Я совершенно новичок в облачной платформе Google и в Kubernetes, так что, возможно, это просто глупая ошибка, но я действительно не знаю, как заставить ее работать.
Как оказалось, проблема была на стороне AWS. Спасибо Джейкобу Томлинсону за предложение.
Хотя Public Accessibility был активирован для экземпляра AWS MySQL, он явно не разрешал доступ из всех источников. Я не уверен, почему это работало с моей локальной машины, но все равно.
Я смог решить эту проблему, добавив группу безопасности в AWS, которая разрешает входящий трафик на все порты и со всеми протоколами для источника 0.0.0.0/0. Затем я связал эту группу безопасности с моим экземпляром MySQL (перейдите к экземпляру, нажмите "Изменить", перейдите в "Настройки сети и безопасности", выберите вновь созданную группу, сохраните изменения). Мне все еще нужно настроить это правило с точки зрения безопасности, но, по крайней мере, теперь все работает.