Express.js와 타입스크립트로 백엔드 개발하기 🚀

콘텐츠 대표 이미지 - Express.js와 타입스크립트로 백엔드 개발하기 🚀

 

 

안녕하세요, 열정 넘치는 개발자 여러분! 오늘은 현대 웹 개발의 핵심 기술인 Express.js와 타입스크립트를 활용한 백엔드 개발에 대해 깊이 있게 알아보겠습니다. 이 글을 통해 여러분은 안정적이고 확장 가능한 백엔드 시스템을 구축하는 방법을 배우게 될 것입니다.

최근 재능넷과 같은 재능 공유 플랫폼에서도 이러한 기술 스택을 활용한 개발자들의 수요가 늘어나고 있죠. 그만큼 이 기술의 중요성과 실용성이 증명되고 있다고 볼 수 있습니다.

 

이 가이드는 초보자부터 중급 개발자까지 모두에게 유용한 정보를 제공할 것입니다. 우리는 기본 개념부터 시작해 고급 기술까지 단계별로 살펴볼 예정이에요. 자, 이제 Express.js와 타입스크립트의 세계로 함께 떠나볼까요? 🌟

1. Express.js와 타입스크립트 소개 📚

1.1 Express.js란?

Express.js는 Node.js 환경에서 동작하는 웹 애플리케이션 프레임워크입니다. 간결하고 유연한 구조를 가지고 있어, 개발자들 사이에서 큰 인기를 얻고 있죠.

 

Express.js의 주요 특징은 다음과 같습니다:

  • 미들웨어 기반 아키텍처
  • 라우팅 시스템
  • 템플릿 엔진 지원
  • 정적 파일 제공
  • HTTP 요청 처리 간소화

 

이러한 특징들 덕분에 Express.js는 RESTful API 개발부터 복잡한 웹 애플리케이션 구축까지 다양한 용도로 활용됩니다.

1.2 타입스크립트의 장점

타입스크립트는 자바스크립트의 상위 집합(Superset) 언어로, 정적 타입 검사와 객체 지향 프로그래밍 기능을 제공합니다.

 

타입스크립트를 사용하면 다음과 같은 이점을 얻을 수 있습니다:

  • 코드 품질 향상
  • 버그 조기 발견
  • 개발 생산성 증가
  • 더 나은 코드 문서화
  • 강력한 IDE 지원

 

이러한 장점들로 인해 타입스크립트는 대규모 프로젝트에서 특히 빛을 발합니다.

1.3 Express.js와 타입스크립트의 시너지

Express.js와 타입스크립트를 함께 사용하면, 강력하고 안정적인 백엔드 시스템을 구축할 수 있습니다. 타입스크립트의 정적 타입 검사는 Express.js 애플리케이션의 안정성을 크게 향상시키며, 코드의 가독성과 유지보수성도 개선됩니다.

 

이 조합은 특히 다음과 같은 상황에서 유용합니다:

  • 복잡한 비즈니스 로직을 다루는 대규모 프로젝트
  • 팀 단위의 협업이 필요한 프로젝트
  • 장기적인 유지보수가 필요한 프로젝트
  • 높은 신뢰성이 요구되는 시스템

 

이제 우리는 Express.js와 타입스크립트의 기본을 알아보았습니다. 다음 섹션에서는 실제 개발 환경 설정부터 시작해 보겠습니다. 🛠️

2. 개발 환경 설정 ⚙️

2.1 Node.js 설치

