PostgreSQL로 React 앱을 배포하는 방법은 무엇인가요?
PostgreSQL은 다양한 사용 사례를 갖춘 고급 엔터프라이즈용 관계형 데이터베이스 관리 시스템입니다. 현재 MySQL에 이어 두 번째로 많이 사용되는 SQL 데이터베이스입니다.
이 글에서는 PostgreSQL의 본질을 살펴보고, SQL 데이터베이스와 NoSQL 데이터베이스의 차이점을 살펴보고, PostgreSQL로 지원되는 웹 앱을 배포하는 방법에 대한 단계별 가이드를 제공합니다.
PostgreSQL이란 무엇인가요?
PostgreSQL은 SQL과 JSON을 지원하는 무료 오픈소스 객체 관계형 데이터베이스입니다.
1996년에 처음 출시되었으므로 성숙하고 강력하며 안전한 관계형 데이터베이스 관리 시스템(RDBMS)으로 간주됩니다.
Postgres는 범용 트랜잭션 데이터베이스, 지리공간 데이터베이스, 동적 웹 애플리케이션 데이터베이스, 페더레이션 데이터베이스 등으로 사용할 수 있습니다.
MySQL과 같은 다른 인기 데이터베이스에 비해 테이블 상속, 사용자 정의 유형, 비동기 복제, 다중 버전 동시성 제어(MVCC)를 지원합니다.
성능, 확장성, 확장성, 내결함성, ACID 규정 준수로 잘 알려져 있습니다.
RDBMS는 Windows, Linux, macOS를 비롯한 대부분의 주요 운영 체제에서 지원됩니다.
또한 Java, Python, C, Go, Perl, JavaScript 등 대부분의 인기 있는 프로그래밍 언어를 지원합니다.
SQL 데이터베이스와 NoSQL 데이터베이스
데이터베이스는 데이터 구조에 따라 두 가지 범주로 나눌 수 있습니다:
- 관계형 데이터베이스(SQL)
- 비관계형 데이터베이스(NoSQL)
관계형 데이터베이스(SQL)
관계형 데이터베이스는 SQL 또는 구조화된 쿼리 언어를 사용합니다. SQL은 데이터 쿼리 및 조작에 사용되는 도메인 전용 언어입니다.
이 언어는 간단한 명령, 트랜잭션, 저장된 함수나 보기와 같은 임베디드 프로시저를 지원합니다.
SQL 데이터베이스는 미리 정의된 스키마를 기반으로 합니다. 각 데이터 유형이 고유한 열 집합이 있는 테이블로 구성됩니다. 일반적으로 ACID 속성을 가집니다:
- 원자성
- 일관성
- 격리
- 내구성
SQL 데이터베이스는 1970년대부터 널리 사용되어 왔습니다.
가장 많이 사용되는 SQL 데이터베이스는 MySQL, PostgreSQL, SQLite 및 Oracle Database입니다.
비관계형 데이터베이스(NoSQL)
비관계형 데이터베이스 또는 비SQL 데이터베이스는 엄격한 스키마를 따르지 않습니다. 비관계형 데이터베이스는 방대한 양의 비정형 또는 동적 데이터(가장 일반적으로 JSON)를 저장하는 데 적합합니다.
다음과 같은 여러 유형의 NoSQL 데이터베이스가 있습니다:
- 문서 데이터베이스
- 키-값 데이터베이스
- 그래프 데이터베이스
최근 몇 년 동안 대량의 비정형 데이터의 가용성으로 인해 NoSQL 데이터베이스가 점점 더 인기를 얻고 있습니다.
가장 많이 사용되는 NoSQL 데이터베이스에는 Redis, Cassandra, AWS DynamoDB가 있습니다.
SQL과 NoSQL 중 어느 것이 더 낫나요?
SQL 데이터베이스와 NoSQL 데이터베이스 중 선택은 사용 사례와 데이터에 따라 달라집니다.
방대한 양의 비정형 데이터를 다루고 있다면 NoSQL을 사용하는 것이 좋습니다. 반면에 데이터가 대부분 정형 데이터인 경우에는 SQL이 더 나은 선택입니다.
고려해야 할 또 다른 두 가지 요소는 성능과 확장성입니다. NoSQL 데이터베이스는 SQL 데이터베이스보다 빠른 경향이 있습니다. SQL 데이터베이스는 수직으로만 확장할 수 있는 반면, NoSQL 데이터베이스는 수평으로 확장할 수 있습니다.
마지막으로, 일부 웹 프레임워크는 SQL 데이터베이스만 지원하는 반면, 다른 프레임워크는 NoSQL만 지원합니다.
PostgreSQL로 React 앱을 배포하는 방법은 무엇인가요?
이 문서 섹션에서는 Postgres 지원 웹 애플리케이션을 Back4app에 배포하는 방법에 대해 알아봅니다.
전제 조건
- JavaScript ES6, React 및 Next.js 사용 경험
- Docker, BaaS 및 CaaS 클라우드 모델에 대한 기본 이해
- 컴퓨터에 설치된 JavaScript IDE 및 Docker Desktop
- 무료 Back4app 및 GitHub 계정
Back4app 스택이란 무엇인가요?
배포 프로세스에 대해 자세히 알아보기 전에 Back4app이 제공하는 솔루션에 대해 간략히 살펴보겠습니다.
- Back4app(BaaS )는 완전한 백엔드 솔루션입니다. 여기에는 사용자 관리, 인증, 실시간 데이터베이스(NoSQL 또는 PostgreSQL), 사용자 지정 코드 실행, 자동 생성 API, SDK, 푸시 알림 등이 포함됩니다.
- Back4app 컨테이너(CaaS) 는 Docker 기반 컨테이너 관리 및 배포 플랫폼입니다. 몇 번의 클릭만으로 Docker 컨테이너를 가동할 수 있습니다!
- Back4app AI 에이전트는 새로운 AI 기반 에이전트입니다. 이 에이전트를 사용하면 대화 기능을 통해 모든 클라우드 관련 작업을 수행할 수 있습니다. 이 에이전트는 다른 두 개의 Back4app 솔루션과 긴밀하게 통합됩니다.
이 글에서는 Back4app BaaS와 Back4app 컨테이너를 사용하겠습니다. 하지만 웹 개발에 AI를 활용하는 방법은 웹 개발에 AI를 어떻게 사용하나요? 를 확인하여 AI를 활용하여 개발 프로세스를 가속화하는 방법을 알아보세요.
프로젝트 개요
간단한 예산 추적 웹 애플리케이션을 구축할 예정입니다. 웹 앱을 통해 사용자는 비용을 추가하고, 비용을 제거하고, 다양한 통계(예: 지출 금액, 예산 비율)를 계산할 수 있습니다.
앱은 백엔드와 프론트엔드로 나뉩니다. 백엔드는 Back4app(PostgreSQL로 지원)으로 빌드되고, 프론트엔드는 React(Next.js 사용)로 빌드됩니다.
Parse SDK를 사용하여 이 둘을 연결하고 프론트엔드를 Back4app 컨테이너에 배포하겠습니다.
백엔드
백엔드부터 시작하겠습니다.
Back4app 앱 만들기
Back4app 앱을 만들려면 먼저 Back4app 대시보드로 이동하여 “새 앱 만들기”를 클릭합니다.
다음으로 백엔드를 구축 중이므로 ‘서비스형 백엔드’를 선택합니다.
애플리케이션에 설명이 포함된 이름을 지정하고 데이터베이스로 “PostgreSQL”을 선택한 다음 “만들기”를 클릭합니다.
이 글을 쓰는 시점에서 개발자의 관점에서 두 데이터베이스 유형 사이에는 큰 차이가 없습니다. 두 데이터베이스 유형 모두에 동일한 구문 분석 SDK 메서드가 적용됩니다.
Back4app은 애플리케이션에 필요한 모든 것을 준비하는 데 시간이 조금 걸립니다. 여기에는 데이터베이스, 애플리케이션 레이어, 자동 확장, 자동 백업 및 보안 설정이 포함됩니다.
앱이 준비되는 즉시 앱의 실시간 데이터베이스 보기로 리디렉션됩니다.
데이터베이스 아키텍처
이제 데이터베이스를 디자인해 보겠습니다.
앱이 비교적 간단하므로 클래스는 하나만 필요합니다. 이 클래스를 Expense라고
부르겠습니다.
새 데이터베이스 클래스를 만들려면 ‘클래스 만들기’를 클릭하고 이름을 비용으로
지정한 다음 ‘공개 읽기 및 쓰기 사용’이 선택되어 있는지 확인합니다.
공개 읽기 및 쓰기를 활성화하는 것은 누구나 클래스에서 CRUD 작업을 수행할 수 있으므로 나쁜 습관으로 간주됩니다. 보안은 이 글의 범위를 벗어납니다. 그래도 구문 분석 서버 보안을 검토하는 것이 좋습니다.
기본적으로 데이터베이스 클래스에는 다음 네 가지 필드가 있습니다:
+-----------+------------------------------------------------------------------------+
| Name | Explanation |
+-----------+------------------------------------------------------------------------+
| objectId | Object's unique identifier |
+-----------+------------------------------------------------------------------------+
| updatedAt | Date time of the object's last update. |
+-----------+------------------------------------------------------------------------+
| createdAt | Date time of object's creation. |
+-----------+------------------------------------------------------------------------+
| ACLs | Allow you to control the access to the object (e.g. read, update). |
+-----------+------------------------------------------------------------------------+
프론트엔드를 구축할 때 사용할 것이므로 간단히 살펴보세요.
그런 다음 Expense
클래스에 다음 필드를 추가합니다:
+-----------+-------------+--------------------+----------+
| Data type | Name | Default value | Required |
+-----------+-------------+--------------------+----------+
| String | name | <leave blank> | yes |
+-----------+-------------+--------------------+----------+
| String | description | <leave blank> | no |
+-----------+-------------+--------------------+----------+
| Number | price | 0 | yes |
+-----------+-------------+--------------------+----------+
그런 다음 몇 가지 샘플 데이터로 데이터베이스를 채웁니다.
이름, 설명, 가격을 입력하여 몇 가지 항목을 만듭니다. 또는 이 데이터 덤프를 가져올 수도 있습니다.
테스트 데이터는 나중에 백엔드와 프론트엔드를 테스트할 수 있게 해줍니다.
클라우드 코드
Back4app을 사용하면 클라우드 코드 함수를 통해 사용자 정의 JavaScript 코드를 실행할 수 있습니다. 함수는 작업으로 예약하거나 Parse 또는 HTTP 요청으로 호출할 수 있습니다.
관리되는 환경 내에서 운영되므로 자체 서버를 관리하고 확장할 필요가 없습니다.
서비스형 기능(FaaS)에 대해 자세히 알아보려면 서버리스 기능이란 무엇인가요?
클라우드 코드 기능을 활용하여 비용 통계를 계산합니다.
생성하려면 사이드바에서 ‘클라우드 코드 > 기능 및 웹 호스팅’을 선택합니다. 그런 다음 cloud/main.js를 열고 다음 코드를 붙여넣습니다:
// cloud/main.js
const totalBudget = 100;
Parse.Cloud.define("getStatistics", async (request) => {
const query = new Parse.Query("Expense");
const totalExpenses = await query.count();
const results = await query.find();
const totalSpent = results.reduce(
(sum, expense) => sum + expense.get("price"), 0);
const spentPercentage = totalSpent > 0 ?
Math.round((totalSpent / totalBudget) * 100) : 0;
return {
totalExpenses,
totalSpent,
totalBudget,
spentPercentage
};
});
- 이 코드는
getStatistics라는
새로운 클라우드 코드 함수를 정의합니다. - 이 함수는 데이터를 집계하여
총 지출액과
지출 비율을
계산합니다.
마지막으로 ‘배포’를 클릭하여 클라우드에 기능을 배포합니다.
백엔드 작업은 끝났습니다. 정말 쉬웠습니다!
프론트엔드
이 글 섹션에서는 앱의 프론트엔드를 구현해 보겠습니다.
다음 앱 만들기
Next.js 앱을 부트스트랩하는 가장 쉬운 방법은 create-next-app
유틸리티를 사용하는 것입니다. 이 유틸리티를 사용하려면 터미널을 열고 다음 명령을 실행합니다:
$ npx create-next-app@latest back4app-postgres
√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@)? ... No
Creating a new Next.js app in /back4app-postgres.
다음 앱 만들기
유틸리티를 사용한 적이 없는 경우 자동으로 설치됩니다.
컴포넌트 라이브러리 대신 TailwindCSS를 사용할 것이므로 반드시 활성화하세요.
다음으로, 먼저 공개/폴더의 콘텐츠를 삭제하여 부트스트랩된 프로젝트를 정리합니다.
src/app/globals.css의 처음 세 줄만 유지합니다:
/* app/src/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
그리고 app/src/globals.css를 다음 코드로 바꿉니다:
// src/app/page.js
export default function Page() {
return (
<p>Back4app rocks!</p>
);
}
개발 서버를 시작합니다:
$ next dev
즐겨찾는 웹 브라우저를 열고 http://localhost:3000/ 으로 이동합니다. 모든 것이 정상적으로 진행되면 “Back4app이 작동합니다!”라는 메시지가 표시됩니다.
조회수
프론트엔드에는 다음과 같은 엔드포인트가 있습니다:
/
비용 및 비용 통계 표를 표시합니다.- /
add/는
새 비용을 추가하는 양식을 표시합니다. /삭제/
/ 비용 삭제 확인을 표시합니다.
이러한 엔드포인트를 구현하려면 다음 디렉터리 구조를 만드세요:
src/
├── add/
│ └── page.js
└── delete/
└── [objectId]/
└── page.js
또한 Container.js 및 Header.js를 사용하여 컴포넌트 폴더를 만듭니다:
src/
└── components/
├── Container.js
└── Header.js
Container.js에 다음을 붙여넣습니다:
// src/app/components/Container.js
const Container = ({children}) => {
return (
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
{children}
</div>
)
}
export default Container;
Header.js에 대해서도 동일하게 수행합니다:
// src/app/components/Header.js
import Container from "@/app/components/Container";
import Link from "next/link";
const Header = () => {
return (
<Container>
<div className="py-4">
<Link href="/">
<div
className="text-2xl font-semibold text-indigo-500 hover:text-indigo-700"
>
back4app-postgres
</div>
</Link>
</div>
</Container>
)
}
export default Header;
layout. js에서 Container.j s와 Header.js를 다음과 같이 사용하세요:
// src/app/layout.js
"use client";
import {Inter} from "next/font/google";
import "./globals.css";
import Header from "@/app/components/Header";
import Container from "@/app/components/Container";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
<Header/>
<Container>
{children}
</Container>
</body>
</html>
);
}
마지막으로 뷰 코드를 파일에 적절히 붙여넣습니다:
개발 서버를 다시 실행하고 브라우저에서 http://localhost:3000 을 방문합니다. 이와 비슷한 화면이 표시될 것입니다:
‘비용 추가’ 버튼을 클릭하면 비용 추가 양식으로 리디렉션됩니다.
Parse SDK
Back4app 백엔드에 연결하는 방법에는 여러 가지가 있습니다:
- RESTful API
- GraphQL API
- Parse SDK
가장 강력하고 간단한 설정이므로 후자를 사용하겠습니다.
Parse SDK는 데이터 쿼리, 데이터 관리, 클라우드 코드 기능 실행 등을 위한 편리한 도구가 포함된 툴킷입니다.
JavaScript, PHP, Flutter, Objective-C 등 다양한 프로그래밍 언어와 프레임워크에서 사용할 수 있습니다.
먼저 npm을 통해 Parse를 설치하세요:
$ npm install parse
React 뷰에서 Parse를 사용하려면 먼저 초기화해야 합니다. 하지만 그 전에 모든 뷰에 Parse 인스턴스를 전달할 수 있도록 React 컨텍스트를 생성합니다.
src/app 폴더에 컨텍스트 폴더를 만들고 그 안에 parseContext.js 파일을 만듭니다:
import {createContext} from "react";
const ParseContext = createContext();
export default ParseContext;
그런 다음 layout.js에서 Parse를 초기화하고 전체 앱을 다음과 같이 ParseContext.Provider로
래핑합니다:
// src/app/layout.js
import Parse from "parse/dist/parse";
import ParseContext from "@/app/context/parseContext";
Parse.initialize(
"<your_parse_application_id>",
"<your_parse_javascript_key>",
);
Parse.serverURL = "https://parseapi.back4app.com/";
export default function RootLayout({ children }) {
return (
<ParseContext.Provider value={Parse}>
<html lang="en">
// ...
</html>
</ParseContext.Provider>
);
}
교체해야 합니다. <your_parse_application_id>
및 <your_parse_javascript_key>
를 실제 키로 교체해야 합니다. 키를 받으려면 Back4app 대시보드로 이동하여 사이드바에서 ‘앱 설정 > 보안 및 키’를 선택하세요.
이제 뷰에서 다음과 같이 Parse
인스턴스를 얻을 수 있습니다:
const parse = useContext(ParseContext);
그런 다음 뷰를 약간 수정하여 구문 분석 메서드를 호출합니다.
src/app/page.js:
// src/app/page.js
export default function Page() {
// ...
const parse = useContext(ParseContext);
const fetchExpenses = () => {
const query = new parse.Query("Expense");
query.find().then((fetchedExpenses) => {
const expenses = fetchedExpenses.map(expense => ({
objectId: expense.id,
name: expense.get("name"),
description: expense.get("description"),
price: expense.get("price"),
createdAt: expense.get("createdAt"),
}));
setExpenses(expenses);
console.log("Expenses fetched successfully.");
}).catch((error) => {
console.error("Error while fetching expenses:", error);
});
}
const fetchStatistics = () => {
parse.Cloud.run("getStatistics").then((statistics) => {
setStatistics(statistics);
console.log("Statistics fetched successfully.");
}).catch((error) => {
console.error("Error while fetching statistics:", error);
});
}
// ...
}
src/app/add/page.js:
// src/app/add/page.js
export default function Page() {
// ...
const parse = useContext(ParseContext);
const onAddClick = () => {
const Expense = parse.Object.extend("Expense");
const expense = new Expense();
expense.set("name", name);
expense.set("description", description);
expense.set("price", parseFloat(price));
expense.save().then((expense) => {
console.log("Expense created successfully with objectId: ", expense.id);
router.push("/");
}, (error) => {
console.error("Error while creating expense: ", error);
}
);
}
const onCancelClick = () => {
router.push("/");
}
// ...
}
src/app/delete/[objectId]/page.js:
// src/app/delete/[objectId]/page.js
export default function Page() {
// ...
const parse = useContext(ParseContext);
const onDeleteClick = () => {
const Expense = parse.Object.extend("Expense");
const query = new parse.Query(Expense);
query.get(objectId).then((expense) => {
return expense.destroy();
}).then((response) => {
console.log("Expense deleted successfully");
router.push("/");
}).catch((error) => {
console.error("Error while deleting expense: ", error);
});
}
const onCancelClick = () => {
router.push("/");
}
// ...
}
파일 상단에 있는 가져오기 기능을 잊지 마세요:
import {useContext} from "react";
import ParseContext from "@/app/context/parseContext";
좋아요, 끝났습니다.
이제 프론트엔드가 백엔드에 연결되었습니다. 브라우저에서 앱을 방문하면 백엔드에서 데이터가 올바르게 로드되는 것을 확인할 수 있습니다. 이제 프론트엔드의 모든 변경 사항이 백엔드에 반영됩니다.
도커라이즈
Back4app 컨테이너는 CaaS 플랫폼이므로 배포하기 전에 프로젝트를 도커화해야 합니다. 프로젝트를 도커라이즈하는 권장 방법은 Docker파일을 사용하는 것입니다.
도커파일은 컨테이너 이미지를 생성하기 위한 지침을 제공하는 청사진 스크립트입니다.
프로젝트 루트에서 도커파일을 만듭니다:
# Dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
RUN npm install -g next
EXPOSE 3000
CMD ["next", "start", "-p", "3000"]
이 도커파일은 node:18-alpine
이미지를 활용하고, 작업 디렉터리를 설정하고, 종속성을 관리하고, 프로젝트를 통해 복사하고, 애플리케이션을 빌드합니다.
완료되면 포트 3000을
노출하고 해당 포트에서 수신 대기할 Next.js 서버를 시작합니다.
다음으로 이미지 크기를 최소화하기 위해 .dockerignore 파일을 생성합니다:
# .dockerignore
.idea/
node_modules/
.next/
/out/
build/
.vercel
.dockerignore 파일은 .gitignore 파일과 비슷한 방식으로 작동합니다.
로컬에서 이미지를 빌드하고 실행하여 모든 것이 작동하는지 확인하세요:
$ docker build -t back4app-postgres:1.0 .
$ docker run -it -p 3000:3000 back4app-postgres:1.0
웹 브라우저를 열고 http://localhost:3000 으로 이동합니다. 웹 애플리케이션이 정상적으로 작동해야 합니다.
VCS로 푸시
Back4app 컨테이너에 코드를 배포하려면 GitHub에 푸시해야 합니다.
- GitHub 계정에 로그인합니다.
- 새 리포지토리를 만듭니다.
- 원격 원본 URL(예: [email protected]:
duplxey/repo.git
)을 복사합니다. - Git 리포지토리 초기화:
git init
- 리모트 추가:
git remote add origin
- 모든 파일 추가:
git add .
- 커밋 생성:
git commit -m "프로젝트 초기화"
- 소스 코드 푸시:
git push origin main
즐겨 사용하는 웹 브라우저를 열고 모든 코드가 리포지토리에 추가되었는지 확인합니다.
코드 배포
이제 앱이 도커화되고 GitHub에서 호스팅되었으므로 마침내 배포할 수 있습니다.
Back4app 대시보드로 이동하여 “새 앱 만들기” 버튼을 다시 한 번 클릭합니다.
도커화된 애플리케이션을 배포하기 때문에 ‘서비스형 컨테이너’를 선택합니다.
Back4app 컨테이너를 처음 사용하는 경우, GitHub를 Back4app 계정에 연결해야 합니다.
Back4app이 액세스할 수 있는 리포지토리를 선택할 때 이전 단계에서 생성한 리포지토리에 대한 액세스를 허용해야 합니다.
다음으로 리포지토리를 ‘선택’합니다.
Back4app 컨테이너를 사용하면 포트, 자동 배포, 환경 변수 및 상태 확인과 같은 배포 설정을 구성할 수 있습니다.
앱이 간단하기 때문에 이름만 제공하고 다른 모든 항목은 기본값으로 유지할 수 있습니다.
“앱 만들기”를 클릭하면 Back4app이 GitHub에서 코드를 가져와서 Docker 이미지를 빌드하고 컨테이너 레지스트리에 푸시한 후 배포합니다.
잠시 후 사이드바의 URL에서 앱을 사용할 수 있습니다.
결론
이 글에서는 PostgreSQL의 정의, SQL 데이터베이스와 NoSQL 데이터베이스의 차이점, Postgres 지원 웹 애플리케이션을 Back4app에 배포하는 방법에 대해 알아보았습니다.
이해도를 테스트하기 위해 이러한 아이디어 중 몇 가지를 구현해 보는 것이 좋습니다:
- 사용자 인증
- 글로벌 예산 대신 사용자 기반으로 설정하세요.
- Back4app 컨테이너 앱에 사용자 지정 도메인 추가하기
back4app-postgres 리포지토리에서 최종 소스 코드를 가져옵니다.