Firebase Cloud Functions를 V1에서 V2로 마이그레이션하고,
Cli를 이용해서 테스트하고 배포까지 진행하는 과정을 기록했습니다.
2023년에 Firebase Cloud Functions V1에 대한 글을 작성했는데,
해당 글을 수정하여 V2 버전에 대한 내용으로 다시 채우게 되었습니다.
V1버전에 대한 지원이 중단될 예정이므로, V2 버전으로 마이그레이션 바랍니다.
V2버전에 대한 마이그레이션 방법은 공식 문서를 참고하거나, 이 글을 통해 진행하실 수 있습니다.

Firebase에도 AWS의 서버리스 프레임워크 AWS Lambda 처럼, 서버리스를 지원합니다.
그 서비스 이름은 바로 'Cloud Functions' 입니다.
도입 배경
저같은 경우에는, 한정적인 서버 자원에서 서버의 과부하를 줄이기 위해서
크롤링 작업이나, 중요도가 낮은 업데이트같이 속도 면에서 크게 중요하지 않은 작업들은 서버리스를 활용하고 있습니다.
그리고 AWS Lambda 와 Firebase Cloud Functions 중에 Firebase Cloud Functions를 사용하게 된 배경은
1. 개발자가 해야 할 세팅이 매우 간편하고 2. 무료 Cost 상한선이 높기 때문입니다.
시간과 돈을 절약해주기 때문에 사용했다고 보면 되겠네요 ㅎㅎ
Cloud Functions
Firebase용 Cloud Functions는 Firebase 기능과 HTTPS 요청에 의해 트리거되는 이벤트에 응답하여 백엔드 코드를 자동으로 실행할 수 있는 서버리스 프레임워크입니다.
함수를 작성하고 배포하면 Google 서버에서 즉시 함수를 관리하기 시작합니다. HTTP 요청으로 직접 함수를 실행하거나, 백그라운드 함수의 경우 Google 서버에서 이벤트를 수신대기하고 함수가 트리거되면 실행합니다.
이 서비스를 이용하기 위해서는 기본 요금 서비스로는 이용할 수 없고,
사용량 만큼 지불(Blaze)로 요금제를 업그레이드 하고 나야 이용할 수 있습니다.
하지만 Blaze를 이용한다고 해서, 기존에 이용하던 서비스들이 모두 유료로 전환되는 개념이 아니라
기본 무료 요금제만큼 이용할 수 있되, 기본 무료 요금제의 한도를 넘어갈 때 부터 사용량 당 요금이 부과되는 방식입니다.
즉, 기존 무료 사용량 + 추가 요금 부과 가 Blaze 요금제라고 볼 수 있습니다.
1. Cloud functions 설정
firebase 프로젝트를 연결하기 위한 프로젝트 디렉토리를 생성한 뒤에, 아래 명령어를 입력하여 설정 도구를 받아줍니다.
$ npm install -g firebase-tools
그 다음엔 firebase 프로젝트를 초기화해줍니다.
firebase init
그 다음 필요한 기능들을 space를 이용해서 멀티체크하고
(저같은 경우엔 firestore & cloud functions)

그 이후 프로젝트를 새로 만들어서 할지, 아니면 기존에 있던거로 할지 선택합니다.

만약 다음과 같은 에러가 발생한다면
Error: Failed to list Firebase projects
로그인 인증을 다시 진행해줘야합니다.
firebase login --reauth
기본적인 설정을 완료하고, JavaScript를 이용해서 설정합니다.

2. 함수 작성하기
제가 Cloud Functions를 사용하는 목적은 다음과 같았습니다.
Flutter를 이용하여 Firestore의 문서를 추가하게 되면 해당 문서 주제를 구독하고 있는 유저들에게 FCM을 발송시키고자 하는 목적입니다
Client 단에서는 Firebase-Admin을 사용할 수 없기 때문에, 별도의 서버 없이 간편하게 Cloud Functions를 이용하여 이를 구현하고자 했습니다.
1. 설정
프로젝트 설정 -> 클라우드 메세징에서 Cloud Messaging API가 설정되어 있어야 합니다.
여기에 나와있듯, V1버전은 현재 지원하지 않기에 V2 API 를 사용해야 하며, 이와 관련해서 아래 코드로 다뤄보겠습니다.

2-1. index.js (V1)
아래 코드는 V1 API 예시입니다.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendFCMOnDocumentAdded = functions.firestore
.document("{collection}/{documentId}")
.onCreate(async (snapshot, context) => {
// 주제 구독 관련 코드 작성하셔야 합니다
// Send the FCM message to the specified topic
try {
await admin.messaging().sendToTopic(topic, payload);
console.log("FCM message sent successfully");
} catch (error) {
console.error("Error sending FCM message:", error);
}
});
2-2. index.js (V2)
이렇게 사용하던 코드를 V2로 마이그레이션하게 되면 아래와 같습니다.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendFCMOnDocumentAddedFunction = onDocumentCreated(
"{collection}/{documentId}",
async (event) => {
// 주제 구독 관련 코드 작성하셔야 합니다
// Send the FCM message to the specified topic
try {
await admin.messaging().sendToTopic(topic, payload);
console.log("FCM message sent successfully");
} catch (error) {
console.error("Error sending FCM message:", error);
}
}
);
보시다시피 크게 달라진 점은 없어서 난이도적으로 어려운 점은 없습니다.
함수들이 어떻게 바뀌었는지에 대한 코드는 공식 문서에서 쉽게 확인할 수 있으니 참고 바랍니다.
3. 테스트