Express.js와 타입스크립트를 사용하기 위해서는 먼저 Node.js를 설치해야 합니다. Node.js 공식 웹사이트(https://nodejs.org)에서 LTS 버전을 다운로드하여 설치하세요.

 

설치가 완료되면 터미널에서 다음 명령어를 실행하여 설치가 제대로 되었는지 확인합니다:

node --version
npm --version

2.2 프로젝트 초기화

새 프로젝트 디렉토리를 만들고, 그 디렉토리로 이동한 후 npm을 초기화합니다:

mkdir express-typescript-project
cd express-typescript-project
npm init -y

이 명령어는 package.json 파일을 생성합니다.

2.3 필요한 패키지 설치

이제 Express.js와 타입스크립트, 그리고 관련 패키지들을 설치합니다:

npm install express
npm install -D typescript @types/express @types/node ts-node nodemon

여기서 각 패키지의 역할은 다음과 같습니다:

  • express: 웹 애플리케이션 프레임워크
  • typescript: 타입스크립트 컴파일러
  • @types/express: Express.js의 타입 정의
  • @types/node: Node.js의 타입 정의
  • ts-node: 타입스크립트를 직접 실행할 수 있게 해주는 도구
  • nodemon: 파일 변경을 감지하여 자동으로 서버를 재시작해주는 도구

2.4 타입스크립트 설정

타입스크립트 설정 파일(tsconfig.json)을 생성합니다:

npx tsc --init

생성된 tsconfig.json 파일을 열고 다음과 같이 수정합니다:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

2.5 프로젝트 구조 설정

다음과 같은 프로젝트 구조를 만듭니다:

express-typescript-project/
├── src/
│   ├── routes/
│   ├── controllers/
│   ├── models/
│   ├── middleware/
│   └── app.ts
├── package.json
└── tsconfig.json

2.6 스크립트 설정

package.json 파일에 다음 스크립트를 추가합니다:

"scripts": {
  "start": "node dist/app.js",
  "dev": "nodemon src/app.ts",
  "build": "tsc -p ."
}

이제 기본적인 개발 환경 설정이 완료되었습니다! 🎉

 

다음 섹션에서는 실제로 Express.js와 타입스크립트를 사용하여 간단한 서버를 만들어보겠습니다. 계속해서 따라와 주세요! 💪

3. 첫 번째 Express.js + 타입스크립트 서버 만들기 🖥️

3.1 기본 서버 설정

src/app.ts 파일을 생성하고 다음 코드를 작성합니다:

import express, { Express, Request, Response } from 'express';

const app: Express = express();
const port = 3000;

app.get('/', (req: Request, res: Response) => {
  res.send('Hello, Express.js with TypeScript!');
});

app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

이 코드는 간단한 Express.js 서버를 설정하고, 루트 경로('/')에 대한 GET 요청을 처리합니다.

3.2 서버 실행

터미널에서 다음 명령어를 실행하여 서버를 시작합니다:

npm run dev

브라우저에서 http://localhost:3000 에 접속하면 "Hello, Express.js with TypeScript!" 메시지를 볼 수 있습니다.

3.3 라우팅 추가하기

src/routes 디렉토리에 users.ts 파일을 생성하고 다음 코드를 작성합니다:

import express, { Router, Request, Response } from 'express';

const router: Router = express.Router();

router.get('/', (req: Request, res: Response) => {
  res.send('Users list');
});

router.get('/:id', (req: Request, res: Response) => {
  res.send(`User with ID ${req.params.id}`);
});

export default router;

그리고 app.ts 파일을 수정하여 이 라우터를 사용합니다:

import express, { Express, Request, Response } from 'express';
import userRoutes from './routes/users';

const app: Express = express();
const port = 3000;

app.use('/users', userRoutes);

app.get('/', (req: Request, res: Response) => {
  res.send('Hello, Express.js with TypeScript!');
});

app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

3.4 미들웨어 추가하기

Express.js의 강력한 기능 중 하나는 미들웨어입니다. 간단한 로깅 미들웨어를 만들어 봅시다.

src/middleware/logger.ts 파일을 생성하고 다음 코드를 작성합니다:

import { Request, Response, NextFunction } from 'express';

export const logger = (req: Request, res: Response, next: NextFunction) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
  next();
};

그리고 app.ts 파일에 이 미들웨어를 추가합니다:

import express, { Express, Request, Response } from 'express';
import userRoutes from './routes/users';
import { logger } from './middleware/logger';

const app: Express = express();
const port = 3000;

app.use(logger);
app.use('/users', userRoutes);

app.get('/', (req: Request, res: Response) => {
  res.send('Hello, Express.js with TypeScript!');
});

app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

3.5 에러 처리

마지막으로, 간단한 에러 처리 미들웨어를 추가해 봅시다. app.ts 파일의 맨 아래에 다음 코드를 추가합니다:

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

이제 우리는 기본적인 Express.js + 타입스크립트 서버를 만들었습니다! 🎉

 

이 서버는 다음과 같은 기능을 가지고 있습니다:

  • 기본 라우팅
  • 사용자 관련 라우팅
  • 로깅 미들웨어
  • 기본적인 에러 처리

 

