Nginx로 클라이언트에서 오는 요청을 백엔드 서버와 프런트 서버로 나눠주는 구조로 설계한다.
npm init
명령 실행{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js",
"dev": "nodemon server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.3",
"mysql":"^2.16.0",
"nodemon":"1.18.3",
"body-parser":"1.19.0"
}
}
const mysql = require("mysql");
const pool = mysql.createPool({
connectionLimit: 10,
host: 'mysql',
user:'root',
password: 'password',
database: 'myapp'
});
exports.pool = pool;
const express = require("express");
const bodyParser = require('body-parser');
const db = require('./db');
const { query } = require("express");
const app = express()
//json 형태로 오는 요청의 본문 해석
app.use(bodyParser.json());
//테이블 생성
db.pool.query(`CREATE TABLE lists(
id INTEGER AUTO_INCREMENT,
value TEXT,
PRIMARY KEY (id)
)`)
//DB lists 테이블에 있는 모든 데이터를 프론트 서버에 보내준다.
app.get('/api/values', function(req, res){
db.pool.query(`SELECT * FROM lists;`,
(err, results, fileds) => {
if(err)
return res.status(500).send(err)
else
return res.json(results)
})
})
//클라이언트에서 입력한 값을 DB lists에 넣도록 한다.
app.post('/api/value', function(req, res, next){
//DB에 값 넣어준다.
db.pool.query(`INSERT INTO lists (value) VALUES("${req.body.value}")`,
(err, results, fileds) => {
if(err)
return res.status(500).send(err)
else
return res.json({success: true, value: req.body.value})
})
})
app.listen(5000, () => {
console.log("애플리케이션이 5000번 포트에서 시작되었습니다.")
})
#Base Image
FROM node:alpine
WORKDIR /app
COPY ./package.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "start"]
실제 운영 배포에서는 RDS를 사용하지만, 개발에 사용할 MySQL 이미지를 만들기 위한 도커 파일을 작성하도록 한다.
FROM mysql:5.7
#인코딩 설정을 덮어씌운다
ADD ./my.cnf /etc/mysql/conf.d/my.cnf
#도커 호환성 문제로 추가해준다.
FROM --platform=linux/x86_64 mysql:5.7
#my.cnf
[mysqld]
character-set-server=utf8
[mysql]
default-character-set=utf8
[client]
default-character-set=utf8
#default.cnf
upstream frontend {
server frontend:3000;
}
upstream backend {
server backend:5000;
}
server {
listen 80;
location / {
proxy_pass http://frontend;
}
location /api {
proxy_pass http://backend;
}
location /sockjs-node {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
upstream
: 각 포트에서 돌아가고 있음을 명시해준다.listen 80
: nginx 서버 포트를 80번으로 열어준다.location /
: 들어오는 요청을 url에 맞게 매핑해준다.location /sockjs-node
: 이 부분이 없다면 에러 발생MySQL과 유사하게 도커파일을 작성해준다.
FROM nginx
COPY ./default.conf /etc/nginx/conf.d/default.conf
version: '3'
services:
frontend:
build:
dockerfile: Dockerfile.dev #개발 환경을 위한 도커 파일 위치 찾아준다.
context: ./frontend
volumes:
- /app/node_modules #코드를 수정 후 다시 이미지를 build 하는 것 없이 수정된 코드가 반영이 될 수 있게 volume 이용
- ./frontend:/app
stdin_open: true #에러를 보여주도록 한다.
nginx:
restart: always #서버가 꺼진다면 항상 재시작을 해준다.
build:
dockerfile: Dockerfile
context: ./nginx
ports:
- "3000:80"
backend:
build:
dockerfile: Dockerfile.dev
context: ./backend
container_name: app_backend
volumes:
- /app/node_modules
- ./backend:/app
mysql:
build: ./mysql
restart: unless-stopped #개발자가 임의로 멈추려고 할때 제외, 항상 재시작
container_name: app_mysql
ports: # 접근 포트 설정 (컨테이너 외부:컨테이너 내부)
- "3306:3306"
volumes: #{로컬파일}:{도커파일} 참조해주도록 한다
- ./mysql/mysql_data:/var/lib/mysql
- ./mysql/sqls/:/docker-entrypoint-initdb.d/
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: myapp
docker-compose up --build
를 실행해주면 아래와 같은 오류가 발생하였다.
for mysql Cannot start service mysql: Ports are not available: listen tcp 0.0.0.0:3306: bind: address already in use
따라서 실행 중인 프로세스를 kill 해주고자 다음과 같은 명령을 해주었다.
docker stop $(docker ps -a -q) #docker 컨테이너 중지
docker rm -fv $(docker ps -aq) #docker 컨테이너 삭제
sudo lsof -i -P -n | grep 3306 #3306 포트 번호를 잡고 있는 프로세스 조회
sudo kill -9 {PID} #PID로 kill
하지만 3306 포트를 listen하는 프로세스(mysql)이 계속 생성(?) 되어서 그냥 mysql 컨테이너의 포트 번호를 바꿔주도록 하였다.