반응형

이미지 압축 및 s3 업로드는

정말 많이 쓰이지만 의외로 포스팅이 없어

간단히 정리해본다.

 

 

처리절차

1. 클라이언트 요청 (생략)

2. multer-s3로 aws 업로드

3. key로 s3 object를 불러와 압축 후 재 업로드

4. 기존 파일 key로 제거

 

 

1. 클라이언트 요청 (생략)

요청은 포스트맨(Postman)으로 요청,

테스트하면 됨으로 생략 (form-data 방식 활용)

 

 

2. multer-s3로 aws 업로드

express router에서 미들웨어 처리를 해줄것이다.

그전에 multer-s3 미들웨어를 만들어주자.

// aws.ts
const AWS = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');

const aws_config = {
    accessKeyId: process.env.AWS_ACCESS_KEY,
    secretAccessKey: process.env.AWS_SECRET_KEY,
    region: 'ap-northeast-2',
    signatureVersion: 'v4',
};

export const s3 = new AWS.S3();

export const uploadImage = multer({
  storage: multerS3({
    s3,
    bucket: 'test.bucket',
    metadata: (req, file, cb) => {
      cb(null, { fieldName: file.fieldname });
    },
    key: (req, file, cb) => {
      const ext = path.extname(file.originalname);
      const timestamp = new Date().getTime().valueOf();
      const filename = 'test' + timestamp + ext;
      cb(null, filename);
    },
  }),
});

이제 사용자 요청을 받는 router부분에서

uploadImage를 미들웨어로 넣어주면 된다.

// image.router.ts
router.post('/image/upload', uploadImage.single('photo'), (req, res) => {
  ...
})

 

 

3. key로 s3 object를 불러와 압축 후 재 업로드 & 기존 파일 key로 제거

uploadImage 처리 후 req.file에서

업로드된 이미지 객체의 key를 확인할 수 있다.

 

이 key를 활용해 객체를 불러와

압축하여 재업로드 및 삭제를 진행할것이다.

 

// aws.ts
export const compressImageUploadByKey = async (key: string, width?: number) => {
  try {
    const compressedKey = `compressed_${key}`;
    const config = {
      Bucket: 'test.bucket',
      Key: key
    }
        
    let resizedConfig: any = {
      Bucket: 'test.bucket',
      Key: compressedKey
    }

    // fetch
    const imageData: any = await s3.getObject(config).promise();

    // resizing
    const imageBuffer = await sharp(imageData.Body).resize({ width: width || 640 }).toBuffer();
    resizedConfig.Body = imageBuffer;
    
    // upload
    await s3.putObject(resizedConfig).promise();

    // origin image delete
    await s3.deleteObject(config).promise();

    return compressedKey;
  } catch(error) {
    console.log('Get image by key from aws: ', error);
  }
}

불러오고, 압축하고, 업로드하고, 지우고

4가지 작업이 진행되었다.

 

 

새로 업로드된 이미지의 Key를

DB에 저장하거나 하는 작업을 

각 작업 환경에 맞게 진행하면 끝

반응형
반응형

"늘 그랬듯이"

라는 생각은 개발자에게 치명적이다.

 

그 현상을 더 이상

해결해야될 문제로 보지않고

안주하게 만들어버린다.

 

나에게 server.js 스크립트는

그런 대상이다.

 

수 많은 MVP 모델을 만들면서

server.js를 어떻게 구조화할지는

크게 고민하지않앗다.

 

express가 너무나도 쉽게 서버를 만들어주기에

필요할때 route만 더 붙여준다던지

cors를 설정해준다던지 하면 끝이었다.

 

// server.js
const express = require('express');
const api_v1 = require('../api/v1');

const app = express();
const http = require('http').createServer(app);

app.use('/api/v1/', api_v1);
http.listen(process.env.PORT, () => {
  console.log('server is listening on', process.env.PORT);
});

 

간단하게는

이정도면 충분히 훌륭한 앱서버가 된다.

 

문제는

서버에서 담당하는 역할이 많아지면서

여러가지가 붙다보면

코드가 지저분해지고

더이상 보기 싫은 스크립트가 되어버린다.

 

// server.js
const express = require('express');
const { Server } = require('socket.io');
const api_v1 = require('../api/v1');
const config = require('./config/server');

