Cloud Functions로 작은 자동화 만들기
이 글은 「GCP 기초」 연재의 일곱 번째 글이다. 앞의 두 편에서 파일과 데이터를 둘 곳을 만들었으니 이제 일을 시키는 코드를 올린다. 서버를 준비하고 웹 서버를 띄우는 과정 없이, 함수 하나만 올려 두면 필요할 때 알아서 실행되는 방식이다. 이 글에서는 파이썬 함수 하나를 실제로 배포해 보고, 진입점과 환경 변수, 로그 확인, 콜드 스타트와 요금 감각까지 한 바퀴 돈다.
이름부터 정리하고 가자
검색하면 Cloud Functions, Cloud Functions 2세대, Cloud Run functions가 뒤섞여 나온다. 정리하면 이렇다. 구글은 Cloud Functions를 Cloud Run functions로 이름을 바꿨고, 기존 2세대가 지금의 Cloud Run functions, 기존 1세대가 Cloud Run functions(1세대)다. 핵심은 2세대 함수의 실체가 Cloud Run 서비스라는 점이다. 그래서 콘솔에서도 2세대 함수는 Cloud Run 화면에서 관리하고, 1세대만 예전 함수 화면에 남아 있다.
명령어는 아직 둘 다 살아 있다. gcloud functions deploy도 그대로 쓸 수 있고, 소스에서 바로 올리는 gcloud run deploy 방식도 공식 문서에 있다. 새로 시작한다면 2세대를 쓰면 된다.
트리거 — 함수를 누가 부르나
함수를 만들 때 반드시 정해야 하는 것이 트리거다. HTTP 트리거는 주소 하나가 생기고, 그 주소를 부르면 실행돼 응답을 돌려준다. 웹훅이나 간단한 API에 쓴다. 이벤트 트리거는 주소가 없고, 정해 둔 사건이 일어나면 자동으로 실행된다. Pub/Sub 주제에 메시지가 들어오거나 버킷에 파일이 올라오는 것 같은 일이다. 이쪽은 부르는 쪽이 응답을 기다리지 않으므로 결과를 로그로 확인해야 한다.
최소 예제 — 파일 두 개면 된다
함수 배포에 필요한 것은 폴더 하나와 그 안의 파일 두 개다. 코드가 든 main.py, 그리고 쓸 라이브러리를 적은 requirements.txt다.
# main.py
import functions_framework
@functions_framework.http
def hello(request):
name = request.args.get("name", "world")
return f"hello, {name}"
# requirements.txt
functions-framework==3.*
functions_framework는 구글이 만든 얇은 껍데기다. 데코레이터를 붙인 함수를 웹 요청과 연결해 주는 역할만 한다. 덕분에 같은 코드를 로컬에서도 그대로 돌려 볼 수 있다.
gcloud functions deploy hello-fn \
--gen2 \
--region=asia-northeast3 \
--runtime=python312 \
--source=. \
--entry-point=hello \
--trigger-http \
--allow-unauthenticated \
--set-env-vars=GREETING=hi
런타임 이름은 계속 갱신되니 배포 전에 공식 문서에서 확인하는 편이 좋다. --gen2는 생략하면 상황에 따라 세대가 달라질 수 있으니 새로 만들 때는 명시하는 게 안전하다.
콘솔로 만들 때 — 화면에서 정해야 하는 것들
명령어가 부담스럽다면 콘솔에서도 만들 수 있다. Cloud Run의 서비스 만들기 화면에서 "인라인 편집기를 사용하여 함수 만들기"를 고르면 브라우저 안에서 코드까지 작성해 배포할 수 있다. 파일을 따로 준비하지 않아도 된다.
다만 한 화면에 정할 것이 꽤 많다. 처음 보면 어디까지 건드려야 할지 막막하니, 항목별로 무엇을 고르면 되는지 정리해 둔다.
| 항목 | 무엇인가 | 처음엔 이렇게 |
|---|---|---|
| 소스 선택 | 컨테이너 이미지 · 저장소 연동 · 인라인 편집기 셋 중 하나 | 인라인 편집기 |
| 서비스 이름 | 함수 이름이자 주소의 일부. 나중에 변경 불가 | 용도를 알아볼 수 있게 |
| 리전 | 실행될 지역. 이것도 나중에 변경 불가 | 가까운 곳 또는 무료 대상 리전 |
| 엔드포인트 URL | 이름과 리전으로 자동 생성된다 | 건드릴 것 없음 |
| 런타임 | 언어와 버전 | 쓰는 언어의 최신 버전 |
| 트리거 | 비워 두면 HTTP 트리거가 된다 | 비워 둠 |
| 인증 | 공개 액세스 허용 · 인증 필요 | 연습이면 공개, 실제면 인증 필요 |
| 결제 | 요청 기반 · 인스턴스 기반 | 요청 기반 |
| 인그레스 | 내부만 · 전체 공개 | 전체 |
| 서비스 계정 | 함수가 쓸 신원. 보안 탭에 있다 | 기본값으로 시작 |
이 중 서비스 이름과 리전은 만든 뒤에 바꿀 수 없다. 화면 맨 위에도 그렇게 적혀 있다. 나머지는 나중에 수정할 수 있으니 처음에는 위 표의 기본값으로 두고 넘어가도 된다.
결제 방식만 짚고 가면, 요청 기반은 요청을 처리할 때만 요금이 붙고 그 외에는 CPU가 제한된다. 인스턴스 기반은 인스턴스가 살아 있는 동안 계속 과금된다. 가끔 도는 자동화라면 요청 기반이 맞다.
서비스 계정은 컨테이너, 네트워킹, 보안 섹션의 보안 탭에 있다. 기본값은 프로젝트의 기본 컴퓨트 서비스 계정인데 권한이 넓은 편이다. 함수가 특정 리소스만 건드리면 되는 상황이라면 GCP IAM 기초 — 서비스 계정과 권한, 최소 권한 원칙에서 본 대로 전용 계정을 만들어 붙이는 편이 낫다.
컨테이너, 네트워킹, 보안 → 보안 탭. 함수가 어떤 서비스 계정으로 돌지 여기서 고른다
서비스 만들기. 위쪽에서 소스 방식을 고르고, 아래에서 이름·리전·런타임·인증·결제를 정한다
소스 탭. 함수 진입점에 적은 이름과 코드의 함수 이름이 같아야 한다. 여기서는 둘 다 hello다. 수정 후 저장하면 새 버전이 배포된다
진입점·의존성·환경 변수
- 진입점(entry point) — 폴더 안에 함수가 여러 개 있어도 GCP는 어느 것을 부를지 모른다.
--entry-point에 적은 이름의 함수가 실행된다. 파일이 아니라 함수 이름이다. - 의존성 —
requirements.txt에 적힌 것만 설치된다. 배포 후 임포트 오류가 나는 원인은 대개 여기다. - 환경 변수 —
--set-env-vars로 넘기고 코드에서는os.environ으로 읽는다. API 키 같은 비밀값은 환경 변수 대신 Secret Manager에 두는 편이 낫다.
로그로 결과를 본다
함수는 화면이 없으므로 print로 찍은 내용과 오류가 전부 Cloud Logging으로 간다.
gcloud functions logs read hello-fn --gen2 --region=asia-northeast3 --limit=20
관측 가능성 → 로그. 배포 과정과 실행 결과가 시간순으로 쌓인다. print로 찍은 내용도 여기에 나온다
콜드 스타트와 타임아웃
요청이 없을 때 인스턴스가 0개로 내려가는 것이 서버리스의 장점이자 단점이다. 한동안 아무도 부르지 않다가 처음 호출하면 컨테이너를 띄우고 의존성을 로드하는 시간이 붙는데, 이것이 콜드 스타트다. 최소 인스턴스를 1 이상으로 두면 줄어들지만 그동안 계속 요금이 붙으므로, 개인 프로젝트에서는 대개 그냥 감수한다.
타임아웃도 미리 알아야 한다. 배포할 때 지정하지 않으면 기본값은 60초다. 공식 문서 기준 상한은 HTTP 트리거 함수가 최대 60분, 이벤트 기반 함수가 최대 9분이다. 오래 걸리는 작업이라면 함수 안에서 다 하려 하지 말고 작업을 쪼개는 편이 낫다.
컨테이너 배포와 무엇이 다른가
2세대 함수의 결과물이 Cloud Run 서비스라면, 그냥 Cloud Run에 배포하는 것과 무엇이 다를까. 차이는 내가 어디까지 챙기느냐다. 함수 방식은 소스 폴더만 주면 컨테이너 이미지를 대신 구워 주고, 컨테이너 방식은 Dockerfile을 직접 쓰고 이미지를 만들어 올린다. 시스템 패키지를 깔거나 특이한 실행 환경이 필요하면 컨테이너 쪽이 맞다. 실제 컨테이너 배포 과정은 이 블로그의 Cloud Run에 LLM 앱 배포하기에 정리돼 있다.
인증도 같은 원리로 흘러간다. 함수 안에서 다른 GCP 서비스를 부를 때는 키 파일 없이 연결된 서비스 계정이 쓰이는데, 이 구조는 GCP IAM 기초 — 서비스 계정과 권한, 최소 권한 원칙에서 본 ADC 그대로다.
비용 감각
2세대 함수는 Cloud Run 요금 체계를 따른다. 공식 문서 기준 요청 기반 과금의 상시 무료 한도는 월 200만 요청과 일정량의 vCPU·메모리 사용 시간이다. 하루 몇 번 도는 개인 자동화라면 이 안에서 끝난다. 다만 함수 요금 자체와 별개로 빌드와 이미지 저장에 요금이 조금 붙는다는 점은 기억해 두는 게 좋다.
마무리
함수 배포는 결국 세 가지만 정하는 일이다. 어떤 코드를(진입점), 무엇이 부를 때(트리거), 어떤 권한으로(서비스 계정) 실행할지. 나머지는 GCP가 알아서 한다.
다음 편에서는 이 함수를 정해진 시각에 저절로 돌게 만든다. Cloud Scheduler로 크론을 걸고, 그 사이에 Pub/Sub를 끼워 넣으면 왜 더 튼튼해지는지까지 본다.
· · · 연재 순서 · · ·
(이전) GCP 데이터베이스 선택 가이드 — Firestore·Cloud SQL·BigQuery 무엇을 쓸까
(다음) Cloud Scheduler와 Pub/Sub — 정해진 시각에 일 시키기
※ 이 글의 명령어와 한도는 2026년 8월 기준이며 요금·메뉴 구성은 자주 변경됩니다.
댓글
댓글 쓰기