다음 섹션에서는 이 서버를 더욱 발전시켜, 데이터베이스 연결, 인증 처리, 테스팅 등 더 고급 주제들을 다뤄보겠습니다. 계속해서 따라와 주세요! 💪

4. 데이터베이스 연결: MongoDB와 Mongoose 🗄️

4.1 MongoDB 소개

MongoDB는 NoSQL 데이터베이스로, JSON과 유사한 형태의 문서를 저장하고 관리합니다. 유연한 스키마와 높은 확장성으로 인해 현대적인 웹 애플리케이션 개발에 많이 사용됩니다.

4.2 Mongoose 소개

Mongoose는 MongoDB를 위한 ODM(Object Data Modeling) 라이브러리입니다. 이를 통해 MongoDB와의 상호작용을 더 쉽고 직관적으로 할 수 있습니다.

4.3 필요한 패키지 설치

먼저, 필요한 패키지들을 설치합니다:

npm install mongoose
npm install -D @types/mongoose

4.4 데이터베이스 연결 설정

src/config/database.ts 파일을 생성하고 다음 코드를 작성합니다:

import mongoose from 'mongoose';

export const connectDB = async () => {
  try {
    await mongoose.connect('mongodb://localhost:27017/myapp');
    console.log('MongoDB connected');
  } catch (error) {
    console.error('MongoDB connection error:', error);
    process.exit(1);
  }
};

그리고 app.ts 파일에서 이 함수를 호출합니다:

import { connectDB } from './config/database';

// ... 기존 코드 ...

connectDB();

// ... 기존 코드 ...

4.5 모델 정의하기

이제 사용자 모델을 정의해 봅시다. src/models/user.ts 파일을 생성하고 다음 코드를 작성합니다:

import mongoose, { Schema, Document } from 'mongoose';

export interface IUser extends Document {
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

const UserSchema: Schema = new Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  createdAt: { type: Date, default: Date.now }
});

export default mongoose.model<iuser>('User', UserSchema);</iuser>

4.6 컨트롤러 만들기

이제 사용자 관련 로직을 처리할 컨트롤러를 만들어 봅시다. src/controllers/userController.ts 파일을 생성하고 다음 코드를 작성합니다:

import { Request, Response } from 'express';
import User, { IUser } from '../models/user';

export const createUser = async (req: Request, res: Response) => {
  try {
    const { name, email, password } = req.body;
    const user: IUser = new User({ name, email, password });
    await user.save();
    res.status(201).json(user);
  } catch (error) {
    res.status(500).json({ error: 'Error creating user' });
  }
};

export const getUsers = async (req: Request, res: Response) => {
  try {
    const users: IUser[] = await User.find();
    res.status(200).json(users);
  } catch (error) {
    res.status(500).json({ error: 'Error fetching users' });
  }
};

export const getUserById = async (req: Request, res: Response) => {
  try {
    const user: IUser | null = await User.findById(req.params.id);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    res.status(200).json(user);
  } catch (error) {
    res.status(500).json({ error: 'Error fetching user' });
  }
};

4.7 라우터 업데이트

이제 src/routes/users.ts 파일을 수정하여 새로 만든 컨트롤러를 사용하도록 합니다:

import express, { Router } from 'express';
import { createUser, getUsers, getUserById } from '../controllers/userController';

const router: Router = express.Router();

router.post('/', createUser);
router.get('/', getUsers);
router.get('/:id', getUserById);

export default router;

4.8 body-parser 미들웨어 추가

POST 요청의 body를 파싱하기 위해 body-parser 미들웨어를 추가해야 합니다. app.ts 파일에 다음 코드를 추가합니다:

import express, { Express } from 'express';
import bodyParser from 'body-parser';

// ... 기존 코드 ...

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// ... 기존 코드 ...

이제 우리의 Express.js + 타입스크립트 서버가 MongoDB와 연동되어 동작합니다! 🎉

 

이 서버는 다음과 같은 기능을 가지고 있습니다:

  • MongoDB 연결
  • 사용자 모델 정의
  • 사용자 생성, 조회 기능
  • MongoDB를 이용한 데이터 저장 및 조회

 

다음 섹션에서는 인증 기능을 추가하고, 테스트 코드를 작성하는 방법에 대해 알아보겠습니다. 계속해서 따라와 주세요! 💪

