Published on

AWS EC2 환경에서 Docker와 Nginx 설정시 겪은 문제점 개인적인 정리

Authors
  • avatar
    Name
    김민석
    Twitter

Introduction

EC2 인스턴스에서 Docker를 설치 과정 문제

image.png
  • 오류는 현재 사용 중인 Amazon Linux 2023 버전에서는 amazon-linux-extras 명령이 지원되지 않기 때문에 발생하는 것이였다 .
  • amazon-linux-extras는 Amazon Linux 2에서 사용되던 명령어로, Amazon Linux 2023 버전에서는 패키지 관리 방식이 변경해야 했다.

PAT 문제

image.png

오류 메시지는 GitHub가 2021년 8월 13일부터 패스워드를 이용한 인증을 지원하지 않기 때문에 발생한 것이다.

  • 대신 GitHub Personal Access Token (PAT) 을 사용해야 했다.

해결 방법

  1. GitHub에 Settings로 이동하여 → Generate new token으로 이동한다.
  2. 이름, 유효 기간, 권한을 설정하고 Generate 버튼을 클릭하여 토큰을 생성하는 것이다.
  3. 생성된 토큰을 복사하여 EC2 인스턴스에서 GitHub에 접속할 때 GitHub 사용자 이름, 비밀번호 대신 생성한 토큰을 입력하여 해결 하였다.

Personal Access Token (PAT) 란?

  • GitHub에서 사용자 계정의 비밀번호 대신 사용할 수 있는 일종의 인증 토큰이다.
  • GitHub는 보안 강화를 위해 비밀번호 인증을 폐지하고, 대신 Personal Access Token을 사용하도록 하고 있다고 한다 .

접근 권한 문제

image.png

오류 메시지에서 문제는 springboot-app 이미지를 찾을 수 없거나 접근 권한이 없다는 것이다.

springboot-app 이미지 확인

현재 docker-compose.yml 파일에서 application 서비스의 imagespringboot-app을 참조하고 있다.

  • 로컬에서 직접 빌드한 Docker 이미지 (Dockerfile을 사용하여 빌드)
  • Docker Hub 또는 기타 레지스트리에 존재하는 이미지

로컬에서 직접 빌드해야 하는 이미지이기에, docker-compose.yml에서 build 지시자를 추가.

application:
  build:
    context: .
  ports:
    - "8080:8080"
  environment:
    - SPRING_PROFILES_ACTIVE=prod
  • 이렇게 하면 docker-composeDockerfile을 사용하여 springboot-app 이미지를 빌드한다.
  • context: .는 현재 디렉토리에서 Dockerfile을 찾는 것으로 해결 했다.

문제점)

image.png

이 오류는 현재 Dockerfile에서 COPY build/libs/resume-feedback-0.0.1-SNAPSHOT.jar /app/app.jar 명령어가 실패하고 있기 때문이다.

  • 이 오류는 해당 파일이 존재하지 않아서 발생한 것이였다.

해결 방법

  1. 먼저, EC2 인스턴스에서 프로젝트의 build/libs 디렉토리에 JAR 파일이 있는지 확인한다.
  • 해당 파일이 없다면, JAR 파일을 빌드해야 한다.
  1. 만약 build/libs/resume-feedback-0.0.1-SNAPSHOT.jar 파일이 없다면, 다음 명령어를 사용하여 프로젝트를 빌드한다.
./gradlew build

이 명령은 프로젝트를 빌드하고 build/libs/ 디렉토리에 JAR 파일을 생성한다.

하지만, 또 다시 문제가 발생했다.

image.png

지금 ./gradlew build 명령어를 실행하려고 했으나, Permission denied 오류가 발생했다.

이는 gradlew 파일에 실행 권한이 없기 때문에 발생하는 문제이다.

다음 명령어를 사용하여 gradlew 파일에 실행 권한을 추가하였다.

chmod +x ./gradlew

또한, Dockerfile의 JAR 파일 경로 수정

  • build.gradle에서 생성된 JAR 파일의 이름이 다를 수 있다.
  • build/libs 디렉토리에서 실제 파일 이름을 확인한 다음, Dockerfile의 COPY 경로를 수정해야 했다.
  • build/libs/ 디렉토리에 있는 실제 JAR 파일 이름이 다르다면 Dockerfile에서 이를 반영한다.
