배포할 때 개인적으로 가장 무서운 에러 502.. 스푼피드 개발의 배포를 맡았는데 어김없이 502를 만나고야 말았다 😣 잊어버리기 전에 어떻게 해결했는지 과정을 되새겨보기로 했다. 그래야 다음 502 때는 덜 무서울 것 같다
ssh 접속 후 워킹 디렉토리로 진입한다. sudo docker ps -a
명령어를 입력하면 현재 빌드된 컨테이너들을 확인할 수 있는데, 필자의 경우 502 에러가 처음 났을 때 nginx는 정상 up, app은 exit 상태였다.
nginx는 잘 띄워졌는데 app과 연결이 안된 것 같아 sudo docker logs app
으로 에러 로그를 확인했다.
이렇게 뜨길래 npm install 이 제대로 안되었다는 걸 알게 되었고, 수동으로 npm install
을 해준 뒤 sudo docker restart app
으로 재시작해주었다. Dockerfile 에서 npm install 과정을 넣어주었기 때문에 자동으로 되었을 줄 알았는데 왜 누락이 된 것인지, 어느 부분을 놓치고 있는지 아직 발견하지 못했다. 그래서 아직 깃헙액션 후 ssh 에 접속해 npm install -> restart 과정을 수동으로 반복 중인데 빠른 시일 내에 해결하고 기록하고 싶다.
이렇게 app 도 up 상태로 만들어주었는데,, 502가 없어지지 않았다. 그래서 이제 진짜 nginx 설정을 만져봐야겠다 싶었고 우선 파일을 확인하기로 했다.
sudo docker exec -it (nginx컨테이너id) ls /etc/nginx/conf.d
를 해보면 conf.d 폴더 안에 있는 conf 파일이 확인 가능하다. 설정 파일을 커스텀하지 않았다면 기본 nginx 설정 파일은 다음과 비슷한 형태일 것이고 sudo docker exec -it (nginx컨테이너id) vi /etc/nginx/conf.d/default.conf
로 확인할 수 있을 것이다.
user www www; ## Default: nobody
worker_processes 5; ## Default: 1
error_log logs/error.log;
pid logs/nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 4096; ## Default: 1024
}
http {
include conf/mime.types;
include /etc/nginx/proxy.conf;
... 중략
server { # simple load balancing
listen 80;
server_name big.server.com;
access_log logs/big.server.access.log main;
location / {
proxy_pass http://big_server_com;
}
}
}
필자는 커스텀 설정 파일을 만들어둔 상태였는데, 바보같이 위와 같은 default conf 파일을 삭제하지 않았었다.
결론적으로 nginx 기본 설정이 적용되어 app과 연결이 안된 것이었다.
아래처럼 nginx용 Dockerfile 도 만들어주었다 (default 설정을 지우고 커스텀 설정으로 덮는 코드). 이렇게 해야 커스텀 nginx.conf에서 app:3000 을 했던 내용이 먹힐 것이다.
FROM nginx:1.20.2-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
잊지 않고 루트의 docker-compose.yml에도 다음 내용을 추가해준다.
nginx:
build: ./proxy # proxy는 필자의 nginx Dockerfile이 있는 디렉토리 이름
이후 다시 마스터에 푸시해서 배포하고(깃헙액션), ssh 접속 후 sudo docker exec -it (nginx컨테이너id) vi /etc/nginx/conf.d/nginx.conf
를 해보면 자신이 작성한 커스텀 설정 파일 내용이 보인다!!
여기까지 확인했는데 사라지지 않는 502..?!
그렇다면 가장 기본적인 부분을 놓치고 있진 않았는지 확인해보자,,
netstat -nlpt
와 sudo docker ps -a
을 해서 포트 확인을 했는데 포트 연결 방향이 다 맞는 것 같다면 (아래 예시는 Ip 문제 해결 후 사진이지만 해결 전에는 127.0.0.1:80->80/tcp 이런 형식이었음)
ip 설정을 까먹은건 아닌지 체크해볼 필요가 있다.
처음에 로컬로 개발하면서 localhost ip인 127.0.0.1로 설정되어있었을 것인데, 이를 0.0.0.0으로 바꿔주어야 한다.
둘의 차이는 여기 나와있다.
아래의 코드처럼 app.listen 부분에서 ip를 특정적으로 추가해주었더니 성공 💫
import app from './app';
import dotenv from 'dotenv';
import { connectDB } from './config/index';
dotenv.config();
const runServer = async () => {
await connectDB();
/* Run server */
console.log('Set application...');
// app.listen(process.env.PORT, () => console.log(`server Run with port: ${process.env.PORT}`));
app.listen(3000, '0.0.0.0', () => console.log(`server Run with port: ${process.env.PORT}`));
};
runServer();
추가적으로 배포 성공 후 언더스코어 관련 이슈가 있어 적어보자면,
프론트에서 요청을 보낼 때 header 값에 'access_token' 처럼 언더스코어가 포함되어있을 경우 nginx에서 디폴트로 언더바를 지우게끔 되어있어서 발생하는 문제가 있었다.
이는 nginx.conf 에 underscores_in_headers on;
코드를 추가해줌으로써 해결했다.
그리고 도커 컨테이너에 변경을 가했다면 항상 restart 로 최신상태를 유지하자 @~@