const app = express();
const http = require('http').createServer(app);
const io = new Server(http, {});

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

app.use(function (req, res, next) {
  const allowedOrigins = config.allowedOrigin;
  const origin: any = req.headers.origin;
  if (allowedOrigins.indexOf(origin) > -1) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }
  res.header('Access-Control-Allow-Headers', 'Authorization, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS,PATCH');
  res.header('Access-Control-Allow-Credentials', 'true');
  req.method === 'OPTIONS' ? res.sendStatus(200) : next();
});

app.use('/api/v1/', api_v1);

io.sockets.on('connection', (socket) => {
  console.log('socket is connected..!');
});

http.listen(process.env.PORT, () => {
  console.log('server is listening on', process.env.PORT);
});

 

이정도만 되어도 보기싫어지기 시작한다.

우리는 class로 스크립트를 새로 짜보도록 하자.

 

// server.js
const express = require('express');
const { Server, createServer } = require('http');
const { Server as ioServer } = require('socket.io');
const api_v1 = require('../api/v1');
const config = require('./config/server');

const app = express();
const http = require('http').createServer(app);
const io = new Server(http, {});

class Server {
  private app: express.Aplication;
  private server: Server;
  private io: ioServer;
  
  constructor() {
    this.createApp();
    this.createServer();
    this.sockets();
    this.configure();
    this.routes();
    this.listen();
  }
  
  private createServer = (): void => {
    this.server = createServer(this.app);
  }
  
  private createApp = (): void => {
    this.app = express();
  }
  
  private sockets = (): void => {
    this.io = new ioServer(this.server);
  }
  
  private routes = (): void => {
    app.use('/api/v1/', api_v1);
  }
  
  private configure = (): void => {
    app.use(express.urlencoded({ extended: true }));
    app.use(express.json());
    app.use(cookieParser());

    app.use(function (req, res, next) {
      const allowedOrigins = config.allowedOrigin;
      const origin: any = req.headers.origin;
      if (allowedOrigins.indexOf(origin) > -1) {
        res.setHeader('Access-Control-Allow-Origin', origin);
      }
      res.header('Access-Control-Allow-Headers', 'Authorization, X-Requested-With, Content-Type, Accept');
      res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS,PATCH');
      res.header('Access-Control-Allow-Credentials', 'true');
      req.method === 'OPTIONS' ? res.sendStatus(200) : next();
    });
  }
  
  private listen = (): void => {
    this.server.listen(process.env.PORT, () => {
      console.log('server is listening on', process.env.PORT);  
    });
    
    io.sockets.on('connection', (socket) => {
      console.log('socket is connected..!');
    });
  }
}

const App = new Server();

 

이렇게 정리해놓고 보니

목적에 맞는 코드끼리 분리되어

유지보수가 확실히 수월해진듯한 느낌이든다.

 

코드를 짤때는 내 코드를

함께 공유할 개발자도 배려하는 자세를 갖도록 해야겠다.

반응형
반응형

pm2를 이용해서

앱서버를 백그라운드 환경으로 운영이 가능하다.

 

여기서 한발 더 나아가

cluster mode로 실행중인 node.js서버를

pm2를 이용해 돌리곤 했었다.

 

하지만 배포할때마다 일시적으로 중단되어버리는 서버.

원인은 restart로 배포하기때문.

 

reload 명령어를 통해

kill -> restart

reset 형식으로 서버 중단없이

무중단 배포가 가능하다.

pm2 reload index.js

 

근데 이를 제대로 활용하려면

몇가지 설정이 필요하다

 


 

pm2 ecosystem

 

위 명령어로 ecosystem.config.js 파일을 얻을수 있다.

다양한 설정들이 기본으로 세팅되어있는데

docs를 보면서 입맛에 맞게 설정하면 된다.

 

진짜 간단히는

module.exports = {
    apps: [
        {
            name: 'server',
            script: './index.js',
            watch: '.',
            instances: -1, // 클러스터 모드
            // exec_mode: 'cluster', <-- 이것도 클러스터 모드
        },
    ],
};

이렇게만 설정해도 된다

 

package.json을 수정하면

npm 명령어로 서버에서

간편히 실행 혹은 reload 하는것도 가능하다.

scripts: {
  "start": "pm2 start ./ecosystem.config.js --only server",
  "reload": "pm2 reload server"
}

 