COPY build/libs/your-actual-jar-name.jar /app/app.jar

Nginx 설정 파일 준비

nginx.conf 파일을 생성하여 Nginx가 트래픽을 애플리케이션으로 전달하도록 설정한다.

events { }

http {
    server {
        server_name your-ec2-public-dns; # EC2 퍼블릭 DNS 또는 IP 주소

        // ... 생략
}
  • ssl 디렉터리를 프로젝트 내에 생성하고, nginx-selfsigned.crtnginx-selfsigned.key를 넣는다.

Docker Compose로 컨테이너 실행

프로젝트 디렉터리에서 다음 명령어로 Docker Compose를 실행하여 애플리케이션과 Nginx를 시작한다.

docker-compose up --build -d

로컬 환경에서는 정상적으로 작동하고, 배포 환경에서는 문제 발생

image.png
  • 배포 환경에서 API 키가 올바르게 설정되지 않았을 수 있었다.
  • 환경 변수나 설정 파일에서 API 키를 제대로 읽어오고 있는지 확인하였다.

즉, 문제를 해결하기 위해 배포 환경에서 API 키가 올바르게 설정되어 있는지를 다시 한 번 확인하고, 필요한 경우 docker-compose.yml에 환경 변수를 추가하여 설정해봤다.

image.png

docker-compose.yml 파일 수정

docker-compose.yml 파일에 환경 변수를 설정하여 Docker 컨테이너에서 OPENAI_API_KEY를 사용할 수 있도록 한다.

version: '3'
services:
  application:

  // ... 생략

    environment:
      - SPRING_PROFILES_ACTIVE=prod # 필요에 따라 프로파일 설정
      - OPENAI_API_KEY=${OPENAI_API_KEY}

  // ... 생략

Docker Compose 빌드 및 실행

환경 변수 설정 후 다음 명령어를 통해 Docker Compose를 재빌드 및 실행하세요.

docker-compose up --build -d
  • 재빌드: -build 옵션이 포함되어 있기 때문에 docker-composeDockerfile을 사용하여 필요한 이미지를 다시 빌드합니다.
  • 백그라운드 실행: d 옵션은 컨테이너를 백그라운드에서 실행합니다.

배포 상황에서의 문제점)

PDF 파일을 올리니깐, 이렇게 에러가 발생해서 동작을 제대로 하지 않는 이유.

image.png

이 오류 메시지는 Tesseract OCR 라이브러리가 특정 언어 데이터 파일(chi_tra)을 찾지 못해 발생하는 문제이다.

  • Tesseract가 필요로 하는 chi_tra.traineddata 파일이 서버에 없거나, 잘못된 경로에 위치해 있기 때문이라고 한다.

언어 데이터 파일 설치

  • Tesseract가 필요한 traineddata 파일(chi_tra.traineddata)이 있는지 확인한다.
  • 만약 없다면, 다음 명령어로 언어 데이터를 설치한다.
sudo apt-get update
sudo apt-get install tesseract-ocr-chi-tra

역시 없었던 것이다..

image.png

현재 사용 중인 EC2 인스턴스는 Amazon Linux를 기반으로 하고 있어서 apt-get이 아닌 yum 패키지 관리자를 사용해야 했다.

Amazon Linux에서 Tesseract와 관련된 패키지를 설치하려면 yum 명령어를 사용해야 한다는걸 알게 되었다.

현재 tessdata 파일을 임시 디렉토리에 복사하고 tessdata 경로를 설정하고 있는데,

임시 디렉토리는 재시작 시 삭제되기 때문에, 지속적인 경로로 설정하여야 했다.

tessdata 폴더에 eng.traineddatakor.traineddata 파일이 있는 것을 확인했다.

이제 이 경로를 Tesseracttessdata 경로로 정확히 설정해주면 된다.

image.png

application.yml 파일 설정

먼저 application.yml 파일에 다음과 같이 tessdata 경로를 지정한다.

tessdata:
  prefix: src/main/resources/tessdata  # 실제 tessdata 디렉토리 경로

OcrService 클래스 수정

OcrService 클래스에서 tessdata 경로를 application.yml 파일에서 읽어오도록 수정한다.

@Service
@RequiredArgsConstructor
public class OcrService {

