관리 메뉴

백엔드 엔지니어 이재혁

케어매칭 AWS 프리티어 배포기 본문

케어매칭 서비스 배포

케어매칭 AWS 프리티어 배포기

alex00728 2025. 7. 12. 16:25

주의: 이번 작업은 프리티어로 운영하려다보니 억지로 미친짓을 한 것이다.

인프라 관점에서 좋지 않은 방식이라고 생각하니 특별한 목적이 없다면 따라하지 말 것

 

 

일단 서비스를 빠르게 올리기 위해 간단하게 다음 작업만 진행했다.

전부 프리티어로 생성했다.

  1. EC2 인스턴스 생성 (Amazon Linux 2023)
  2. RDS mariaDB 인스턴스 생성
  3. S3 버킷 생성 (케어매칭 이미지 파일 호스팅)

RDS랑 S3는 웹서버 외부 데이터베이스/파일 호스팅을 위해 필요

 

RDS / S3 설정

RDS: 파라미터 그룹 편집 (유니코드를 저장할 수 있도록 변경)

  • character_set_server: `utf8mb4`
  • collation_server: `utf8mb4_unicode_ci`

S3: 이미지 업로드 디렉토리에 대해 퍼블릭 액세스 허용

 

EC2 인스턴스

모든 과정은 Amazon Linux 2023 기준으로 진행했다.

종종 Amazon Linux 2와 다른 경우도 있으니 주의

 

SSH 접속

따로 설정을 안했다면 AWS에서 다운로드 받은 pem 인증서를 거부할 것이다.

pem 인증서 파일 접근 권한을 제한할 필요가 있는데, Windows는 이 과정이 좀 복잡했다...

 

Mac/Linux 계열: 아마 `chmod 400`으로 제한하면 바로 끝났던 것으로 기억

Windows 계열: 글이 길어지니 다른 글 참고 → https://benfatto.tistory.com/54

 

접속: `ssh -i [인증서.pem] ec2-user@[EC2 IP]`

 

Docker 설치

프론트, 백엔드는 Docker로 실행할 것이다.

 

설치: `sudo dnf install -y docker`

실행: `sudo systemctl start docker`

sudo없이 실행: `sudo usermod -a -G docker ec2-user`

 

Redis6 설치

Amazon MemoryDB for Redis 2개월 무료 체험할 수 있지만,

2개월은 너무 짧다고 생각해 그냥 EC2 인스턴스에 같이 설치했다.

 

설치: `sudo dnf install -y redis6`

 

웹서버 설치 및 실행

프론트엔드

프론트엔드 Docker 이미지

Nginx default.conf 수정

`default.conf`에 기존에 쓰던 백엔드 Reverse Proxy에 AWS ALB 주소가 그대로 적혀있었다.

일단 빨리 배포해야 하니까 컨테이너 바깥의 ec2 호스트를 가르키도록 설정을 바꿔줬다.

(환경변수화하는게 유지보수하기엔 좋을듯)

# API reverse proxy 설정
location /api {
    # proxy_pass http://internal-carematching-backend-alb-1372095799.ap-northeast-2.elb.amazonaws.com; # 기존
    proxy_pass http://host.docker.internal:8080;
    # 생략
}

 

host.docker.internal

나중에 알고보니 Linux에서 docker를 구동하면 `host.docker.internal` 주소를 모른다고 한다.

(다른 운영체제에선 잘 인식함)

 

컨테이너 생성시 `--add-host=host.docker.internal:host-gateway`를 매개변수로 넘겨주면

`host.docker.internal`을 `host-gateway`라는 주소로 라우팅해준다.

아마 처음부터 `host-gateway`라는 주소를 사용하도록 했다면 필요 없는 작업일 것 같다.

 

백엔드

백엔드 Docker 이미지

실행시 참고: 프로젝트 소스코드 중 `.env.template` 파일을 참고해서 모든 환경 변수를 주입해주어야 한다.

컨테이너를 생성 할 때 환경 변수 정보를 잘 넣어주자. 아래는 그 일부다.

docker run -d -p 8080:8080 --name carematching-backend \
  --add-host=host.docker.internal:host-gateway \
  # 생략
  -e REDIS_HOST=host.docker.internal \
  -e REDIS_PORT=6379
  ghcr.io/jaehyuk-lee/carematching-backend:latest

 

백엔드는 일단 컨테이너를 띄워보았다.

 

역시 데이터베이스 접속에 실패해서 바로 죽는다.

로그 보는 법: `docker logs [container ID/name]`

 

에러: `org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [Socket fail to connect to host:address=(host=mymariadb.ap-northeast-2.rds.amazonaws.com)(port=3306)(type=primary). Connect timed out]`

 

AWS VPC 보안 그룹 설정

EC2 인스턴스 보안그룹

인바운드 HTTP 허용 (대상: 모든 IP)

인바운드 HTTPS 허용 (대상: 모든 IP)

MariaDB 보안그룹

인바운드 3306 허용 (대상: EC2 인스턴스 보안 그룹)

 

 

이제는 보안그룹 설정도 끝났다. 그런데 아직도 백엔드 실행이 안된다.

로그를 보니까 redis 접속이 안된단다.

 

에러: `Caused by: io.lettuce.core.RedisConnectionException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients.`

 

Redis 접속 허용

외부에서 접근하려면 redis6 설정을 바꿔줘야 한다.

`/etc/redis6/redis6.conf` 파일 내부 `bind 127.0.0.1` 부분에 docker container 주소를 추가해주자.

# Examples:
#
# bind 192.168.1.100 10.0.0.1     # listens on two specific IPv4 addresses
# bind 127.0.0.1 ::1              # listens on loopback IPv4 and IPv6
# bind * -::*                     # like the default, all available interfaces
bind 127.0.0.1 172.17.0.1

 

`172.17.0.1` 주소는 `ifconfig`로 확인한 docker container의 네트워크 주소다.

주소는 서버마다 다를 수 있으니, 직접 `ifconfig`로 확인해야 한다.

$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255

 

이제 Docker container 내부에서도 바깥의 redis에 접근 가능하다.

 

설정 바꾸고 나면 `sudo systemctl restart redis6`로 재실행!

 

백엔드 컨테이너 실행

$ docker container start carematching-backend
# 컨테이너 로그
2025-07-15T07:21:42.578Z  INFO 1 --- [carematching] [           main] c.s.c.CarematchingApplication            : 
    Started CarematchingApplication in 25.755 seconds (process running for 27.403)

백엔드 실행 잘 됐다.

 

http://carematching.kro.kr/

 

 

잘 돌아는 가네

의외로 스왑 메모리를 설정하지 않아도 돌아가긴 했다. 🙄

$ free -h
               total        used        free      shared  buff/cache   available
Mem:           949Mi       576Mi        72Mi       0.0Ki       300Mi       225Mi
Swap:             0B          0B          0B

 

프리티어에 트래픽 제한도 있던데 누가 억지로 트래픽 만들지 않기를...

 

 

 

이후 계획 (완료)

HTTPS를 붙이려고 한다.

 

구체적 계획

  • 도메인 발급
  • Let's Encrypt로 TLS 인증서 발급
  • Nginx 설정에 인증서 설정 반영
  • cronjob으로 인증서 자동 발급 적용

Let's Encrypt로 TLS 인증서를 발급받으면 유효기간이 3개월이라 cronjob으로 반복 필요

 

실제 완성: HTTPS 적용기 참고