고객에게 불편을 주지말자

 


여기서 더 나아간다면

실행중인 process가 덮어씌워지는 경우를

방지하고

reload할 수 있다.

 

// server.js

const app = express();


let disableKeepAlive = false;

// 중단이 감지되면 Keep 상태인 요청 닫음
app.use((req, res, next) => {
    if (disableKeepAlive) {
        res.set('Connection', 'close');
    }
    next();
});

const service = app.listen(process.env.PORT, () => {
    console.log(`The application is listening on port ${process.env.PORT}`);
    if (process.send) {
        console.log('send')
        process.send('ready');
    }
});

process.on('SIGINT', async () => {
    disableKeepAlive = true;
    service.close();
    process.exit(0);
});

이런식으로 구성해주면 된다.

반응형
반응형

next.js를 next install 하여

 

out 폴더를 그대로 배포하면 

 

새로고침 후 index페이지로 이동된다거나

 

~~~/register 와 같이 페이지에 접속했을때도 index페이지가 보여지는 등의 이슈가 발생한다

 

이를 해결하기 위해서는

 

node 서버에서 next.js앱을 실행해주어야한다.

 

node server 설정은

 

const { application } = require('express');
const express = require('express');
const next = require('next');

const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const handle = nextApp.getRequestHandler();

nextApp
    .prepare()
    .then(() => {
        const app = express();

        app.get('*', (req, res) => {
            return handle(req, res);
        });

        app.listen(3000, err => {
            console.log('>>> server is ready on port 3000');
        });
    })
    .catch(err => {
        console.log(err);
        process.exit();
    });

 

이렇게 간단히 할수있고

 

실행은

 

node server.js 이다

 

pm2를통해 무중단 배포를 할때는

 

// package.json

"start": node server.js

 

// 실행

pm2 start npm --name 'next' -- start

반응형
반응형

기획 및 자료조사

오늘 신규 서비스에 대한 아이디어가 나왔고

제품을 만들어 보기로했습니다.

서비스 컨셉과 간략한 기획을 기반으로

필요 기술과 적정 수준 (개발 노고에 대한)에

따라 아키텍쳐를 정의하였습니다.

 

정의

1. 주요 기능 정리

2. 아키텍쳐

3. 라이브러리 (예상)

 

 

위 3가지 큰 틀 안에서 서비스를

명세하였고, 관련해서 충분히 레퍼런스는 있는지

저작권이나 비용적으로 문제는 없는지를

파악하였습니다.

 

Next.js + Node.js + Mongo

결론은 크게 위 3가지로 방향을 잡았습니다.

어디로 튈지 모르는 스타트업 서비스의 특성상

mongo는 정말 찰떡이 아닌가 싶습니다.

 

이전과 다르게 이번 서비스는 SEO와

Scale-Up이 중요하다 판단되어

언제든 새 팀원이 추가되어도 쉽게 적용할수있게

골격이 어느정도 잡혀있다고 하는

Next.js를 채택하기로 하였습니다.

 

API서버로는 Node.js를 채택하였는데,

요구사항을 맞추는데 전혀 문제가 없고

개발 비용면에서도 익숙한 환경이라는 점에서

효율적이기 때문에 선택하게 되었습니다.

특히, Next.js도 처음 도입하는 마당에

서버까지 낯선 환경에 빠지게되면

큰 비용으로 기업이라는 배가 침몰하게되지는

않을까 하는 생각까지 들었습니다. (오바좀 보태서)

 

새로운 프로젝트를 만들어 나가며

어떤 문제 상황들을 맞딱드리는지

위 기술들이 어떤지에대해 주관적인 의견과

역경들을 남겨보도록 하겠습니다.

반응형

'개발, 코딩' 카테고리의 다른 글

git 협업하기 - 실무편  (0) 2022.10.23
Webpack 구성 이해하기  (0) 2022.10.04
Rest API 정리  (0) 2022.09.29
java zulu jdk11 설치  (0) 2022.07.31
M1 Mac, homebrew install (Warning: /opt/homebrew/bin is not in your PATH.)  (0) 2022.07.31
반응형

< 1탄 - 프롤로그 >

웹,앱 등의 서비스에서 광고 수익외에

직접적인 수익을 창출하려면 결제연동을 필수적으로 하게됩니다.

그 과정에서 어려움을 겪게되는대요.

 

