문제의 시작
EC2에 Spring Cloud Config, Gateway, Eureka를 올려서 테스트해보려고 하는데 이상하게 Gateway만 Config-Service의 설정 정보를 받아오지 못하고 이거 때문에 Eureka에서도 인스턴스 목록에 뜨지 않았다. docker로 구성해서 사용했기 때문에 컨테이너 간 통신 문제인가 docker network 설정 정보도 확인해 보고, EC2 인바운드 규칙도 살펴보고, docker-compose 파일 내용도 EC2의 퍼블릭 IP로 바꿔보고, 진짜 여러 가지 다 해봤다. 한 4시간 정도 고생한거 같은데 결국 해결 방법을 찾아냈다.
문제의 원인
Could not locate PropertySource ([ConfigServerConfigDataResource@ec0c838 uris = array<String>['http://퍼블릭IP생략:8888'],
optional = true, profiles = 'default']): I/O error on GET request for "http://퍼블릭IP생략:8888/application/default": Connection refused
위와 같은 에러가 Gateway를 실행하면 계속 떠서 진짜 미치는줄 알았다. 그래도 결국 원인을 알아내고야 말았는데 정말 별거 아니었다.
로컬 환경에서는 집 컴퓨터 성능이 좋기 때문에 프로젝트를 IDE에서 실행해도 빠르게 실행되고, 실행하는 순서를 직접 맞춰서 실행하니 문제가 없었다. 그런데 문제는 EC2 프리티어 인스턴스의 성능이 좋지 않다는 것이다. 그래서 docker-compose 파일에 작성한 아래와 같은 내용에서 depends-on이 별 의미가 없었다.
services:
service-discovery:
image: ness727/service-discovery:1.0
ports:
- "8761:8761"
container_name: service-discovery
hostname: service-discovery
networks:
- my-network
config-service:
image: ness727/config-service:1.0
ports:
- "8888:8888"
container_name: config-service
hostname: config-service
networks:
- my-network
gateway-service:
image: ness727/gateway-service:1.0
ports:
- "8000:8000"
container_name: gateway-service
hostname: gateway-service
networks:
- my-network
depends_on:
- config-service
- service-discovery
environment:
SPRING_CONFIG_IMPORT: 'optional:configserver:http://config-server:8888'
networks:
my-network:
external: true
name: delibird-network
물론 전부 실행하고 나서 gateway만 /actuator/refresh를 호출해서 새로고침해도 되지만 여간 불편한게 아니기 때문에 편하게 실행할 방법을 생각해 봤다.
그 방법은 그냥 단순하게 config-service보다 늦게 실행시키는 것이다.
해결 방법 1 - dockerize
처음 시도했던 방법은 dockerize를 이용해서 다른 서비스가 실행된 다음에 실행되도록 하는 방법이다.
docker-compose실행시 순차 실행을 위한 dockerize 사용
나의 경우 docker-compose 실행시 이미지를 이용해 mongodb를 사용한다. 하지만 nodejs 서버와 함께 docker-compose up 실행시 error가 발생.express 서버 내에 mongoose를 불러와서 connect 하는 부분에서 에러Dock
velog.io
이 블로그에 있는 것처럼 구성하여 실행했는데...
사실 depends-on이랑 별 차이가 없어서 의미 있는 해결 방법은 아니었다.
참고로 openjdk:17-ea-slim와 같은 jdk를 사용하면 dockerize를 설치하기 위해 필요한 도구들이 들어있지 않아서 따로 설치해주어야 한다.
RUN apt-get update && apt-get install -y wget tar && rm -rf /var/lib/apt/lists/*
해결 방법 2 - sh 파일 이용
#!/bin/bash
sleep 50
exec java -jar GatewayService.jar
위와 같은 내용을 sleep.sh라는 이름으로 만들어 Dockerfile과 같은 레벨의 디렉토리에 위치시켰다.
처음에 50초를 기다리고 그다음에 GatewayService를 실행시키라는 명령이다.
왜 50초로 했냐면 사실 처음에 20초 정도로 설정했었는데 그래도 켜지는 타이밍이 맞지 않아 충분히 기다리도록 한 것이다.
그리고 비슷한 방법으로 Dockerfile에 CMD ["sleep 50"] 이런 식으로 작성하면 다음에 오는 EntryPoint가 기다리고 실행되는 것이 아니라 바로 실행되기 때문에 별 의미가 없게 된다.
CMD ["sleep 50 && java -jar GatewayService.jar"] 이거도 의미가 없다. 동작은 원하는 대로 되지만 docker-compose 파일에서 설정한 대로 작동하지 않는다.
FROM openjdk:17-ea-slim
VOLUME /tmp
COPY build/libs/gateway-service-1.0.jar GatewayService.jar
COPY sleep.sh /sleep.sh
RUN chmod +x /sleep.sh
ENTRYPOINT ["/sleep.sh"]
그래서 최종적으로 위와 같은 Dockerfile을 만들었다.
이 파일로 빌드 / 배포하고 EC2에서 받아 사용해 보니 원하는 대로 잘 작동했다!
'공부 > Docker' 카테고리의 다른 글
| [Docker] GCP에서 Docker 및 Docker-Compose 설치하기 (0) | 2024.05.17 |
|---|---|
| [Docker] Image & Container (0) | 2024.01.31 |
| [Docker] Docker에 대해서 간단하게 알아보자 (0) | 2024.01.16 |