오랜만에 사이드 프로젝트를 진행하면서 Docker를 다시 사용했는데 웹서버로 Nginx를 사용하면서 다른 컨테이너로 리버스 프록시를 못하는 문제를 마주하게 되었다.
프로젝트의 통신 흐름은 위 그림처럼 진행이 된다.
1. 사용자가 HTTP 요청을 보냄
2. Nginx는 HTTP 요청을 잡아서 스프링부트로 요청을 전달
그러나 위 과정을 진행하면서 생각도 못했던 문제를 마주하게 되었다.
그 문제는 도커 네트워크 불일치 문제로 인해 Nginx가 받은 HTTP 요청을 스프링부트로 못넘기는 문제였다.
도커 컨테이너끼리의 통신은 도커 네트워크를 통해 이루어지게 되는데 통신하려는 두 컨테이너가 같은 네트워크를 사용하고 있지 않아서 발생한 문제이다.
나는 컨테이너를 구축할 때 아래의 방법으로 컨테이너를 구축했다.
1. Nginx, MySQL은 Docker-compose로 생성
2. SpringBoot는 깃허브액션을 통해 컨테이너 생성
즉 컨테이너를 만들 때 다른 네트워크를 사용하도록 만들었던 것이다.
그러면 저 구성이 무슨 문제가 있길래 요청을 넘기지 못하는 걸까?
네트워크가 어떻게 묶여있는지 그림으로 표현하면 아래와 같다.
Docker-compose로 만든 Nginx, MySQL이 하나의 네트워크로 묶여있고, 깃허브 액션으로 배포했던 SpringBoot가 별개의 네트워크로 묶여있다.
이걸 확인해보려면 아래 명령어를 이용해서 도커 네트워크를 확인할 수 있다.
docker network ls
그리고 아래 명령어를 통해서 해당 네트워크에서 사용 중인 컨테이너의 목록을 볼 수 있다
docker network inspect <네트워크 이름>
(현재는 설정이 완료된 상태라 4개의 컨테이너가 전부 같은 네트워크를 사용하고 있습니다.)
docker-compose에서 아무 설정을 하지 않고 컨테이너를 생성하면 ec2-user_default라는 네트워크를 기본으로 사용하도록 설정되어 있었다.(기본 네트워크는 확인해봐야 합니다. EC2의 OS나 사용자 환경에 따라 달라질 수 있습니다.)
그러니 내가 할 일은 깃허브액션에서 컨테이너를 생성할 때 네트워크를 지정해 주면 되는 것이다.
# EC2에 배포 진행
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_KEY }}
script: |
echo "${{ secrets.DOCKER_HUB_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin
docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/our-password:latest
docker stop our-password || true
docker rm our-password || true
docker run -d \
--network ec2-user_default \
-p ${{ secrets.BACKEND_DOCKER_OUT_PORT }}:${{ secrets.BACKEND_DOCKER_IN_PORT }} \
--name our-password \
${{ secrets.DOCKER_HUB_USERNAME }}/our-password:latest
가장 마지막에 docker run을 진행할 때 --network ec2-user_default를 해당 네트워크를 사용하도록 지정해 두었다.
그리고 다시 배포를 진행하면 해당 컨테이너는 ec2-user_default 네트워크를 사용하게 되는 것이다.
location /api {
proxy_pass http://our-password:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
위 코드는 nginx.conf의 설정 부분이다.
이제 nginx랑 springBoot의 컨테이너 이름인 our-password는 같은 네트워크를 사용하고 있기 때문에 컨테이너 이름이 호스트명으로 사용이 가능하다. 그렇기에 리버스 프록시가 가능하게 된다.
'오류해결' 카테고리의 다른 글
MySQL을 사용하면서 마주했던 시간 반올림 문제 (1) | 2024.12.14 |
---|---|
Input length must be multiple of 16 when decrypting with padded cipher 문제 해결 방법 (0) | 2024.10.31 |
mysql.cj.jdbc.Driver에 빨간글씨가 뜨는 문제 (1) | 2024.09.22 |
스프링 시큐리티에서 인증 후 CSRF 토큰 갱신 문제 (0) | 2024.08.07 |