주로 그 원인은

PG사들이 제공하는 가이드라인이

부실하기 때문입니다.

 

사실 부실할 수 밖에 없은 이유가있죠.

이제는 너무나도 다양해진 개발 환경에 

모두 대응되는 가이드라인을 제공할 수 없기 때문입니다.

 

이번에 React 프로젝트에 결제연동을 하다보니

react와 같은 CSR에 대해서는 가이드라인이 부실함은 물론

관련 자료도 매우 부족함을 알게되었습니다.

 

미약하지만

아임포트 같은 서비스없이

KG이니시스 결제모듈 연동에 성공하여 정보를 공유하고자합니다.

 

다룰 내용은

Client : React 

server : node js

PG: inicis
결제수단 : 가상계좌 ( 다른 결제수단도 PG사와 제휴만 맺으면 해당 방법으로 얼마든지 응용가능해보입니다.)

 

해당 상황에 해당하시는분들에게

많은 도움이 됐으면 합니다.

감사합니다.

반응형
반응형

base64? buffer? stream?

일반적으로 자주 사용하지는 않으나

파일 처리를 할때면 나타나 곤란한 상황을 만드는 녀석들이다.

 

이번에 우연한기회에

AWS에 업로드된 파일 URL을 노출시키지 않으면서

클라이언트에서 파일을 내려받게 해줘야하는 상황이 발생했다.

 

해당 과정에서 삽질하며 얻은 조각 지식들을 공유한다.

 

[ 가정 ]

1. 클라우드 저장소에 파일이 있다.

2. 클라이언트에서 파일 다운로드 요청 발생.

3. 서버에서 해당 파일을 불러온다.

4. 클라이언트에 해당 파일을 전송한다.

5. 다운로드 실시

 

1.  클라우드 저장소에 파일이 있다.

- AWS의 S3에 특정 파일이 저장되어있는 상황입니다.

- 해당 파일은 비문은 아니지만 공유를 원치않아 파일의 링크는 노출되지 않기를 원합니다.

- 마찬가지로 해당 파일의 버킷은 퍼블릭 버킷이 아닙니다.

- 따라서, 허가된 key를 가진 사용자만 파일을 호출할 수 있습니다. (즉, 서버에서만 요청 가능)

 

2. 파일을 필요로 하는 클라이언트는 지정된 서버로 요청을 보냅니다.

- 지정된 서버는 당연히 해당 AWS계정의 접근권한, key를 가진 서버겠죠.

 

3. 서버는  S3로부터 파일을 가져옵니다.

const AWS = require('aws-sdk')

const confg = {
  accessKeyId: '',
  scretAccessKey: '',
  region: '',
  signatureVersion: 'v4',
};

AWS.config.update(config);
const S3 = new AWS.S3();

function getObjectFromS3(key_name) {
  return new Promise((resolve, reject) => {
    S3.getObject({ Bucket: '', Key: key_name }, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    })
  });
}

 

getObjectFromS3를 이용하면 쉽게 파일을 읽어올 수 있습니다.

자, 지금부터가 집중이 필요합니다.

불러온 데이터는 JSON 형태인데

파일은 Body에 Buffer형태로 따라옵니다.

 

이, Buffer를 어떤식으로 클라이언트로 반환해줄건지

이걸 받으려면 클라이언트는 어떻게 해야하는지

주목해야합니다.

 

다시, 돌아가 클라이언트에서 파일을

어떻게 요청해야되는지 살펴봅시다.

 

4. 클라이언트에서 서버에 특정 파일 요청하기

const requestPrivateFile = () => {
  axios.post(url, {}, { responseType: 'arrayBuffer' })
  .then(resp => {
    const { data } = resp;
    console.log(data);
    ...
  });
}

 

자, 일반적인 API요청과 다르게  responseType으로 arrayBuffer을 지정해주었습니다.

이걸 놓치면 백날 삽질해도 소용없습니다.

 

서버에서도 그러면 값을 맞춰서 반환해줘야겠죠?

 

5. 서버에서 불러온 파일 반환해주기

const getPrivateFile = async (req, res) => {
  ...
  
  const file = await getObjectFromKey('something.pdf');
  
  res.writeHead(200, [ 
    ['Content-Type', 'application/pdf'], //  다른 형식의 파일이면 알맞는 mime/type을 지정해주세요.
  ]);
  res.end(Buffer.from(file.Body, 'base64'));
}