배포 전 중요한 단계로,
클라우드에 올리기 전에 기능이 잘 동작하는지 로컬에서 테스트해보기 위해 Firebase Emulator Suite 를 활용할 수 있습니다.
공식 문서에도 테스트 방법이 안내되어 있지만, 간단히 방법만 말씀드리면
아래와 같은 명령으로 먼저 로컬에서 서버를 구동합니다
firebase emulators:start
그럼 제가 사용하고 있는 서비스들에 대한 로컬 서버가 구동되는데요

만약 저처럼 모든 서비스를 올리지 않고
특정 서비스만 테스팅에 올리고 싶으시면 옵션을 주면 됩니다
firebase emulators:start --only firestore,functions
이렇게 로컬 서버를 올리고 나서 http://localhost:4000/ 으로 접속해보시면

Firebase 콘솔같은 홈페이지를 만나 볼 수 있습니다.
각 서비스들은 특정 포트를 갖고 있으며, 예로 http://localhost:8080은 firestore 접근입니다.
예뮬레이터 기본 세팅은 firebase.json 파일에서 진행할 수 있습니다.
firebase.json 파일은 cli를 통해 관리되고 있는 목록들을 전부 확인할 수 있습니다.
{
// 기존 내용이 여기에 있습니다
// 아래에 추가
"emulators": {
"functions": { "port": 5001 },
"firestore": { "port": 8080 },
"pubsub": { "port": 8085 },
"ui": { "port": 4000 }
}
}
포트를 설정하거나 변경해줄 수 있습니다.
작성한 함수의 API를 호출하고 싶다면 브라우저나 REST Client를 사용해서 아래와 같이 접속해줍니다
// http://localhost:5001/{서비스명}/{리전}/{함수명}
http://localhost:5001/sample/us-central1/cron
주의
서버를 띄우고 난 뒤에 firestore 등의 데이터를 삽입하는 코드들이 로컬 서버의 firestore에 반영되는 것을 확인할 수 있습니다.
테스트를 마음껏 진행하되, 주의할 점 한 가지는 FCM을 발송하는 코드들은 로컬서버 상관없이 코드가 동작하므로
실 기기들에게도 그대로 전달될 수 있으므로 주의하셔야 합니다. (경험담)
Scheduler
또한 Scheduler 작업의 경우에는 테스트가 불가능합니다. (경험담)
Scheduler는 GCP 내의 Scheduler 기능을 사용하여 동작하기 때문에, 로컬에선 따로 테스트 할 수 없습니다.
따라서 직접 트리거 함수를 만들어서 함수가 잘 동작하는지 테스트하는 방법이 있습니다.
Region
그리고 간단한 팁으로 FireStore에도 역시 리전을 설정하는 방법이 있습니다.
기본은 us-central1으로 되어있을 텐데, 한국이나 일본 리전으로 바꿔주면 속도 향상을 기대할 수는 있으나
비용은 40% 더 비쌉니다 ㅎㅎ 시간 차이는 해봐야 1분 내외정도입니다.
import { setGlobalOptions } from 'firebase-functions/v2'
setGlobalOptions({ region: 'asia-northeast3' })
+ node18 배포 중단
2025년 2월 21일 기준 곧 node18 기반의 cloud functions 업로드가 지원 중단될 예정이니
node20으로 업데이트하시길 바라며, 방법은 cli 패키지 경로에 functions로 들어가신 뒤
package.json에서 node 버전 18을 20으로 바꿔주면 됩니다.
(메인 패키지의 package.json이 아닌, functions 패키지 내부의 package.json을 수정하셔야 합니다)
4. 배포
콘솔에서 다음 명령어를 입력하여 functions를 배포해주면 됩니다.
주의하실 점은, 배포 명령에는 옵션을 주는 방법과 주지 않는 방법이 있는데요
firebase deploy
firebase deploy --only functions, firestore
firebase deploy같은 경우에는 모든 서비스와, 설정 파일들도 함께 배포가 됩니다.
이게 꼭 나쁜건 아니지만,, 혹시 모를 상황에서 필요한 서비스만 배포하시는 것을 추천드립니다.
그리고 만약 업로드한 함수를 삭제하고 싶다면 아래와 같이 진행하시면 됩니다
// firebase functions:delete {함수이름}
firebase functions:delete cron
만약 스케쥴링에 관한 함수를 삭제하셨다면, 함수 삭제 외에도 GCP에 들어가서 Scheduler에서 스케쥴링을 삭제해주셔야
불필요한 리소스 낭비를 막을 수 있습니다.
이후 Flutter 클라이언트에서 문서를 추가하면, 주제를 구독하고 있는 유저들에게 모두 FCM이 전송됩니다.
Cloud Functions를 연동하면 굉장히 빠르게 메세지가 수신됩니다~~ (보내고 1초)

궁금하신 부분은 댓글 남겨주세용
참고
https://firebase.google.com/docs/functions/firestore-events?hl=ko
'[서버] > [AWS & Firebase]' 카테고리의 다른 글
AWS 불완전한 멀티파트 업로드 용량 관리하기 (0) | 2025.02.19 |
---|---|
Spring Scheduled가 EC2 에서 시차가 생길 때 (0) | 2024.11.02 |
AWS Swap memory 활용으로 메모리 부족 해결하기 (0) | 2024.06.19 |
[TroubleShooting] Cloud functions 'cannot find module' (0) | 2024.01.16 |
AWS OpenSearch Service 비용 이슈 (0) | 2023.01.08 |