크롬 드라이버, 셀레니움, 도커 환경 연동

이정빈·2024년 6월 1일
2

트러블슈팅

목록 보기
4/7
post-thumbnail

오류 상황

오류 내용

공지사항 크롤러가 로컬에서는 잘 동작하는데 EC2 서버에 올라가면 문제였다. 그래서 크롤링이 되지 않는 오류가 발생했다.
아래는 docker logs [컨테이너아이디] 명령어를 통해 찍은 로그이다.

주요 내용은 아래 내용이다.

Caused by: org.openqa.selenium.SessionNotCreatedException: Could not start a new session. Response code 500. Message: unknown error: Chrome failed to start: exited abnormally.

셀레니움을 통해 크롤링을 해야하는데 크롬이 제대로 실행이 되지 않는 오류가 발생한 것이다.

오류 원인 코드

[CrawlerController.java 일부]

public void getAllNotice() throws InterruptedException, ParseException {
        log.info("==== "+ "새 공지사항 크롤링 시작 시각: "+ String.valueOf(LocalDateTime.now())+"====");
        // Headless 모드로 Chrome 실행
        ChromeOptions options = new ChromeOptions();
        // Headless 모드 활성화
        options.addArguments("--headless");
        options.addArguments("--disable-dev-shm-usage");
        options.addArguments("--ignore-ssl-errors=yes");
        options.addArguments("--ignore-certificate-errors");

        // WebDriver 인스턴스 생성
        WebDriver driver = new ChromeDriver(options);

[Dockerfile]

# 기본 이미지를 설정합니다.
FROM ubuntu:22.04

# Java 설치
RUN apt-get update && \
    apt-get install -y openjdk-17-jdk wget gnupg unzip && \
    rm -rf /var/lib/apt/lists/*

# 작업 디렉토리를 설정합니다.
WORKDIR /app

# 스프링 어플리케이션 JAR 파일을 컨테이너로 복사합니다.
COPY ./build/libs/notify-crawler-0.0.1-SNAPSHOT.jar /app/notify-crawler.jar

# 크롬 브라우저와 크롬 드라이버를 설치합니다.
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
    sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \
    apt-get update && \
    apt-get install -y google-chrome-stable && \
    wget -q "https://chromedriver.storage.googleapis.com/114.0.5735.90/chromedriver_linux64.zip" -O /tmp/chromedriver.zip && \
    unzip /tmp/chromedriver.zip -d /usr/local/bin/ && \
    rm /tmp/chromedriver.zip && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 환경 변수를 설정합니다.
ENV CHROME_DRIVER_PATH=/usr/local/bin/chromedriver
ENV SPRING_PROFILES_ACTIVE=prod
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
ENV PATH=$PATH:$JAVA_HOME/bin

# 포트를 엽니다.
EXPOSE 8082

# 어플리케이션을 실행합니다.
ENTRYPOINT ["java", "-Dwebdriver.chrome.driver=/usr/local/bin/chromedriver", "-jar", "/app/notify-crawler.jar"]

도커 파일을 보면 크롬 브라우저와 크롬 드라이버를 설치하는 코드가 포함되어있다.

[build.gradle]

dependencies {

	//Jsoup
	implementation 'org.jsoup:jsoup:1.14.3'

	// Selenium WebDriver
	implementation 'org.seleniumhq.selenium:selenium-java:4.1.0'
	// Chrome WebDriver
	implementation 'io.github.bonigarcia:webdrivermanager:5.0.3'

	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.kafka:spring-kafka'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	testImplementation 'org.projectlombok:lombok:1.18.28'
	testImplementation 'org.springframework.boot:spring-boot-starter-security'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
	implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0'
}

build.gradle에도 셀레니움과 크롬 웹 드라이버를 포함하고 있다.

예상 원인

로컬에서는 크롬과 크롬드라이버를 시스템에 직접 다운 받고 실행했지만 서버에서는 도커로 띄우기 때문에 도커 컨테이너 안에 크롬과 크롬 드라이버를 설치하고 이것과 셀레니움이 서로 버젼이 맞아서 잘 돌아가야한다.

따라서 크롬 드라이버 버젼, 크롬 버젼, 셀레니움 버젼의 호환 문제가 발생했거나 호환성이 문제 없어도 스프링 코드가 도커 컨테이너 내에서 설치경로를 인식하지 못해 크롬을 불러내지 못하는 것이 문제일 것이다.

예상 해결 방안

1. 크롬, 크롬 드라이버, 셀레니움의 버젼 맞추기

원래는 3개를 다 맞추려고 했는데 셀레니움 공식 문서 를 보니 셀레니움 4.6버젼부터 selenium manager를 포함하고 있어서 자동으로 브라우저 버젼을 인식하여 브라우져와 호환되는 드라이버를 다운로드 하고 설정해준다는 것을 알게 되었다.
따라서 실제 해결방안에 적은 아래방법과 같이 진행하였다.

실제 해결 방법

1. 도커파일에서는 크롬만 설치하도록 수정

[수정 완료한 Dockerfile]

# JDK 17을 포함한 OpenJDK 이미지를 베이스 이미지로 사용
FROM openjdk:17-jdk-slim

# 필수 패키지 설치
RUN apt-get update && apt-get install -y wget curl unzip

# 작업 디렉토리를 설정합니다.
WORKDIR /app

# 스프링 애플리케이션 JAR 파일을 컨테이너로 복사합니다.
COPY ./build/libs/notify-crawler-0.0.1-SNAPSHOT.jar /app/notify-crawler.jar

# 크롬 설치
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN apt-get install -y ./google-chrome-stable_current_amd64.deb
RUN rm ./google-chrome-stable_current_amd64.deb

# 크롬 버전 확인
RUN google-chrome --version

# 포트를 엽니다.
EXPOSE 8082

# 어플리케이션을 실행합니다.
ENTRYPOINT ["java", "-jar", "/app/notify-crawler.jar"]

보면 드라이버를 설치하는 부분과 환경변수를 설정하는 부분들을 제거했다.

2. build.gradle은 셀레니움 버젼을 4.6 이상으로 바꾸고 웹 드라이버 의존성을 삭제

[기존의 build.gradle]

	// Selenium WebDriver
	implementation 'org.seleniumhq.selenium:selenium-java:4.1.0'
	// Chrome WebDriver
	implementation 'io.github.bonigarcia:webdrivermanager:5.0.3'

[수정 완료한 build.gradle]

	// Selenium WebDriver
	implementation 'org.seleniumhq.selenium:selenium-java:4.8.0'

그런데 여전히 오류가 발생했다.

그래서 이번에는 크롬 드라이버 옵션을 추가하였다.

        ChromeOptions options = new ChromeOptions();
        // Headless 모드 활성화
        options.addArguments("--headless");
        options.addArguments("--no-sandbox"); // 추가한 옵션
        options.addArguments("--disable-dev-shm-usage");
        options.addArguments("--disable-gpu"); //추가한 옵션
        options.addArguments("--ignore-ssl-errors=yes");
        options.addArguments("--ignore-certificate-errors");

추가한 옵션은 아래와 갗은 기능을 한다.

짜잔!! 아래의 결과처럼 오류를 해결하였다!!
이걸로 하루를 날렸었는데 블로그를 쓰면서 각잡고 하다보니 금방 해결했다 😀😀


참고:

profile
사용자의 입장에서 생각하며 문제를 해결하는 백엔드 개발자입니다✍

0개의 댓글