sendFile이나 send 등이 아니라 위와 같은 방식으로

파일을 리턴해주게됩니다.

 

6. 자, 그러면 파일을 받아서 한번 다운로드해볼까요?

const requestPrivateFile = () => {
  axios.post(url, {}, { responseType: 'arrayBuffer' })
  .then(resp => {
    const { data } = resp;

    downloadFile(data, 'something.pdf');
  });
}

function downloadFile(buffer, filename) {
  const blob = new Blob([buffer], { type: 'application/pdf' });
  const url = window.URL.createObjectURL(blob);
  
  const a = document.createElement('a');
  a.download = filename; // download될때의 파일명을 지정해줍니다.
  a.href = url;
  
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a); // 더 이상 필요없으므로 삭제
}

 

자, 여기까지 "서버로부터 buffer 형식으로 파일 전송받아 처리하기"를 해보았습니다.

알고나면 간단하지만 모를때는 조각조각 흩어져있는

토막지식들로인해 어려움을 주는 사항이었습니다...

 

여러가지 상황에 응용이 가능하니 알아두면 좋을것같습니다.

반응형
반응형

nodejs에서 pdfjs-dist 라이브러리를 사용하기위해 canvas가 필요했다.

(pdfjs가 canvas에 의존적이기 때문)

 

그런데 linux기반 서버에서 canvas설치 후 실행시 다음과 같은 에러가났다.

Cannot find module '../build/Release/canvas'

 

한참을 헤맸다.

node-gyp rebuild니 permission 에러니...

 

정답은 늘 가까이에 있고, 많이 사용하는 라이브러리는 늘 답안이 나와있다. (감사해요 stackoverflow)

I just use "npm uninstall canvas" and then install using "npm i canvas"

 

이 단 한줄의 문장으 내 머리를 후려쳤다.

생각해보니 canvas에서 지시한 지시사항을 실행하기 전에 canavs를 먼저 설치한것이다.

 

sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev

 

위는 canvas에서 ubuntu환경일 경우 먼저 설치하라고 안내해준 library들이다.

 

나는 이미 진행했으므로

npm uninstall canvas
npm install canvas

 

canvas를 다시 설치해주는것만으로 해결되었다.

 

pdfjs는 pdf to png작업을 위해 사용하였는데, 곧 관련내용을 정리해볼 예정이다.

반응형
반응형

Rest API서버와 DB서버가 각기 다른 서버에서 운영되는건 매우 흔한일이며

지극히 정상적인 일이라고 볼수있다.

 

서비스의 규모가 절대로 커질일이 없는것이 아니라면 일단은 분리하는게 좋다는 생각이다.

그럼에도 개발속도와 편의성 측면에서 한 서버에서 API서버와 DB를 운영하고는 하는데 (제가 그랬습니다...)

 

두 서버를 분리시키고 데이터 마이그레이션하는 방법에대해 소개하도록 하겠습니다.

 

 

1.  DB서버 생성 및 몽고 환경 셋업

이 부분에서 사실 제일많은 시간비용이 소모됩니다.

왜냐면 1~10까지 구구절절 설명해주는 자료가 많이 부족하기 때문이죠.

 

아래와 같은 작업을 해야합니다.

1) EC2환경설정

2) 몽고디비 설치

3) 몽고디비 실행

4) 몽고디비 관리자 계정 설정 및 readwrite계정 추가

5) .conf파일 수정

6) 몽고디비 재실행

7) DB서버에 연결 테스트

8) 데이터 덤프 및 마이그레이션

 

1) EC2환경설정

여기서 할것은 보안그룹설정인데요

몽고의 기본포트인 27017포트를 개방해줍니다.

 

 

2) 몽고디비 설치

각 OS마다 설치방법은 다르지만, 설치와 관련해서는 Mongo에서 매우 친절하게 안내해주고있으니 참고하시기 바랍니다

docs.mongodb.com/manual/installation/

 

 

3) 몽고디비 실행

실행, 정지, 재실행, 상태확인에 대해서 간단히 명령어를 알아보도록 하겠습니다.

두가지 버전이 있는데요, systemctl / service 두개의 키워드를 통해 가능합니다.

 

(실행) stystemctl start mongod

(중지) systemctl stop mongod

