From ca8c45e7d284ac41b134d6686b2b34f6e5c9a8fb Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Wed, 2 Jul 2025 01:33:19 +0700 Subject: [PATCH] Docker: Env var flag to upgrade latest version of Chrome and ChromeDriver Signed-off-by: Viet Nguyen Duc --- ENV_VARIABLES.md | 1 + NodeBase/start-selenium-node.sh | 7 ++ NodeChrome/Dockerfile | 49 +++---------- NodeChrome/install-chrome.sh | 45 ++++++++++++ NodeChrome/install-chromedriver.sh | 72 +++++++++++++++++++ NodeChrome/update-chrome-components.sh | 57 +++++++++++++++ NodeChrome/wrap_chrome_binary | 4 +- Standalone/start-selenium-standalone.sh | 7 ++ .../generate_list_env_vars/description.yaml | 5 ++ scripts/generate_list_env_vars/value.yaml | 2 + 10 files changed, 208 insertions(+), 41 deletions(-) create mode 100755 NodeChrome/install-chrome.sh create mode 100755 NodeChrome/install-chromedriver.sh create mode 100755 NodeChrome/update-chrome-components.sh diff --git a/ENV_VARIABLES.md b/ENV_VARIABLES.md index 19ef488f10..5478297a7b 100644 --- a/ENV_VARIABLES.md +++ b/ENV_VARIABLES.md @@ -153,3 +153,4 @@ | SE_VIDEO_CRF | | | | | SE_VIDEO_MAXRATE | | | | | SE_NODE_DELETE_SESSION_ON_UI | true | Enable capability to support deleting session on Grid UI | --delete-session-on-ui | +| SE_UPDATE_CHROME_COMPONENTS | | Applicable for node-chrome, standalone-chrome (arch linux/amd64). Update the latest version of Chrome and ChromeDriver at the beginning of the container startup. Read more: [#2872](https://github.com/SeleniumHQ/docker-selenium/pull/2872) | | diff --git a/NodeBase/start-selenium-node.sh b/NodeBase/start-selenium-node.sh index 4ac805f411..fa0433e9f7 100755 --- a/NodeBase/start-selenium-node.sh +++ b/NodeBase/start-selenium-node.sh @@ -1,5 +1,12 @@ #!/bin/bash +# Check if Chrome components update is enabled +if [ "${SE_UPDATE_CHROME_COMPONENTS}" = "true" ] && [ -f /opt/bin/update-chrome-components.sh ]; then + echo "Chrome components update enabled, checking for updates..." + echo "Note that after the container gets restarted, updated binaries will be lost unless you call the update script within the build container process." + /opt/bin/update-chrome-components.sh +fi + # Start the pulseaudio server pulseaudio -D --exit-idle-time=-1 diff --git a/NodeChrome/Dockerfile b/NodeChrome/Dockerfile index 84d1da1a03..fa4f3b320a 100644 --- a/NodeChrome/Dockerfile +++ b/NodeChrome/Dockerfile @@ -16,26 +16,16 @@ USER root # google-chrome-unstable #============================================ ARG CHROME_VERSION="google-chrome-stable" -RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor | tee /etc/apt/trusted.gpg.d/google.gpg >/dev/null \ - && echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \ - && apt-get update -qqy \ - && if echo "${CHROME_VERSION}" | grep -qE "google-chrome-stable[_|=][0-9]*"; \ - then \ - CHROME_VERSION=$(echo "$CHROME_VERSION" | tr '=' '_') \ - && wget -qO google-chrome.deb "https://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/${CHROME_VERSION}_$(dpkg --print-architecture).deb" \ - && apt-get -qqy --no-install-recommends install --allow-downgrades ./google-chrome.deb \ - && rm -rf google-chrome.deb ; \ - else \ - apt-get -qqy --no-install-recommends install ${CHROME_VERSION} ; \ - fi \ - && rm /etc/apt/sources.list.d/google-chrome.list \ - && rm -rf /var/lib/apt/lists/* /var/cache/apt/* +COPY --chown="${SEL_UID}:${SEL_GID}" install-chrome.sh update-chrome-components.sh /opt/bin/ +RUN chmod +x /opt/bin/install-chrome.sh /opt/bin/update-chrome-components.sh \ + && /opt/bin/install-chrome.sh #================================= # Chrome Launch Script Wrapper #================================= -COPY wrap_chrome_binary /opt/bin/wrap_chrome_binary -RUN /opt/bin/wrap_chrome_binary +COPY --chown="${SEL_UID}:${SEL_GID}" wrap_chrome_binary /opt/bin/wrap_chrome_binary +RUN chmod +x /opt/bin/wrap_chrome_binary \ + && /opt/bin/wrap_chrome_binary #============================================ # Chrome webdriver @@ -44,30 +34,9 @@ RUN /opt/bin/wrap_chrome_binary # Latest released version will be used by default #============================================ ARG CHROME_DRIVER_VERSION -RUN DRIVER_ARCH=$(if [ "$(dpkg --print-architecture)" = "amd64" ]; then echo "linux64"; else echo "linux-aarch64"; fi) \ - && if [ ! -z "$CHROME_DRIVER_VERSION" ]; \ - then CHROME_DRIVER_URL=https://storage.googleapis.com/chrome-for-testing-public/$CHROME_DRIVER_VERSION/${DRIVER_ARCH}/chromedriver-${DRIVER_ARCH}.zip ; \ - else CHROME_MAJOR_VERSION=$(google-chrome --version | sed -E "s/.* ([0-9]+)(\.[0-9]+){3}.*/\1/") \ - && if [ $CHROME_MAJOR_VERSION -lt 115 ]; then \ - echo "Geting ChromeDriver latest version from https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_MAJOR_VERSION}" \ - && CHROME_DRIVER_VERSION=$(wget -qO- https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_MAJOR_VERSION} | sed 's/\r$//') \ - && CHROME_DRIVER_URL=https://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip ; \ - else \ - echo "Geting ChromeDriver latest version from https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${CHROME_MAJOR_VERSION}" \ - && CHROME_DRIVER_VERSION=$(wget -qO- https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${CHROME_MAJOR_VERSION} | sed 's/\r$//') \ - && CHROME_DRIVER_URL=https://storage.googleapis.com/chrome-for-testing-public/$CHROME_DRIVER_VERSION/${DRIVER_ARCH}/chromedriver-${DRIVER_ARCH}.zip ; \ - fi \ - fi \ - && echo "Using ChromeDriver from: "$CHROME_DRIVER_URL \ - && echo "Using ChromeDriver version: "$CHROME_DRIVER_VERSION \ - && wget --no-verbose -O /tmp/chromedriver_${DRIVER_ARCH}.zip $CHROME_DRIVER_URL \ - && rm -rf /opt/selenium/chromedriver \ - && unzip /tmp/chromedriver_${DRIVER_ARCH}.zip -d /opt/selenium \ - && rm /tmp/chromedriver_${DRIVER_ARCH}.zip \ - && mv /opt/selenium/chromedriver /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION || true \ - && mv /opt/selenium/chromedriver-${DRIVER_ARCH}/chromedriver /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION || true \ - && chmod 755 /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION \ - && ln -fs /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION /usr/bin/chromedriver +COPY --chown="${SEL_UID}:${SEL_GID}" install-chromedriver.sh /opt/bin/ +RUN chmod +x /opt/bin/install-chromedriver.sh \ + && /opt/bin/install-chromedriver.sh #============================================ # Chrome cleanup script and supervisord file diff --git a/NodeChrome/install-chrome.sh b/NodeChrome/install-chrome.sh new file mode 100755 index 0000000000..01dea4d20f --- /dev/null +++ b/NodeChrome/install-chrome.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +#============================================ +# Google Chrome Installation Script +#============================================ +# This script installs Google Chrome with support for: +# - Different channels (stable, beta, unstable) +# - Specific versions +# - Architecture detection +#============================================ + +set -e + +# Default Chrome version/channel +CHROME_VERSION="${CHROME_VERSION:-google-chrome-stable}" + +echo "Installing Google Chrome: ${CHROME_VERSION}" + +# Add Google Chrome repository +wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor | tee /etc/apt/trusted.gpg.d/google.gpg >/dev/null +echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >>/etc/apt/sources.list.d/google-chrome.list + +# Update package list +apt-get update -qqy + +# Install Chrome based on version specification +if echo "${CHROME_VERSION}" | grep -qE "google-chrome-stable[_|=][0-9]*"; then + # Install specific version + CHROME_VERSION=$(echo "$CHROME_VERSION" | tr '=' '_') + echo "Installing specific Chrome version: ${CHROME_VERSION}" + wget -qO google-chrome.deb "https://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/${CHROME_VERSION}_$(dpkg --print-architecture).deb" + apt-get -qqy --no-install-recommends install --allow-downgrades ./google-chrome.deb + rm -rf google-chrome.deb +else + # Install from repository (stable, beta, unstable) + echo "Installing Chrome channel: ${CHROME_VERSION}" + apt-get -qqy --no-install-recommends install ${CHROME_VERSION} +fi + +# Cleanup +rm /etc/apt/sources.list.d/google-chrome.list +rm -rf /var/lib/apt/lists/* /var/cache/apt/* + +echo "Google Chrome installation completed" +google-chrome --version diff --git a/NodeChrome/install-chromedriver.sh b/NodeChrome/install-chromedriver.sh new file mode 100755 index 0000000000..1b95425683 --- /dev/null +++ b/NodeChrome/install-chromedriver.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +#============================================ +# ChromeDriver Installation Script +#============================================ +# This script installs ChromeDriver with support for: +# - Automatic version detection based on Chrome version +# - Specific version installation +# - Architecture detection +#============================================ + +set -e + +# Default ChromeDriver version (empty for auto-detection) +CHROME_DRIVER_VERSION="${CHROME_DRIVER_VERSION:-}" + +echo "Installing ChromeDriver..." + +# Detect architecture +DRIVER_ARCH=$(if [ "$(dpkg --print-architecture)" = "amd64" ]; then echo "linux64"; else echo "linux-aarch64"; fi) +echo "Detected architecture: ${DRIVER_ARCH}" + +# Determine ChromeDriver version and URL +if [ ! -z "$CHROME_DRIVER_VERSION" ]; then + # Use specified version + echo "Using specified ChromeDriver version: ${CHROME_DRIVER_VERSION}" + CHROME_DRIVER_URL="https://storage.googleapis.com/chrome-for-testing-public/$CHROME_DRIVER_VERSION/${DRIVER_ARCH}/chromedriver-${DRIVER_ARCH}.zip" +else + # Auto-detect version based on Chrome version + CHROME_MAJOR_VERSION=$(google-chrome --version | sed -E "s/.* ([0-9]+)(\.[0-9]+){3}.*/\1/") + echo "Detected Chrome major version: ${CHROME_MAJOR_VERSION}" + + if [ $CHROME_MAJOR_VERSION -lt 115 ]; then + # Use old ChromeDriver API for versions < 115 + echo "Getting ChromeDriver latest version from https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_MAJOR_VERSION}" + CHROME_DRIVER_VERSION=$(wget -qO- https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_MAJOR_VERSION} | sed 's/\r$//') + CHROME_DRIVER_URL="https://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip" + else + # Use new Chrome for Testing API for versions >= 115 + echo "Getting ChromeDriver latest version from https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${CHROME_MAJOR_VERSION}" + CHROME_DRIVER_VERSION=$(wget -qO- https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${CHROME_MAJOR_VERSION} | sed 's/\r$//') + CHROME_DRIVER_URL="https://storage.googleapis.com/chrome-for-testing-public/$CHROME_DRIVER_VERSION/${DRIVER_ARCH}/chromedriver-${DRIVER_ARCH}.zip" + fi +fi + +echo "Using ChromeDriver from: ${CHROME_DRIVER_URL}" +echo "Using ChromeDriver version: ${CHROME_DRIVER_VERSION}" + +# Download and install ChromeDriver +wget --no-verbose -O /tmp/chromedriver_${DRIVER_ARCH}.zip $CHROME_DRIVER_URL + +# Remove existing ChromeDriver +rm -rf /opt/selenium/chromedriver + +# Extract ChromeDriver +unzip /tmp/chromedriver_${DRIVER_ARCH}.zip -d /opt/selenium +rm /tmp/chromedriver_${DRIVER_ARCH}.zip + +# Handle different extraction patterns +if [ -f "/opt/selenium/chromedriver" ]; then + mv /opt/selenium/chromedriver /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION +elif [ -f "/opt/selenium/chromedriver-${DRIVER_ARCH}/chromedriver" ]; then + mv /opt/selenium/chromedriver-${DRIVER_ARCH}/chromedriver /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION + rm -rf /opt/selenium/chromedriver-${DRIVER_ARCH} +fi + +# Set permissions and create symlink +chmod 755 /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION +ln -fs /opt/selenium/chromedriver-$CHROME_DRIVER_VERSION /usr/bin/chromedriver + +echo "ChromeDriver installation completed" +chromedriver --version diff --git a/NodeChrome/update-chrome-components.sh b/NodeChrome/update-chrome-components.sh new file mode 100755 index 0000000000..49111c54f7 --- /dev/null +++ b/NodeChrome/update-chrome-components.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +#============================================ +# Chrome Components Update Script +#============================================ +# This script updates Chrome and ChromeDriver to latest versions +# Can be run at container startup to ensure latest versions +#============================================ + +set -e + +# Check if update is enabled via environment variable +if [ "${SE_UPDATE_CHROME_COMPONENTS}" != "true" ]; then + echo "Chrome components update disabled (SE_UPDATE_CHROME_COMPONENTS != true)" + exit 0 +fi + +echo "Starting Chrome components update..." + +# Check if we have sudo access +if ! sudo -n true 2>/dev/null; then + echo "Warning: No sudo access available. Chrome components update skipped." + echo "To enable updates, ensure the container user has sudo privileges." + exit 0 +fi + +# Update Chrome if needed +echo "Checking for Chrome updates..." +CURRENT_CHROME_VERSION=$(google-chrome --version 2>/dev/null || echo "Chrome not found") + +if [ "$CURRENT_CHROME_VERSION" = "Chrome not found" ]; then + echo "Chrome not found, installing..." + sudo /opt/bin/install-chrome.sh +else + echo "Current Chrome version: $CURRENT_CHROME_VERSION" + echo "Updating Chrome to latest version..." + sudo /opt/bin/install-chrome.sh + sudo /opt/bin/wrap_chrome_binary +fi + +# Update ChromeDriver if needed +echo "Checking for ChromeDriver updates..." +CURRENT_CHROMEDRIVER_VERSION=$(chromedriver --version 2>/dev/null | head -1 || echo "ChromeDriver not found") + +if [ "$CURRENT_CHROMEDRIVER_VERSION" = "ChromeDriver not found" ]; then + echo "ChromeDriver not found, installing..." + sudo /opt/bin/install-chromedriver.sh +else + echo "Current ChromeDriver version: $CURRENT_CHROMEDRIVER_VERSION" + echo "Updating ChromeDriver to latest compatible version..." + sudo /opt/bin/install-chromedriver.sh +fi + +echo "Chrome components update completed" +echo "Final versions:" +google-chrome --version +chromedriver --version diff --git a/NodeChrome/wrap_chrome_binary b/NodeChrome/wrap_chrome_binary index ff97ca1bb5..ddf1304bc6 100755 --- a/NodeChrome/wrap_chrome_binary +++ b/NodeChrome/wrap_chrome_binary @@ -1,4 +1,6 @@ -#!/bin/bash +#!/usr/bin/env bash + +set -e WRAPPER_PATH=$(readlink -f /usr/bin/google-chrome) BASE_PATH="$WRAPPER_PATH-base" diff --git a/Standalone/start-selenium-standalone.sh b/Standalone/start-selenium-standalone.sh index dd8daf95fd..f23fa628f8 100755 --- a/Standalone/start-selenium-standalone.sh +++ b/Standalone/start-selenium-standalone.sh @@ -2,6 +2,13 @@ # # IMPORTANT: Change this file only in directory Standalone! +# Check if Chrome components update is enabled +if [ "${SE_UPDATE_CHROME_COMPONENTS}" = "true" ] && [ -f /opt/bin/update-chrome-components.sh ]; then + echo "Chrome components update enabled, checking for updates..." + echo "Note that after the container gets restarted, updated binaries will be lost unless you call the update script within the build container process." + /opt/bin/update-chrome-components.sh +fi + # Start the pulseaudio server pulseaudio -D --exit-idle-time=-1 diff --git a/scripts/generate_list_env_vars/description.yaml b/scripts/generate_list_env_vars/description.yaml index 61a3c15758..e46f88f6e1 100644 --- a/scripts/generate_list_env_vars/description.yaml +++ b/scripts/generate_list_env_vars/description.yaml @@ -468,3 +468,8 @@ - name: SE_NODE_DELETE_SESSION_ON_UI description: Enable capability to support deleting session on Grid UI cli: --delete-session-on-ui +- name: SE_UPDATE_CHROME_COMPONENTS + description: 'Applicable for node-chrome, standalone-chrome (arch linux/amd64). + Update the latest version of Chrome and ChromeDriver at the beginning of the container + startup. Read more: [#2872](https://github.com/SeleniumHQ/docker-selenium/pull/2872)' + cli: '' diff --git a/scripts/generate_list_env_vars/value.yaml b/scripts/generate_list_env_vars/value.yaml index b3887cb11a..91ea2b6910 100644 --- a/scripts/generate_list_env_vars/value.yaml +++ b/scripts/generate_list_env_vars/value.yaml @@ -252,6 +252,8 @@ default: '5' - name: SE_SUPERVISORD_UNIX_SERVER_PASSWORD default: secret +- name: SE_UPDATE_CHROME_COMPONENTS + default: '' - name: SE_UPLOAD_COMMAND default: '' - name: SE_UPLOAD_DESTINATION_PREFIX