    @Value("${tessdata.prefix}")
    private String tessDataPath;

    private final Tesseract tesseract = new Tesseract();

    @PostConstruct
    public void init() {
        // Tesseract 설정에 yml에서 주입받은 tessDataPath를 사용
        tesseract.setDatapath(tessDataPath);  // 설정 파일에서 경로 가져오기
        tesseract.setLanguage("kor");  // 필요한 경우 "eng+kor"로 설정
    }

    public String extractTextFromPdfWithOcr(File pdfFile) throws IOException, TesseractException {
        StringBuilder extractedText = new StringBuilder();
        try (PDDocument document = PDDocument.load(pdfFile)) {
            PDFRenderer renderer = new PDFRenderer(document);

            for (int page = 0; page < document.getNumberOfPages(); ++page) {
                BufferedImage image = renderer.renderImageWithDPI(page, 300, ImageType.GRAY);
                String pageText = tesseract.doOCR(image);
                extractedText.append(pageText);
            }
        }
        return extractedText.toString();
    }
}
  • @Value("${tessdata.prefix}")를 통해 application.yml에서 설정한 tessdata.prefix 값을 tessDataPath에 주입받는다.
  • Tesseract 객체의 setDatapath() 메서드에 tessDataPath를 설정한다.
  • init() 메서드에서 tessDataPath가 Tesseract의 datapath로 사용되기 때문에, 임시 디렉토리로 복사하는 작업은 필요하지 않는다.

도커 컨테이너에 Tesseract 설치 및 설정하기

  • Dockerfile 수정하기
# OpenJDK 17을 기반으로 한 Docker 이미지 사용
FROM openjdk:17-jdk-slim

# Tesseract 및 필수 패키지 설치
RUN apt-get update && apt-get install -y tesseract-ocr tesseract-ocr-kor tesseract-ocr-eng libtesseract-dev

// ... 생략

이렇게 하면 도커 이미지를 빌드할 때 Tesseract와 한국어 및 영어 언어 데이터도 함께 설치된다.

docker-compose.yml 수정

  • docker-compose.yml에서 Dockerfile을 사용하여 애플리케이션을 빌드하고, 필요한 환경 변수를 설정해 준다.
version: '3'
services:
  application:

  // ... 생략

    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - TESSDATA_PREFIX=/usr/share/tesseract-ocr/4.00/tessdata  # Tesseract 데이터 경로 설정

  // ... 생략

위 설정에서 TESSDATA_PREFIX/usr/share/tesseract-ocr/4.00/tessdata로 설정했다.

이는 Tesseract의 언어 데이터 위치를 지정하는 환경 변수이다.

  • 이제 변경 사항을 반영하여 도커 컨테이너를 다시 빌드하고 실행하여 에러를 해결 하였다.

도메인 설정해보기.

나는 밑에 있는 서비스를 통해 1년 동안 도메인을 공짜로 사용할 수 있게 되었다.

image.png

이 화면은 DNS 설정 페이지로, AWS EC2 서버에 도메인을 연결할 수 있다.

필요한 설정은 IP 연결 (A) 항목을 이용해 AWS EC2 인스턴스의 퍼블릭 IP 주소를 입력하는 것이다.

  1. EC2 퍼블릭 IP 확인
  • AWS EC2 콘솔로 이동하여, 도메인을 연결하고자 하는 EC2 인스턴스를 찾는다.
  • 해당 인스턴스의 퍼블릭 IPv4 주소를 확인하면 되는 것이다.
  1. IP 연결 (A) 항목 설정
  • IP연결 (A) 항목 오른쪽의 빈칸에 EC2 퍼블릭 IP 주소를 입력한다.

이렇게 IP 연결 (A) 항목에 EC2 퍼블릭 IP 주소를 입력하고 저장하면 기본적인 설정은 완료

  1. Nginx 및 방화벽 설정 확인
  • EC2 인스턴스에서 Nginx가 정상적으로 작동하고, 80번 포트(HTTP)가 열려 있어야 한다.
  • AWS 보안 그룹 설정에서 인바운드 규칙에 80번 포트가 허용되어 있는지 확인한다.

이후 이력서가이드.웹.한국 주소로 접속하면 설정한 EC2 인스턴스에 연결된 애플리케이션이 표시 되었다.