(재실행) systemctl restart mongod

(상태확인) systemctl status mongod

 

일단 설치했으면 실행해줍니다.

systemctl status mongod 를 입력해 정상적으로 동작중이며, mongo를 입력했을때 몽고디비로 진입된다면

잘 설치 및 실행되었다고 볼 수 있습니다

 

 

4) 몽고디비 관리자 계정 설정 및 readwrite계정추가

여기서 많이 헤매게됩니다.

기본적으로 로컬에 있는 몽고에서는 해주지않아도 되는데 (단, 하지않았을때 보안의 위험이있습니다)

리모트 서버의 DB에 연결하려면 반드시 계정설정을 해주어야됩니다.

외부에서 연결을 요청하면 몽고에서 사용자 권한을 확인하기 때문입니다.

 

먼저, 관리자 계정을 생성해주어야합니다.

관리자 계정이란 정말로 슈퍼어드민을 의미하며 DB를 드랍,추가 하는것까지 가능하니 계정관리에 주의해야합니다.

 

몽고에는 기본적으로 admin이라는 db가 생성되어있는데요. 다음과 같은 절차를 밟도록 하겠습니다.

가) admin db 사용: use admin

나) 어드민 계정 생성: db.createUser({ user: 'admin', pwd: '패스워드', roles: [{ role: 'root', db: 'admin' }] })

다) 생성된 계정 확인: db.getUser('admin')

라) 일반 readwrite계정 생성: db.createUser({ user: 'manager', pwd: '패스워드', roles: [{ role: 'readWrite', db: 'myFirstDb' }, { role: 'readWrite', db: 'mySecondDb' } ] })

마)  생성된 계정 확인: db.getUser('manager')

 

 

5) .conf 파일 설정

거의 다 왔습니다. 리모트에서 연결해주기 위해서는 보안설정을 셋업한 상태로 몽고를 실행해주어야만 합니다.

방법은 두가진데요. 제가 확실히 말씀드릴수 있는건 .conf 파일 설정이니 이것을 따르시길 추천드립니다.

 

mongod.conf 파일은 기본적으로 /etc/mongod.conf 경로에 생성됩니다.

몽고를 설치했지만 해당위치에 mongod.conf파일이 보이지 않는다면 찾아보시기 바랍니다.

 

mongod.conf 파일에서 아래의 파트를 정확하게, 아주 똑같이 작성합니다.

 

net:
  port: 27017
  bindIp: 0.0.0.0

 

security:
  authorization: enabled

 

(mongod --auth 라는 방법도 있다는데 제가 확신할수없어 아주 개인적으로 권장하지 않습니다.)

 

여기서 0.0.0.0은 모든 IP에서의 요청을 받겠다는 의미인데, 보안계정을 생성해주었으니 믿고 가도록 합니다.

API서버 주소인 13.x.x.x,192.x.x.x 등을 입력할수도 있다고 하지만 에러가 나는 경험을 했습니다.

관련하여 아시는 분이 있다면 댓글 부탁드립니다.

 

 

6) 몽고디비 재실행

systemctl restart mongo

 

재실행 했다면 반드시 상태도 확인해주세요

systemctl status mongo

 

여기까지 잘 되셨나요?

 

 

7) DB서버에 연결 테스트

자, 대망의 연결 테스트입니다.

로컬 서버에서 테스트하셔도 전혀 무방합니다.

 

연결 주소는 아래와 같이 작성합니다.

mongod://아이디:패스워드@도메인혹은아이피:27017/디비명

 

예제입니다.

mongod://manager:openpassword@cup.camil.com:27017/coffee

 

API서버에서 직접 연결을 체크해봐도 좋고

MongoBB Compass같은 툴을 통해 연결을 시도해 봐도 괜찮은 방법입니다.

후자의 경우 다른 코드에서 발생하는 에러와 분리하여 테스트할 수 있다는 장점이 있습니다.

 

 

8) 데이터 덤프 및 마이그레이션

여기는, 기존의 DB가 있는경우에만 진행해주시면 됩니다.

 

기존의 API서버에서 먼저 데이터를 덤프하는데요, 덤프란 기존의 데이터를 백업하기위해 카피한다고 생각하시면 됩니다.

BSON 타입으로 하는방법과 JSON 타입으로 하는방법 2가지가 있는데요.

