오늘은 이론적인 내용과 실용적인 내용 둘 다 잘 배웠다. 특히 막연하게 알고있었던 배포 과정과 도커 컨테이너를 어떻게 배포하는지 알게되었다.
배포란 말 그대로 내 소스코드를 사람들에게 배포하는 것이다.
사실 복잡한 것이 아니라 로컬 컴퓨터로 서버를 run 또는 node 명령과 같은 명령으로 실행시키는 것과 같은데, 로컬 컴퓨터로 하면 계속 켜놔야 하고 방화벽 설정을 직접 다 해야하는 번거로움 및 해킹에 취약하다는 단점 때문에 클라우드 컴퓨팅 서비스를 사용하여 내 로컬 컴퓨터가 아닌 업체의 컴퓨터를 빌려 서버를 실행시켜 놓는것이다.
그럼 node.js로 만든 서버를 배포하는 과정을 예시로 들어보자. 먼저 로컬 컴퓨터에서 서버를 구동하고 배포하려고 하면, main.js에 소스코드를 작성하고 터미널에 해당 프로젝트 디렉토리로 들어가서 node main
이라는 명령어를 치고, 서버에서 예를들자면 listening on port xxxx
이라는 문구가 뜰 것이다. 이렇게 해서 배포가 끝났다. (사실 이렇게 실행시킨다고 다른 컴퓨터에서 내 서버에 요청을 날릴순 없다. 웹 서버를 구동하기 위한 추가적인 절차가 필요하다)
그러면 이번엔 로컬 컴퓨터에서 소스코드를 작성한 뒤에 클라우드 서비스를 이용하여 배포하는 과정을 알아보자. EC2 인스턴스를 빌린다. EC2인스턴스는 컴퓨터이다. 그 컴퓨터에 ssh로 접속할 수 있다. 접속하고 난 뒤 소스코드가 필요하니 github에 올려둔 소스코드를 clone한다. (처음 ec2에 접속하면 git도 없으니 git도 설치하고, 여러가지 필요한 것들을 설치해준다) 그 다음 로컬 컴퓨터에서 했듯이 클론한 리포지토리로 가서 npm install 등을 실행해주고, node main
을 쳐서 서버를 실행시킨다. 이렇게 배포가 끝난다.
만약 소스코드를 업데이트 한다면 ec2에 접속해서 git pull을 통해 업데이트된 소스코드를 다시 받아주고 새로운 패키지를 설치했다면 npm install도 해주는 등 추가적인 명령들을 실행한 후 다시 node main을 통해 서버를 구동할 것이다.
이거를 소스코드가 변경될 때마다 사람이 일일히 해야한다면 상당히 귀찮을 것이다. 그래서 ci/cd를 통한 배포 자동화가 필요한 것이다.
npm install mongoose
import mongoose from 'mongoose'
const MONGODB_URI = process.env.MONGODB_URI
if (!MONGODB_URI) {
throw new Error(
'Please define the MONGODB_URI environment variable inside .env.local'
)
}
/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = global.mongoose
if (!cached) {
cached = global.mongoose = { conn: null, promise: null }
}
async function dbConnect() {
if (cached.conn) {
return cached.conn
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
}
cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
return mongoose
})
}
try {
cached.conn = await cached.promise
} catch (e) {
cached.promise = null
throw e
}
return cached.conn
}
export default dbConnect
import { PostCategory } from "@/app/types/post";
import mongoose from "mongoose";
const PostSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
contents: String,
category: {
type: String,
enum: PostCategory,
default: PostCategory.General,
},
writeId: mongoose.Schema.Types.ObjectId,
},
{ timestamps: true }
);
export const PostModel =
mongoose.models.Post || mongoose.model("Post", PostSchema);
import dbConnect from "@/dbConnect";
import { PostModel } from "@/lib/api/models/post";
import { NextRequest, NextResponse } from "next/server";
export const GET = async (req: NextRequest) => {
await dbConnect();
const posts = PostModel.find();
return NextResponse.json(posts);
};
export const POST = async (req: NextRequest) => {
await dbConnect();
const body = await req.json();
const post = await PostModel.create(body);
return NextResponse.json(post);
};
import dbConnect from "@/dbConnect";
import { PostModel } from "@/lib/api/models/post";
import { NextRequest, NextResponse } from "next/server";
export const GET = async (
req: NextRequest,
{ params }: { params: { postId: string } }
) => {
await dbConnect();
const postId = params.postId;
const post = await PostModel.findOne({ _id: postId });
return NextResponse.json(post);
};
// post 수정 api
export const POST = async (
req: NextRequest,
{ params }: { params: { postId: string } }
) => {
await dbConnect();
const body = req.json();
const postId = params.postId;
const post = await PostModel.findOneAndUpdate({ _id: postId }, body, {
new: true,
});
return NextResponse.json(post);
};
// post 삭제 api
export const DELETE = async (
req: NextRequest,
{ params }: { params: { postId: string } }
) => {
await dbConnect();
const postId = params.postId;
const post = await PostModel.findByIdAndDelete(postId);
return NextResponse.json(post);
};
import dbConnect from "@/dbConnect";
import { PostModel } from "@/lib/api/models/post";
import { NextRequest, NextResponse } from "next/server";
enum PostOrder {
CreatedAtAsc = "CREATED_AT_ASC",
CreatedAtDesc = "CREATED_AT_DESC",
}
const getSortOrder = (orderBy: string): { createdAt: 1 | -1 } => {
switch (orderBy) {
case PostOrder.CreatedAtAsc:
return { createdAt: 1 };
case PostOrder.CreatedAtDesc:
return { createdAt: -1 };
default:
return { createdAt: -1 };
}
};
export const GET = async (req: NextRequest) => {
// const query = new URL(req.url);
const searchParams = req.nextUrl.searchParams;
const orderBy = searchParams.get("orderBy");
const category = searchParams.get("category");
const filter = {};
if (category) {
Object.assign(filter, { category });
}
await dbConnect();
const posts = await PostModel.find(filter).sort(
getSortOrder(orderBy as string)
);
return NextResponse.json(posts);
};
발표자료를 준비하는데 이론적인 개념이 헷갈려서 힘들었다. 계속 찾아보고 물어보고 있지만 아직 헷갈리는 개념이 너무 많고 용어도 정확하게 알려주는 곳이 잘 없다.