안녕하세요
최근에 웹,앱,모바일에서 후기 작성시 고객이 등록한 이미지가 저장이 제대로 안되는것 같다고 버그가 올라왔다
이미지 업로드 코드를 확인해보니
@UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: (request, file, callback) => {
const uploadPath = 'app/img';
if (!existsSync(uploadPath)) {
mkdirSync(uploadPath, { recursive: true });
}
callback(null, uploadPath);
},
filename: (request, file, callback) => {
callback(null, uuidv4() + '_' + file.originalname);
},
}),
}),
)
uploadFile(@UploadedFile() file: Express.Multer.File) {
const url = getFileDir() + file.filename;
return { url, name: file.originalname };
}
로컬환경에서 이미지를 등록하니 나의 로컬에 잘 저장이 된다.
노드는 현재 회사 물리서버(우분투)에서 도커로 배포되고있는데?
나의 Mac로컬 폴더에 잘 저장되는거 까지 확인이 됐다
하지만 결국 웹사이트에서 이미지를 불러낼라면
노드를 회사서버에 배포를 하게되고 회사 우분투서버 폴더내에 이미지가 저장이 되야한다
심지어 도커로 배포를 하고 있다면 도커 컨테이너내 WORKDIR/app/img로 저장이 될 것이다.
도커 컨테이너에 이미지가 저장이 된다면 도커 컨테이너가 삭제되거나 초기화가 된다면 해당 이미지는 전부 날라갈것이다.
이때 사용되는것이 VOLUME이다.
도커컨테이너랑 물리서버랑 폴더 마운트?공유?
우리회사는 현재 docker-compose로 블루/그린 방식으로 무중단 배포중이다.
docker-compose에 미리 volumes를 설정해주면된다.
services:
iwedding-api-green:
image: iwedding-api
container_name: iwedding-api-green
build: .
privileged: true
ports:
- '6902:6900'
volumes:
- /mnt/iweddingfs/mission:/app/img
물리서버(/mnt/iweddingfs/mission) === 도커컨테이너(/app/img) 와 서로 마운팅되어 공유가 된다.
왼쪽 = 물리서버
오른쪽 = 도커컨테이너
서로 같은 이미지가 있는것을 알수있다.
그래서 물리서버랑 도커랑 서로 공유는 잘되고 있는데 이미지가 왜 저장이 안되던건데요?
사실 아직도 정확한 원인은 파악하지 못했다.
일단 이미지 저장한후 업로드까지 로직을 파악하고 docker-compose.yml 파일에도 볼륨이 잘 적용되어있고
전혀 잘못된점을 찾지 못해서 각 폴더마다 chmod 777 권한도 줘보고 온갖 방법을 다 써봤다.
그래도 물리서버 = 도커컨테이너가 정상적으로 마운트가 되지 않았다..
예상원인은 도커를 빌드시 볼륨을 다시 생성하지않고 끌고오는데 이때 마운팅이 제대로 안되는거 같다
(도커컨테이너를 최초로 빌드후 배포시 마운팅이 잘됨)
그래서 어떻게 해결했어요?
역시 뭐든 캐시? 파일?를 초기화하고 다시 하는게 또 하나의 방법인거 같다
서버내 도커 볼륨을 전부 삭제하고 도커컨테이너에 등록된 볼륨명을 바꿔주니 물리서버와 도커컨테이너볼륨이 정상적으로 마운트 동기화가 되었다
도커컨테이너를 최초로 빌드하여 배포하면 마운팅이 잘되니 볼륨을 새로만들어주고 마운팅을 하면 된다고 생각하였고
docker-compose 명령어중 --renew-anon-volumes 추가하여 문제를 해결했다
(sudo docker-compose -f docker-compose-green.yml up --renew-anon-volumes -d --build)
sudo docker volume prune
volumes:
- /mnt/iweddingfs/mission:/app/img --> /mnt/iweddingfs/mission:/app/img2로 변경
FileInterceptor('file', { storage: diskStorage({ destination: (request, file, callback) => { const uploadPath = '/app/img' ==> '/app/img2' 여기로 변경!!; if (!existsSync(uploadPath)) { mkdirSync(uploadPath, { recursive: true }); } // const resizeUploadPath = 'app/img'; // if (!existsSync(resizeUploadPath)) { // mkdirSync(resizeUploadPath, { recursive: true }); // } // ``; callback(null, uploadPath); }, filename: (request, file, callback) => { callback(null, uuidv4() + '_' + file.originalname); }, }), }), ) uploadFile(@UploadedFile() file: Express.Multer.File) {
느낀점
도커컨테이너를 계속 재활용을 하지않고 새로운 컨테이너를 생성후 기존에 있던 컨테이너를 통채로 백업을 하는 배포환경이라면
이미지 업로드만 따로하는 간단한 노드서버를 pm2로 배포시켜 해당 서버로 파일을 업로드하는게 좋을 수도 있겠다~싶습니다
아 그리고 새로운 프로젝트를 진행한다면 AWS S3가 사용하기도 쉽고 관리 측면에서도 좋은거 같다~
'개발' 카테고리의 다른 글
[velog 2023-03-17] 아이웨딩B AWS EC2 + Route53 + Load Balancer + Nginx (0) | 2024.05.28 |
---|---|
[복붙, velog 2023-03-09] 아이웨딩 Yarn workspace 모노레포 프로젝트 (0) | 2024.05.24 |
[velog 2022-07-06] NextJS 뒤로가기 스크롤 복원 안되는 문제 (0) | 2024.05.23 |
[velog 2022-06-28] NextJS _middleware 사용하기 (0) | 2024.05.23 |
[velog 2022-06-27] NodeJS 레디스(Redis) 사용하기 (0) | 2024.05.23 |