여기서는 속도가 더 빠르다고하는 BSON 타입을 채택하여 진행하도록 하겠습니다.

 

아래의 명령어를 사용하면 내 현재 위치(경로)에 dump라는 폴더 내에 데이터가 덤프가 됩니다.

mongodump --host 127.0.0.1 --out /data/db/backup

 

덤프된 데이터를 FileZila와 같은 프로그램을 이용해 새 DB서버로 이전해줍니다.

이 때, 덤프된 파일들을 어디로 이전하는지 정확히 위치를 체크하도록 합니다.

 

* /home/root/  정도의 경로에 backups폴더를 생성하여 이전하는것을 추천드립니다.

 

데이터를 옮겼다면, 콘솔에서 해당 경로로 이동합니다.

위와 같이 했다면

cd /home/root/backups

가 되겠죠?

 

마지막입니다. 데이터 마이그레이션을 진행해주면 되는데요, 지금 디비가 텅텅 비어있으니 간단히 처리할 수 있습니다.

단, 진행 전 잠시 mongod.conf 파일의 security파트를 주석처리 하도록 합니다.

 

#security:
  #authorization: enabled

 

systemctl restart mongo

systemctl status mongo

 

몽고의 상태가 정상이라면 마이그레이션을 진행합니다.

mongorestore --host 127.0.0.1 --port 27017 --db 복구하려는 db명 덤프된 디렉터리 위치

 

예제입니다.

mongorestore --host 127.0.0.1 --port 27017 --db coffee ./coffee

 

*********** 수정***********

덤프될 디렉터리 위치를 잡을 필요없이 간단히 아래와 같이 복원가능합니다.

mongorestore -d db db

************************************

 

정상적으로 마이그레이션 됐는지를 먼저 체크해볼까요?

mongo

show databases

>> coffee DB가 존재하나요?

 

use coffee

show collections

>> collection들은 잘 이전되었나요?

 

잘 되었다면 다시 security설정을 해줍니다.

 

security:
  authorization: enabled

 

systemctl restart mongo

systemctl status mongo

 

 

============================

 

고생하셨습니다. 여기까지입니다.

이 글이 몽고 원격 연결 및 마이그레이션의 성지가 되기를 바라며

부족한 글 많은 분들의 댓글로 꽉꽉 채워지기를 바라겠습니다.

 

반응형
반응형

암호화에는 대칭키와 비대칭키 방식이 있다.

 

대칭키 방식은 암호화와 복호화에 같은 키를 이용하는 방식이다.

주로 서버에서 암/복화하를 모두 하는 경우에 사용한다.

 

 

비대칭키 방식은 암호화 복호화에 각기 다른 키를 사용하는 방식이다.

먼저,  (복호화를 위한)개인키를 생성하고

개인키를 가지고  (복화화를 위한)공개키를  생성한다.

 

클라이언트와의 통신간에 암호화를 필요로 하는 경우 비대칭키를 사용하게되는데,

이는 대칭키 방식에 비해 속도가 다소 떨어진다고 한다.

 

나는 이번에 계좌번호, 카드번호 등의 데이터 교환을 위해 비대칭키 방식을 사용하게 되었다.

 

 

실제로, 어떻게 구현해 나가면 되는지 알아보자.

1. 개인키를 생성한다.

 - openssl genrsa -out private.key 2048 // 나는 이거로는 안심이 안된다. 4096을 사용

 

2. 개인키를 가지고 공개키를 생성한다.

 - openssl rsa -in private.key -out public.key -pubout (PKCS#8 표준)

 

3. PKCS#1 을 사용하고자 한다.

 - openssl rsa -pubin -in public.key -RSAPublicKey_out

 

4. 환경변수를 쉽게 사용하게 해주는 dotenv를 정의하는 .env파일에 다음과 같이 정의한다.

 - private키의 줄 끝마다 \n를 붙여 한줄로 합쳐준다.

// before
asdfasdf
asdfasdf
asdfasdf

// after
asdfasdf\nasdfasdf\nasdfasdf

 

5. 사용할 때는 다음과 같은 코드를 통해 사용할 수 있다

export const getPrivateKey = () => {
    return process.env.PRIVATE_KEY.replace(/\\n/g, '\n');
};

 

6. 이후의 암복화하는 일상 하던것과 다르지 않다...

반응형