Cloud Run에서 헤드리스 Chrome 사용

Google Cloud Functions와 같은 서비스에서 헤드리스 Chrome을 사용하려는 사람들을 자주 봅니다. "Headless Chrome"이라는 문구는 매우 으스스하게 들릴 수 있지만 이는 GUI 없이 실행되고 프로그래밍 방식으로 상호 작용하는 일반 Chrome 브라우저를 의미합니다.

불행히도 필요한 Chrome 바이너리는 Cloud Functions 런타임에 설치되지 않으며 Python 종속 항목을 설치하는 것 외에 런타임을 수정할 방법이 없습니다.

그러나 한 가지 대안은 Cloud Run 을 사용하는 것입니다. 그러면 Chrome 설치를 포함하여 런타임을 완전히 사용자 지정할 수 있습니다! 그렇게 합시다.

구성: Dockerfile



먼저 Dockerfile 를 생성합니다. 이것은 공식 Python 기본 이미지를 사용하고, 몇 가지 추가 종속성을 설치하고, Chrome을 설치하고, 애플리케이션의 종속성을 설치합니다.

# Use the official Python image.
# https://hub.docker.com/_/python
FROM python:3.7

# Install manually all the missing libraries
RUN apt-get update
RUN apt-get install -y gconf-service libasound2 libatk1.0-0 libcairo2 libcups2 libfontconfig1 libgdk-pixbuf2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libxss1 fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils

# Install Chrome
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN dpkg -i google-chrome-stable_current_amd64.deb; apt-get -fy install

# Install Python dependencies.
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . .

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 main:app


구성: requirements.txt



이 파일Dockerfile은 모든 Python 종속 항목의 특정 버전이 포함된 파일requirements.txt을 사용합니다. selenium 및 설치한 Chrome 버전에 해당하는 프로젝트의 특정 버전 chromedriver-binary 을 설치해야 합니다.

# requirements.txt

Flask==1.0.2
gunicorn==19.9.0
selenium==3.141.0
chromedriver-binary==77.0.3865.40.0


구성: main.py



마지막으로 Flask, Selenium을 사용하여 Python 애플리케이션을 작성합니다.

# main.py

from flask import Flask, send_file
from selenium import webdriver
import chromedriver_binary  # Adds chromedriver binary to path

app = Flask(__name__)

# The following options are required to make headless Chrome
# work in a Docker container
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("window-size=1024,768")
chrome_options.add_argument("--no-sandbox")

# Initialize a new browser
browser = webdriver.Chrome(chrome_options=chrome_options)


@app.route("/")
def hello_world():
    browser.get("https://www.google.com/search?q=headless+horseman&tbm=isch")
    browser.save_screenshot("spooky.png")
    return send_file("spooky.png")


테스트 및 배포



Docker가 로컬에 설치되어 있으면 이를 실행하여 테스트할 수 있습니다.

$ docker build -t my_screenshot_service .
$ docker run --rm -p 8080:8080 -e PORT=8080 my_screenshot_service


http://localhost:8080에서 확인하세요.



그렇지 않으면 Cloud Run에 직접 배포할 수 있습니다.

$ gcloud builds submit --tag gcr.io/YOUR_PROJECT/my_screenshot_service
$ gcloud beta run deploy my_screenshot_service --image gcr.io/YOUR_PROJECT/my_screenshot_service --region us-central1 --platform managed


그리고 그게 다야!

몇 가지 참고 사항:
  • Docker 컨테이너와의 호환성을 보장하기 위해 --no-sandbox를 사용하고 있으므로 이러한 서비스는 신뢰할 수 있는 URL로만 지정하십시오.
  • 이러한 서비스를 사용자 입력에 노출할 때는 주의하십시오. 예를 들어 스크린샷을 찍는 URL을 사용자가 제공한 경우 파일 시스템에 있는 모든 파일의 스크린샷도 찍을 수 있습니다!
  • 더 나은 보안을 위해 반드시 권한이 없는 새 서비스 계정을 생성하고 이를 서비스의 ID로 사용하십시오. 예제는 https://cloud.google.com/run/docs/securing/service-identity을 참조하십시오.
  • 좋은 웹페이지 즐겨찾기