5. 인증 기능 구현: JWT를 이용한 사용자 인증 🔐

5.1 JWT 소개

JWT(JSON Web Token)는 웹 애플리케이션에서 사용자 인증을 위해 널리 사용되는 방식입니다. 토큰 기반 인증 시스템으로, 서버 측에서 상태를 유지할 필요가 없어 확장성이 뛰어납니다.

5.2 필요한 패키지 설치

JWT 관련 패키지를 설치합니다:

npm install jsonwebtoken bcrypt
npm install -D @types/jsonwebtoken @types/bcrypt

5.3 사용자 모델 업데이트

src/models/user.ts 파일을 수정하여 비밀번호 해싱 기능을 추가합니다:

import mongoose, { Schema, Document } from 'mongoose';
import bcrypt from 'bcrypt';

export interface IUser extends Document {
  name: string;
  email: string;
  password: string;
  createdAt: Date;
  comparePassword(candidatePassword: string): Promise<boolean>;
}

const UserSchema: Schema = new Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  createdAt: { type: Date, default: Date.now }
});

UserSchema.pre<iuser>('save', async function(next) {
  if (!this.isModified('password')) return next();

  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

UserSchema.methods.comparePassword = async function(candidatePassword: string): Promise<boolean> {
  return bcrypt.compare(candidatePassword, this.password);
};

export default mongoose.model<iuser>('User', UserSchema);</iuser></boolean></iuser></boolean>

5.4 JWT 유틸리티 함수 만들기

src/utils/jwt.ts 파일을 생성하고 다음 코드를 작성합니다:

import jwt from 'jsonwebtoken';
import { IUser } from '../models/user';

const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';

export const generateToken = (user: IUser): string => {
  return jwt.sign({ id: user._id }, JWT_SECRET, { expiresIn: '1d' });
};

export const verifyToken = (token: string): jwt.JwtPayload => {
  return jwt.verify(token, JWT_SECRET) as jwt.JwtPayload;
};

5.5 인증 미들웨어 만들기

src/middleware/auth.ts 파일을 생성하고 다음 코드를 작성합니다:

import { Request, Response, NextFunction } from 'express';
import { verifyToken } from '../utils/jwt';

export const auth = (req: Request, res: Response, next: NextFunction) => {
  const token = req.header('Authorization')?.replace('Bearer ', '');

  if (!token) {
    return res.status(401).json({ error: 'No token, authorization denied' });
  }

  try {
    const decoded = verifyToken(token);
    (req as any).userId = decoded.id;
    next();
  } catch (error) {
    res.status(401).json({ error: 'Token is not valid' });
  }
};

5.6 인증 컨트롤러 만들기

src/controllers/authController.ts 파일을 생성하고 다음 코드를 작성합니다:

import { Request, Response } from 'express';
import User, { IUser } from '../models/user';
import { generateToken } from '../utils/jwt';

export const login = async (req: Request, res: Response) => {
  try {
    const { email, password } = req.body;
    const user: IUser | null = await User.findOne({ email });

    if (!user) {
      return res.status(400).json({ error: 'Invalid credentials' });
    }

    const isMatch = await user.comparePassword(password);

    if (!isMatch) {
      return res.status(400).json({ error: 'Invalid credentials' });
    }

    const token = generateToken(user);
    res.json({ token });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
};

export const register = async (req: Request, res: Response) => {
  try {
    const { name, email, password } = req.body;
    let user: IUser | null = await User.findOne({ email });

    if (user) {
      return res.status(400).json({ error: 'User already exists' });
    }

    user = new User({ name, email, password });
    await user.save();

    const token = generateToken(user);
    res.status(201).json({ token });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
};

5.7 인증 라우터 만들기

src/routes/auth.ts 파일을 생성하고 다음 코드를 작성합니다:

import express, { Router } from 'express';
import { login, register } from '../controllers/authController';

const router: Router = express.Router();

router.post('/login', login);
router.post('/register', register);

export default router;

5.8 메인 앱에 인증 라우터 추가

app.ts 파일을 수정하여 인증 라우터를 추가합니다:

import express, { Express } from 'express';
import userRoutes from './routes/users';
import authRoutes from './routes/auth';
import { connectDB } from './config/database';

const app: Express = express();
const port = 3000;

connectDB();

app.use(express.json());
app.use('/api/users', userRoutes);
app.use('/api/auth', authRoutes);

app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

이제 우리의 Express.js + 타입스크립트 서버에 JWT를 이용한 인증 기능이 추가되었습니다! 🎉

 

이 서버는 이제 다음과 같은 기능을 가지고 있습니다:

  • 사용자 등록 및 로그인
  • 비밀번호 해싱
  • JWT 토큰 생성 및 검증
  • 보호된 라우트에 대한 인증 미들웨어

 

다음 섹션에서는 우리가 만든 API의 테스트 코드를 작성하는 방법에 대해 알아보겠습니다. 계속해서 따라와 주세요! 💪

6. 테스트 코드 작성: Jest를 이용한 단위 테스트 및 통합 테스트 🧪

6.1 Jest 소개

Jest는 Facebook에서 만든 JavaScript 테스팅 프레임워크로, 간단한 설정으로 빠르고 효율적인 테스트를 할 수 있습니다. 타입스크립트와의 호환성도 뛰어나 우리 프로젝트에 적합합니다.

6.2 필요한 패키지 설치

Jest와 관련 패키지들을 설치합니다:

npm install -D jest ts-jest @types/jest supertest @types/supertest

6.3 Jest 설정

프로젝트 루트에 jest.config.js 파일을 생성하고 다음 내용을 작성합니다:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootdir>/src'],
  testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
  transform: {
    '^.+\\.ts$': 'ts-jest',
  },
};</rootdir>

6.4 단위 테스트 작성

src/__tests__/unit/user.test.ts 파일을 생성하고 다음 코드를 작성합니다:

import User from '../../models/user';

describe('User Model Test', () => {
  it('should create & save user successfully', async () => {
    const userData = {
      name: 'Test User',
      email: 'test@example.com',
      password: 'password123'
    };
    const user = new User(userData);
    const savedUser = await user.save();
    
    expect(savedUser._id).toBeDefined();
    expect(savedUser.name).toBe(userData.name);
    expect(savedUser.email).toBe(userData.email);
    expect(savedUser.password).not.toBe(userData.password); // password should be hashed
  });

  it('should fail to save user with missing required field', async () => {
    const userWithoutRequiredField = new User({ name: 'Test User' });
    let err;
    try {
      await userWithoutRequiredField.save();
    } catch (error) {
      err = error;
    }
    expect(err).toBeInstanceOf(Error);
  });
});

6.5 통합 테스트 작성

src/__tests__/integration/auth.test.ts 파일을 생성하고 다음 코드를 작성합니다:

import request from 'supertest';
import { Express } from 'express';
import mongoose from 'mongoose';
import { createServer } from '../../app'; // 서버 생성 함수를 별도로 만들어야 합니다.

let app: Express;

beforeAll(async () => {
  app = await createServer();
});

afterAll(async () => {
  await mongoose.connection.close();
});

describe('Authentication Endpoints', () => {
  it('should register a new user', async () => {
    const res = await request(app)
      .post('/api/auth/register')
      .send({
        name: 'Test User',
        email: 'test@example.com',
        password: 'password123'
      });
    expect(res.statusCode).toEqual(201);
    expect(res.body).toHaveProperty('token');
  });

  it('should login an existing user', async () => {
    const res = await request(app)
      .post('/api/auth/login')
      .send({
        email: 'test@example.com',
        password: 'password123'
      });
    expect(res.statusCode).toEqual(200);
    expect(res.body).toHaveProperty('token');
  });
});

6.6 테스트 실행을 위한 스크립트 추가

package.json 파일의 "scripts" 섹션에 다음 내용을 추가합니다:

"scripts": {
  ...
  "test": "jest",
  "test:watch": "jest --watch"
}

6.7 테스트 실행

다음 명령어로 테스트를 실행할 수 있습니다:

npm test

또는 파일 변경을 감지하여 자동으로 테스트를 실행하려면:

npm run test:watch

이제 우리의 Express.js + 타입스크립트 서버에 테스트 코드가 추가되었습니다! 🎉

 

이 테스트 코드는 다음과 같은 기능을 검증합니다:

  • 사용자 모델의 생성 및 저장
  • 필수 필드 누락 시 에러 발생
  • 사용자 등록 API
  • 사용자 로그인 API

 

테스트 코드를 작성함으로써 우리는 애플리케이션의 신뢰성을 높이고, 버그를 조기에 발견할 수 있게 되었습니다. 또한 새로운 기능을 추가하거나 기존 코드를 수정할 때 더 자신감 있게 작업할 수 있게 되었습니다.

 

다음 섹션에서는 우리가 만든 서버를 실제 운영 환경에 배포하는 방법에 대해 알아보겠습니다. 계속해서 따라와 주세요! 💪

7. 배포: Docker와 AWS를 이용한 서버 배포 🚀

7.1 Docker 소개

Docker는 애플리케이션을 컨테이너화하여 개발, 배포, 실행을 쉽게 만들어주는 플랫폼입니다. 컨테이너를 사용하면 애플리케이션과 그 의존성을 하나의 패키지로 묶어 어떤 환경에서도 일관되게 실행할 수 있습니다.

7.2 Dockerfile 작성

프로젝트 루트에 Dockerfile을 생성하고 다음 내용을 작성합니다:

FROM node:14

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["node", "dist/app.js"]

7.3 .dockerignore 파일 작성

프로젝트 루트에 .dockerignore 파일을 생성하고 다음 내용을 작성합니다:

node_modules
npm-debug.log
dist

7.4 Docker 이미지 빌드

터미널에서 다음 명령어를 실행하여 Docker 이미지를 빌드합니다:

docker build -t my-express-app .

7.5 Docker 컨테이너 실행

다음 명령어로 Docker 컨테이너를 실행합니다:

docker run -p 3000:3000 my-express-app

7.6 AWS EC2 인스턴스 생성

  1. AWS 콘솔에 로그인합니다.
  2. EC2 대시보드로 이동합니다.
  3. "인스턴스 시작" 버튼을 클릭합니다.
  4. Amazon Linux 2 AMI를 선택합니다.
  5. 인스턴스 유형을 선택합니다 (예: t2.micro).
  6. 보안 그룹 설정에서 SSH (22번 포트)와 HTTP (80번 포트) 접근을 허용합니다.
  7. 새 키 페어를 생성하고 다운로드합니다.
  8. "인스턴스 시작" 버튼을 클릭합니다.

7.7 EC2 인스턴스에 Docker 설치

SSH를 사용하여 EC2 인스턴스에 접속한 후, 다음 명령어를 실행하여 Docker를 설치합니다:

sudo yum update -y
sudo amazon-linux-extras install docker
sudo service docker start
sudo usermod -a -G docker ec2-user

7.8 EC2 인스턴스에 애플리케이션 배포

  1. 로컬 머신에서 Docker 이미지를 Docker Hub에 푸시합니다:
docker tag my-express-app your-dockerhub-username/my-express-app
docker push your-dockerhub-username/my-express-app
  1. EC2 인스턴스에서 다음 명령어를 실행하여 Docker 이미지를 가져오고 실행합니다:
docker pull your-dockerhub-username/my-express-app
docker run -d -p 80:3000 your-dockerhub-username/my-express-app

7.9 도메인 연결 (선택사항)

  1. 도메인 이름을 구매합니다 (예: AWS Route 53 사용).
  2. EC2 인스턴스의 퍼블릭 IP 주소를 도메인 이름에 연결합니다.

이제 우리의 Express.js + 타입스크립트 서버가 AWS EC2 인스턴스에 성공적으로 배포되었습니다! 🎉

 

이 배포 과정을 통해 우리는 다음과 같은 것들을 달성했습니다:

  • Docker를 이용한 애플리케이션 컨테이너화
  • AWS EC2 인스턴스 생성 및 설정
  • Docker Hub를 이용한 이미지 공유
  • 실제 운영 환경에 애플리케이션 배포

 

이로써 우리는 Express.js와 타입스크립트를 이용한 백엔드 개발부터 배포까지의 전체 과정을 완료했습니다. 이 과정에서 우리는 현대적인 백엔드 개발의 핵심 기술들을 다루었고, 실제 운영 환경에 배포할 수 있는 안정적이고 확장 가능한 서버를 구축했습니다.

 

앞으로 여러분은 이 지식을 바탕으로 더 복잡하고 규모가 큰 프로젝트에도 도전할 수 있을 것입니다. 계속해서 학습하고 경험을 쌓아가며, 더 나은 개발자로 성장하시기 바랍니다. 화이팅! 💪