Google Cloud Function对接MongoDB VM及多服务跨端通信方案咨询
所有资源统一放在同一个Google Cloud VPC下走内网通信,既不需要暴露公网降低安全风险,也能获得更低的通信延迟。
1.1 配置MongoDB允许内网访问
你当前的MongoDB仅绑定了本地回环地址127.0.0.1,只能在VM本地访问,需要修改配置放开内网访问权限:
- 编辑MongoDB配置文件:
sudo nano /etc/mongod.conf - 找到
net配置段,修改bindIp参数:
net: port: 27017 bindIp: 127.0.0.1,10.156.0.5
这里加上你的MongoDB VM的内网IP 10.156.0.5,允许VPC内网的请求访问MongoDB服务。
- 保存退出后重启MongoDB生效:
sudo systemctl restart mongod
1.2 开启MongoDB身份验证(必做)
你当前的MongoDB没有开启访问控制,任何能访问端口的主体都可以读写、删除全部数据,必须配置权限:
- 进入Mongo shell:
mongo - 先切换到admin库创建超级管理员,再给爬虫业务库创建单独的读写用户:
use admin db.createUser( { user: "mongoAdmin", pwd: "自定义强密码", roles: [ { role: "root", db: "admin" } ] } ) // 示例中业务库名为immo_scrape,可根据自己的需求修改 use immo_scrape db.createUser( { user: "immo_writer", pwd: "自定义业务账号密码", roles: [ { role: "readWrite", db: "immo_scrape" } ] } )
- 退出Mongo shell,再次编辑
/etc/mongod.conf,找到security段开启身份验证:
security: authorization: enabled
- 重启MongoDB生效:
sudo systemctl restart mongod
1.3 配置VPC防火墙规则
在Google Cloud控制台的「VPC网络-防火墙」页面添加两条规则:
- 规则1:允许VPC内网访问MongoDB端口
- 目标:选择「指定目标标签」,给你的MongoDB VM打上
mongodb-server的标签后填入 - 来源IPv4范围:
10.0.0.0/8(覆盖VPC内所有VM、Serverless连接器的内网地址) - 协议和端口:选择TCP,填入
27017
- 目标:选择「指定目标标签」,给你的MongoDB VM打上
- 规则2:如果后续有自定义Python服务需要通信,按需放开对应端口即可,比如自定义API用5000端口就添加TCP 5000的放行规则。
2.1 创建VPC连接器
Cloud Function默认运行在Google托管的Serverless网络环境中,不在你的VPC内,需要创建VPC连接器打通网络:
- 打开Google Cloud控制台的「Serverless VPC访问」页面
- 点击创建连接器,选择和你的MongoDB VM相同的VPC、相同的区域
- IP范围分配
10.8.0.0/28即可,吞吐量选择最小的100Mbps就能满足爬虫需求,等待创建完成。
2.2 部署Cloud Function绑定VPC连接器
部署你的Python爬虫函数时,在「运行时、构建、连接设置」的「连接」标签页,选择刚才创建的VPC连接器,路由选择「所有流量通过VPC连接器路由」即可。
2.3 Python插入MongoDB代码示例
首先在Cloud Function的requirements.txt里添加兼容Python3.5的pymongo依赖:
pymongo==3.12.3
函数逻辑示例:
import pymongo from pymongo import MongoClient def scrape_immo(request): # 这里替换为你自己的爬虫逻辑,获取抓取到的房源数据 house_data = { "source_url": "https://www.immobilienscout24.de/expose/xxx", "price": 329000, "area": 89.5, "address": "柏林米特区某街道" } # 连接MongoDB,替换为你自己的业务账号密码、库名 client = MongoClient("mongodb://immo_writer:你的业务密码@10.156.0.5:27017/immo_scrape") db = client["immo_scrape"] collection = db["houses"] # 插入数据 collection.insert_one(house_data) return "存储完成", 200
只要VM都部署在同一个VPC下,不需要额外复杂配置:
- 直接用对方VM的内网IP+对应服务端口访问即可,比如VM A要访问VM B上的Python API服务,B的内网IP是
10.156.0.6,API端口是5000,就直接请求http://10.156.0.6:5000/接口路径 - 如果嫌记IP麻烦,可以在Google Cloud的「VPC网络-云DNS」里创建私有区域,给VM配置内网域名,比如
mongodb.internal指向10.156.0.5,后续直接用域名访问即可。
两种方案可选,爬虫拆分场景推荐第二种:
4.1 直接HTTP调用
如果你的函数都是HTTP触发的,直接调用目标函数的触发URL即可,如需做身份验证避免外部非法调用,可以在请求头里加Google ID令牌,示例代码:
import urllib.request import google.auth.transport.requests import google.oauth2.id_token def call_another_func(request): target_url = "目标Cloud Function的触发URL" # 生成身份验证令牌 auth_req = google.auth.transport.requests.Request() id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_url) # 发送请求 req = urllib.request.Request(target_url) req.add_header("Authorization", f"Bearer {id_token}") response = urllib.request.urlopen(req) return response.read()
记得在目标函数的权限设置里,给当前函数的服务账户授予「Cloud Functions调用者」权限。
4.2 Pub/Sub异步触发(推荐)
非常适合爬虫拆分的解耦场景,比如拆分后流程为:
- 函数A:负责抓取房源列表页,把每个房源的详情URL推送到Pub/Sub的
immo_detail_topic主题 - 函数B:绑定
immo_detail_topic作为触发器,收到消息后自动执行,抓取对应房源的详情页存入MongoDB
这种方案不会因为短时间内请求量太大导致函数调用失败,消息会自动缓存重试,稳定性更高。
内容的提问来源于stack exchange,提问作者user14361382

