如何通过 TCP 通过 MySQL 代理 Docker 容器连接到云 SQL(第 2 代)
How to connect to Cloud SQL (2nd Generation) via MySQL Proxy Docker Container over TCP
运行 Mac OS X,我一直在尝试使用 these directions 通过代理连接到云 SQL 实例。安装 MySQL 客户端、gce-proxy 容器并在 Google Cloud Platform 中创建服务帐户后,您可以开始 运行 文档中指定的这两个命令:
docker run -d -v /cloudsql:/cloudsql \
-v [LOCAL_CERTIFICATE_FILE_PATH]:[LOCAL_CERTIFICATE_FILE_PATH] \
b.gcr.io/cloudsql-docker/gce-proxy /cloud_sql_proxy \
-instances=[INSTANCE_CONNECTION_NAME]=tcp:3306 -credential_file=[CLOUD_KEY_FILE_PATH]
mysql -h127.0.0.1 -uroot -p
首先,我不明白这应该如何工作,因为容器没有公开端口。毫不奇怪,当我尝试连接时,我从 MySQL 客户端收到以下错误:
ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (61)
但是如果我通过在docker run
命令中添加-p 3306:3306
来暴露端口,我仍然无法连接。相反,我从 MySQL 客户端收到以下错误:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
我已经通过 that documentation 在我的 docker 主机上成功连接到代理 运行 cloud_sql_proxy
,所以我对我的凭据文件和我的 mysql 客户端配置正确。容器的日志没有说明尝试过任何连接。我可以通过 docker 连接到普通的 mysql 容器。我在这里错过了什么?
文档中确实有些遗漏。
1) 正如您所指出的,您需要从容器中公开端口。您需要通过指定 -p 127.0.0.1:3306:3306
来确保只将它公开给本地机器。
2) 然后当运行容器时,你会想要通过指定-instances=[INSTANCE_CONNECTION_NAME]=tcp:0.0.0.0:3306
暴露容器外的端口
我尝试了@Vadim 的建议,基本上是这样的:
docker run -d -v /cloudsql:/cloudsql \
-p 127.0.0.1:3306:3306 \
-v [LOCAL_CERTIFICATE_FILE_PATH]:[LOCAL_CERTIFICATE_FILE_PATH] \
b.gcr.io/cloudsql-docker/gce-proxy /cloud_sql_proxy \
-instances=[INSTANCE_CONNECTION_NAME]=tcp:0.0.0.0:3306 -credential_file=[CLOUD_KEY_FILE_PATH]
我仍然无法建立连接,因为我仍然收到此错误:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
但是,docker 容器的日志显示了一个连接,如下所示:
2016/10/16 07:52:32 New connection for "[INSTANCE_CONNECTION_NAME]"
2016/10/16 07:52:32 couldn't connect to "[INSTANCE_CONNECTION_NAME]": Post https://www.googleapis.com/sql/v1beta4/projects/[PROJECT_NAME]/instances/[CLOUD_SQL_INSTANCE_NAME]/createEphemeral?alt=json: oauth2: cannot fetch token: Post https://accounts.google.com/o/oauth2/token: x509: failed to load system roots and no roots provided
现在看来它正在获取流量,但它找不到 SSL 容器的证书。我使用了 OpenSSL's cert.pem
export of my certificates and mounted it to the same location in the docker container. It makes sense that an arbitrary mapping of [LOCAL_CERTIFICATE_FILE_PATH]:[LOCAL_CERTIFICATE_FILE_PATH]
wasn't helping the proxy figure out where the certificates were. So I used a clue from this Kubernetes setup guide 并将安装的卷更改为 -v [LOCAL_CERTIFICATE_FILE_PATH]:/etc/ssl/certs
。幸运的是,这奏效了。
TL;DR - 这是通过 TCP 将 Docker 容器发送到 运行 的最终语法:
docker run -d \
-p 127.0.0.1:3306:3306 \
-v [SERVICE_ACCOUNT_PRIVATE_KEY_DIRECTORY]:[SERVICE_ACCOUNT_PRIVATE_KEY_DIRECTORY] \
-v [LOCAL_CERTIFICATE_DIRECTORY]:/etc/ssl/certs \
b.gcr.io/cloudsql-docker/gce-proxy /cloud_sql_proxy \
-instances=[INSTANCE_CONNECTION_NAME]=tcp:0.0.0.0:3306 \
-credential_file=[SERVICE_ACCOUNT_PRIVATE_KEY_JSON_FILE]
我能够通过 docker-compose 弄清楚如何在本地 docker 环境中使用 cloudsql-proxy。您需要提取 Cloud SQL 实例凭证并准备好它们。我将它们作为 credentials.json
保存在我的项目根目录中,并将其添加到项目中的 .gitignore
。
我发现的关键部分是在 GCP 实例 ID 后使用 =tcp:0.0.0.0:5432
,以便可以转发端口。然后,在您的应用程序中,使用 cloudsql-proxy
而不是 localhost
作为主机名。确保您的其余数据库凭据在您的应用程序机密中有效,以便它可以通过 cloudsql-proxy 容器提供的本地代理进行连接。
注意:请记住,我正在编写一个 tomcat java 应用程序,我的 docker-compose.yml
反映了这一点。
docker-compose.yml:
version: '3'
services:
cloudsql-proxy:
container_name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.11
command: /cloud_sql_proxy --dir=/cloudsql -instances=<YOUR INSTANCE ID HERE>=tcp:0.0.0.0:5432 -credential_file=/secrets/cloudsql/credentials.json
ports:
- 5432:5432
volumes:
- ./credentials.json:/secrets/cloudsql/credentials.json
restart: always
tomcatapp-api:
container_name: tomcatapp-api
build: .
volumes:
- ./build/libs:/usr/local/tomcat/webapps
ports:
- 8080:8080
- 8000:8000
env_file:
- ./secrets.env
restart: always
运行 Mac OS X,我一直在尝试使用 these directions 通过代理连接到云 SQL 实例。安装 MySQL 客户端、gce-proxy 容器并在 Google Cloud Platform 中创建服务帐户后,您可以开始 运行 文档中指定的这两个命令:
docker run -d -v /cloudsql:/cloudsql \
-v [LOCAL_CERTIFICATE_FILE_PATH]:[LOCAL_CERTIFICATE_FILE_PATH] \
b.gcr.io/cloudsql-docker/gce-proxy /cloud_sql_proxy \
-instances=[INSTANCE_CONNECTION_NAME]=tcp:3306 -credential_file=[CLOUD_KEY_FILE_PATH]
mysql -h127.0.0.1 -uroot -p
首先,我不明白这应该如何工作,因为容器没有公开端口。毫不奇怪,当我尝试连接时,我从 MySQL 客户端收到以下错误:
ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (61)
但是如果我通过在docker run
命令中添加-p 3306:3306
来暴露端口,我仍然无法连接。相反,我从 MySQL 客户端收到以下错误:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
我已经通过 that documentation 在我的 docker 主机上成功连接到代理 运行 cloud_sql_proxy
,所以我对我的凭据文件和我的 mysql 客户端配置正确。容器的日志没有说明尝试过任何连接。我可以通过 docker 连接到普通的 mysql 容器。我在这里错过了什么?
文档中确实有些遗漏。
1) 正如您所指出的,您需要从容器中公开端口。您需要通过指定 -p 127.0.0.1:3306:3306
来确保只将它公开给本地机器。
2) 然后当运行容器时,你会想要通过指定-instances=[INSTANCE_CONNECTION_NAME]=tcp:0.0.0.0:3306
我尝试了@Vadim 的建议,基本上是这样的:
docker run -d -v /cloudsql:/cloudsql \
-p 127.0.0.1:3306:3306 \
-v [LOCAL_CERTIFICATE_FILE_PATH]:[LOCAL_CERTIFICATE_FILE_PATH] \
b.gcr.io/cloudsql-docker/gce-proxy /cloud_sql_proxy \
-instances=[INSTANCE_CONNECTION_NAME]=tcp:0.0.0.0:3306 -credential_file=[CLOUD_KEY_FILE_PATH]
我仍然无法建立连接,因为我仍然收到此错误:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
但是,docker 容器的日志显示了一个连接,如下所示:
2016/10/16 07:52:32 New connection for "[INSTANCE_CONNECTION_NAME]"
2016/10/16 07:52:32 couldn't connect to "[INSTANCE_CONNECTION_NAME]": Post https://www.googleapis.com/sql/v1beta4/projects/[PROJECT_NAME]/instances/[CLOUD_SQL_INSTANCE_NAME]/createEphemeral?alt=json: oauth2: cannot fetch token: Post https://accounts.google.com/o/oauth2/token: x509: failed to load system roots and no roots provided
现在看来它正在获取流量,但它找不到 SSL 容器的证书。我使用了 OpenSSL's cert.pem
export of my certificates and mounted it to the same location in the docker container. It makes sense that an arbitrary mapping of [LOCAL_CERTIFICATE_FILE_PATH]:[LOCAL_CERTIFICATE_FILE_PATH]
wasn't helping the proxy figure out where the certificates were. So I used a clue from this Kubernetes setup guide 并将安装的卷更改为 -v [LOCAL_CERTIFICATE_FILE_PATH]:/etc/ssl/certs
。幸运的是,这奏效了。
TL;DR - 这是通过 TCP 将 Docker 容器发送到 运行 的最终语法:
docker run -d \
-p 127.0.0.1:3306:3306 \
-v [SERVICE_ACCOUNT_PRIVATE_KEY_DIRECTORY]:[SERVICE_ACCOUNT_PRIVATE_KEY_DIRECTORY] \
-v [LOCAL_CERTIFICATE_DIRECTORY]:/etc/ssl/certs \
b.gcr.io/cloudsql-docker/gce-proxy /cloud_sql_proxy \
-instances=[INSTANCE_CONNECTION_NAME]=tcp:0.0.0.0:3306 \
-credential_file=[SERVICE_ACCOUNT_PRIVATE_KEY_JSON_FILE]
我能够通过 docker-compose 弄清楚如何在本地 docker 环境中使用 cloudsql-proxy。您需要提取 Cloud SQL 实例凭证并准备好它们。我将它们作为 credentials.json
保存在我的项目根目录中,并将其添加到项目中的 .gitignore
。
我发现的关键部分是在 GCP 实例 ID 后使用 =tcp:0.0.0.0:5432
,以便可以转发端口。然后,在您的应用程序中,使用 cloudsql-proxy
而不是 localhost
作为主机名。确保您的其余数据库凭据在您的应用程序机密中有效,以便它可以通过 cloudsql-proxy 容器提供的本地代理进行连接。
注意:请记住,我正在编写一个 tomcat java 应用程序,我的 docker-compose.yml
反映了这一点。
docker-compose.yml:
version: '3'
services:
cloudsql-proxy:
container_name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.11
command: /cloud_sql_proxy --dir=/cloudsql -instances=<YOUR INSTANCE ID HERE>=tcp:0.0.0.0:5432 -credential_file=/secrets/cloudsql/credentials.json
ports:
- 5432:5432
volumes:
- ./credentials.json:/secrets/cloudsql/credentials.json
restart: always
tomcatapp-api:
container_name: tomcatapp-api
build: .
volumes:
- ./build/libs:/usr/local/tomcat/webapps
ports:
- 8080:8080
- 8000:8000
env_file:
- ./secrets.env
restart: always