DV360 API를 호출해야 하는 FastAPI 기반 크롤러를 Cloud Run Job으로 실행하면서, 다음과 같은 문제가 발생했다.
결국, Cloud Run 환경에서 고정 IP로 외부 API에 접근해야 했고, 그 과정에서 다양한 시행착오와 구조적 설정이 필요했다.
Cloud Run Job에서 외부 API에 접근할 때 고정 IP를 사용하고, 이 IP를 화이트리스트에 등록해 접근을 허용하는 구조 만들기.
[Cloud Run Job] ➔ [VPC Connector] ➔ [Serverless VPC Access] ➔ [Cloud NAT] ➔ [고정 External IP] ➔ [External API Endpoint]
Cloud Run Job으로 DV360 API에 요청을 보냈는데, 403 에러 발생. 로그를 통해 보니 API 쪽 서버에서 접속 시도 자체를 차단.
Google Cloud NAT가 없을 경우, Cloud Run은 매번 다른 IP로 외부 호출을 시도.
curl ifconfig.me를 통해 내부적으로 확인했을 때 IP가 매번 달랐음.no external access from VPC subnetgcloud compute addresses create fixed-egress-ip \
--project=my-project-id \
--region=asia-northeast3
gcloud compute routers create nat-router \
--network=default \
--region=asia-northeast3
gcloud compute routers nats create nat-config \
--router=nat-router \
--region=asia-northeast3 \
--nat-external-ip-pool=fixed-egress-ip \
--nat-custom-subnet-ip-ranges=default \
--enable-logging
gcloud compute networks vpc-access connectors create run-vpc-connector \
--network default \
--region asia-northeast3 \
--range 10.8.0.0/28
gcloud run jobs update my-crawler-job \
--vpc-connector=run-vpc-connector \
--vpc-egress=all-traffic
이제 Cloud Run Job의 모든 외부 트래픽은 fixed-egress-ip로 나간다.
Cloud Run Job은 다음과 같은 환경변수로 호출되며 실행된다.
os.environ["PLAN_ID"] = "12345"
os.environ["PLATFORMS"] = '["dv360"]'
os.environ["OPTIONS_JSON"] = '{"dv360": {"budget": 10000000, "location": "KR", ... }}'
그리고 Python에서는 이를 다음과 같이 파싱:
plan_id = int(os.environ["PLAN_ID"]) # ❌ 이 부분에서 "UNKNOWN" 들어오면 에러 발생
String planId = requestBody.containsKey("plan_id")
? requestBody.get("plan_id").toString()
: String.valueOf(saveId); // saveId = Long
saveId를 fallback으로 지정하여 항상 Long 사용--vpc-connector와 --vpc-egress=all-traffic을 꼭 설정해야 NAT가 적용됨nat-external-ip-pool 지정 누락 → ephemeral IP 사용--nat-external-ip-pool=fixed-egress-ip 명시Cloud Run에서 고정 IP를 통해 외부 API 호출하는 구조는 생각보다 복잡하지만, 한번 구성해두면 확장성과 관리성이 뛰어나다. 특히 다음과 같은 상황에서 매우 유용하다.
Cloud Run Job + VPC Connector + Cloud NAT의 조합은 이런 요구사항을 충족할 수 있는 강력한 아키텍처이다.