[GCP] 상품 데이터 S3 업로드 자동화 트러블슈팅 (with Cloud Functions)

yeahcold·2025년 3월 31일
0

Data Engineering

목록 보기
12/20

💡 프로젝트 개요

제품 JSON 데이터를 가공하여 필터링 → 변환 → 네이버 쇼핑 API 이용해 TSV 포맷으로 저장 → S3 업로드까지 자동화하는 파이프라인을 구축했습니다.
파이썬으로 작성하였고, Cloud Functions 에 배포하여 매일 S3 Bucket에 업로드하는 걸 목표로 진행하였습니다.


1️⃣ Excel에서 CSV 한글 깨짐 (인코딩 이슈)

❌ 문제

ikea_raw.csv 파일을 S3에 업로드했더니 브라우저에서는 잘 열리지만,
Excel에서 열었을 때 인코딩 깨짐 현상이 발생하고 경고 문구가 뜸.

🔍 원인

  • Python 기본 csv 저장 시 UTF-8 인코딩은 Excel이 잘 인식하지 못함
  • 특히 BOM(Byte Order Mark) 없이 저장하면 한글이 깨질 수 있음

✅ 해결

  • 처음엔 utf-8-sig로 인코딩해 저장해서 해결했지만,
  • 최종적으로 CSV 대신 TSV(Tab-separated values) 형식으로 전환
  • Excel에서 열 때도 깨지지 않고, 구분자 충돌도 없음
with open("raw.tsv", "w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=..., delimiter="\t")

2️⃣ 네이버 카테고리 자동 매핑 실패

❌ 문제

네이버 카테고리 매핑 시 일부 제품은 카테고리 경로가 매핑되지 않아
기본 카테고리 ID로 처리되는 비율이 많았음

🔍 원인

  • 스프레드시트의 카테고리명과 API 결과의 카테고리명이 형식 차이로 매칭이 되지 않음
  • 예: 주방/조리도구>후라이팬/웍 vs 주방/조리도구>후라이팬/웍

✅ 해결

  • 문자열을 정규화하는 normalize_category_string() 함수를 별도로 구현
s = s.replace("/", "/").replace(">", ">").replace(":", ":").replace("\u3000", "")
s = s.replace("\u00a0", "").replace(" ", "").lower()
  • 스프레드시트 기준으로 정규화된 키와 원본 키 둘 다 등록

3️⃣ Cloud Functions에서 AWS S3 인증 실패

❌ 문제

로컬에서는 정상적으로 업로드되던 boto3 코드가 Cloud Functions에선 Access Denied 오류

🔍 원인

  • Cloud Functions 환경에 AWS 자격증명(AWS_ACCESS_KEY, AWS_SECRET_KEY)이 누락됨
  • 또는 --set-env-vars 플래그로 환경변수를 잘못 전달함

✅ 해결

  • .env 파일에 키를 저장하고, dotenv로 로컬과 공통 처리
  • GCP 배포 시 아래처럼 명시적으로 환경변수 전달
gcloud functions deploy export-ikea-products \
  --runtime python310 \
  --trigger-http \
  --entry-point export_ikea_products \
  --source . \
  --allow-unauthenticated \
  --set-env-vars AWS_ACCESS_KEY=xxx,AWS_SECRET_KEY=xxx,AWS_REGION=ap-northeast-2

4️⃣ CloudFront 캐시로 인해 TSV 변경이 반영되지 않음

❌ 문제

S3에는 최신 TSV가 올라갔는데,
CloudFront URL에서는 여전히 이전 파일이 보임

🔍 원인

  • S3 버킷에 연결된 CloudFront 배포가 캐싱된 파일을 계속 제공
  • CloudFront 캐시 무효화가 자동으로 되지 않음

✅ 해결

  • boto3를 사용해 CloudFront 캐시 무효화 자동화 함수 추가
client.create_invalidation(
    DistributionId=DISTRIBUTION_ID,
    InvalidationBatch={
        "Paths": {"Quantity": 1, "Items": ["/ikea_naver_ep.tsv"]},
        "CallerReference": str(time.time())
    }
)
  • S3 업로드 후 CloudFront 무효화까지 포함하여 운영
profile
Software Engineer

0개의 댓글