[따라하며 배우는 도커와 CI 환경] 복잡한 어플 실제로 배포해보기 (개발 환경 부분)

Jimin Lim·2022년 6월 24일
0

Docker

목록 보기
8/9
post-thumbnail

✅ 설계

Nginx로 클라이언트에서 오는 요청을 백엔드 서버와 프런트 서버로 나눠주는 구조로 설계한다.

✅ Node JS 구성

🔗 backend 폴더를 만들어 준 후 backend 폴더로 이동, npm init 명령 실행

🔗 필요한 dependency 추가

{
  "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"
  }
}

🔗 mysql 연결

const mysql = require("mysql");
const pool = mysql.createPool({
    connectionLimit: 10,
    host: 'mysql',
    user:'root',
    password: 'password',
    database: 'myapp'
});

exports.pool = pool;

🔗 간단한 api 작성

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번 포트에서 시작되었습니다.")
})

✅ Node.js를 위한 도커 파일 작성

#Base Image
FROM node:alpine

WORKDIR /app

COPY ./package.json ./

RUN npm install

COPY . .

CMD ["npm", "run", "start"]

✅ DB 구성

실제 운영 배포에서는 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

✅ nginx 구성

🔗 설정 파일 작성

#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: 이 부분이 없다면 에러 발생

🔗 Dockerfile 작성

MySQL과 유사하게 도커파일을 작성해준다.

FROM nginx
COPY ./default.conf  /etc/nginx/conf.d/default.conf

✅ Docker Compose 작성

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 컨테이너의 포트 번호를 바꿔주도록 하였다.

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글