Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update SonarQube images to version 8.3 #7703

Merged
merged 1 commit into from
Apr 30, 2020

Conversation

michal-duda-sonarsource
Copy link
Contributor

Hi
Please do not merge this pull request after reviewing, there is still some time until we release SonarQube 8.3. We are opening a PR now because we made changes to the image and we'd be happy to get feedback and apply changes earlier (if needed) for smoother release.
Thanks!

@michal-duda-sonarsource michal-duda-sonarsource changed the title SonarQube 8.3 Update SonarQube images to version 8.3 Mar 30, 2020
@yosifkit
Copy link
Member

Diff:
diff --git a/_bashbrew-list b/_bashbrew-list
index 3eacb14..813ce8d 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -3,9 +3,9 @@ sonarqube:7.9.3-community
 sonarqube:8-community
 sonarqube:8-developer
 sonarqube:8-enterprise
-sonarqube:8.2-community
-sonarqube:8.2-developer
-sonarqube:8.2-enterprise
+sonarqube:8.3-community
+sonarqube:8.3-developer
+sonarqube:8.3-enterprise
 sonarqube:community
 sonarqube:developer
 sonarqube:enterprise
diff --git a/sonarqube_developer/Dockerfile b/sonarqube_developer/Dockerfile
index 8516748..2178aaa 100644
--- a/sonarqube_developer/Dockerfile
+++ b/sonarqube_developer/Dockerfile
@@ -1,46 +1,64 @@
-FROM openjdk:11-jre-slim
-
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
-
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
-
 ARG SONARQUBE_VERSION=8.2.0.32929
-ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-developer/sonarqube-developer-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
+FROM adoptopenjdk/openjdk11:alpine-jre as build
+ARG SONARQUBE_VERSION
+ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-developer/sonarqube-developer-${SONARQUBE_VERSION}.zip
+ENV SONARQUBE_HOME=/opt/sonarqube \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && apk update \
+    && apk upgrade \
+    && apk add --no-cache --update gnupg unzip curl \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
         gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error  "$SONARQUBE_ZIP_URL" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error  "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf $SONARQUBE_HOME/bin/* \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values) 
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+    
+COPY run.sh sonar.sh $SONARQUBE_HOME/bin/
+
+FROM adoptopenjdk/openjdk11:alpine-jre
+ARG SONARQUBE_VERSION
+ENV SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SONARQUBE_HOME="/opt/sonarqube" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp" \
+    ES_TMPDIR="/opt/sonarqube/temp"
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && apk update \
+    && apk upgrade \
+    && apk add --no-cache --update bash su-exec ttf-dejavu
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+COPY --chown=sonarqube:sonarqube --from=build ${SONARQUBE_HOME} ${SONARQUBE_HOME}
+
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
\ No newline at end of file
diff --git a/sonarqube_developer/run.sh b/sonarqube_developer/run.sh
index d7fc3a4..ecc7443 100755
--- a/sonarqube_developer/run.sh
+++ b/sonarqube_developer/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
 
 declare -a sq_opts
-
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
+            echo "read entry: ${sq_opts[*]}"
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    set -- "$@" "${sq_opts[*]}"
+fi
+
+exec "$@"
\ No newline at end of file
diff --git a/sonarqube_developer/sonar.sh b/sonarqube_developer/sonar.sh
new file mode 100755
index 0000000..695233b
--- /dev/null
+++ b/sonarqube_developer/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" -Dsonar.log.console=true $@
\ No newline at end of file
diff --git a/sonarqube_enterprise/Dockerfile b/sonarqube_enterprise/Dockerfile
index 3d17bf5..9bb7e46 100644
--- a/sonarqube_enterprise/Dockerfile
+++ b/sonarqube_enterprise/Dockerfile
@@ -1,46 +1,64 @@
-FROM openjdk:11-jre-slim
-
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
-
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
-
 ARG SONARQUBE_VERSION=8.2.0.32929
-ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-enterprise/sonarqube-enterprise-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
+FROM adoptopenjdk/openjdk11:alpine-jre as build
+ARG SONARQUBE_VERSION
+ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-enterprise/sonarqube-enterprise-${SONARQUBE_VERSION}.zip
+ENV SONARQUBE_HOME=/opt/sonarqube \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && apk update \
+    && apk upgrade \
+    && apk add --no-cache --update gnupg unzip curl \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
         gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "${SONARQUBE_ZIP_URL}" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error  "$SONARQUBE_ZIP_URL" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error  "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf $SONARQUBE_HOME/bin/* \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values) 
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+    
+COPY run.sh sonar.sh $SONARQUBE_HOME/bin/
+
+FROM adoptopenjdk/openjdk11:alpine-jre
+ARG SONARQUBE_VERSION
+ENV SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SONARQUBE_HOME="/opt/sonarqube" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp" \
+    ES_TMPDIR="/opt/sonarqube/temp"
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && apk update \
+    && apk upgrade \
+    && apk add --no-cache --update bash su-exec ttf-dejavu
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+COPY --chown=sonarqube:sonarqube --from=build ${SONARQUBE_HOME} ${SONARQUBE_HOME}
+
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
\ No newline at end of file
diff --git a/sonarqube_enterprise/run.sh b/sonarqube_enterprise/run.sh
index d7fc3a4..ecc7443 100755
--- a/sonarqube_enterprise/run.sh
+++ b/sonarqube_enterprise/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
 
 declare -a sq_opts
-
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
+            echo "read entry: ${sq_opts[*]}"
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    set -- "$@" "${sq_opts[*]}"
+fi
+
+exec "$@"
\ No newline at end of file
diff --git a/sonarqube_enterprise/sonar.sh b/sonarqube_enterprise/sonar.sh
new file mode 100755
index 0000000..695233b
--- /dev/null
+++ b/sonarqube_enterprise/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" -Dsonar.log.console=true $@
\ No newline at end of file
diff --git a/sonarqube_latest/Dockerfile b/sonarqube_latest/Dockerfile
index ccdcdfe..c357f41 100644
--- a/sonarqube_latest/Dockerfile
+++ b/sonarqube_latest/Dockerfile
@@ -1,46 +1,64 @@
-FROM openjdk:11-jre-slim
-
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
-
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
-
 ARG SONARQUBE_VERSION=8.2.0.32929
-ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
+FROM adoptopenjdk/openjdk11:alpine-jre as build
+ARG SONARQUBE_VERSION
+ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-${SONARQUBE_VERSION}.zip
+ENV SONARQUBE_HOME=/opt/sonarqube \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && apk update \
+    && apk upgrade \
+    && apk add --no-cache --update gnupg unzip curl \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
         gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error  "$SONARQUBE_ZIP_URL" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error  "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf $SONARQUBE_HOME/bin/* \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values) 
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+    
+COPY run.sh sonar.sh $SONARQUBE_HOME/bin/
+
+FROM adoptopenjdk/openjdk11:alpine-jre
+ARG SONARQUBE_VERSION
+ENV SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SONARQUBE_HOME="/opt/sonarqube" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp" \
+    ES_TMPDIR="/opt/sonarqube/temp"
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && apk update \
+    && apk upgrade \
+    && apk add --no-cache --update bash su-exec ttf-dejavu
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+COPY --chown=sonarqube:sonarqube --from=build ${SONARQUBE_HOME} ${SONARQUBE_HOME}
+
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
\ No newline at end of file
diff --git a/sonarqube_latest/run.sh b/sonarqube_latest/run.sh
index d7fc3a4..ecc7443 100755
--- a/sonarqube_latest/run.sh
+++ b/sonarqube_latest/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
 
 declare -a sq_opts
-
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
+            echo "read entry: ${sq_opts[*]}"
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    set -- "$@" "${sq_opts[*]}"
+fi
+
+exec "$@"
\ No newline at end of file
diff --git a/sonarqube_latest/sonar.sh b/sonarqube_latest/sonar.sh
new file mode 100755
index 0000000..695233b
--- /dev/null
+++ b/sonarqube_latest/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" -Dsonar.log.console=true $@
\ No newline at end of file

@yosifkit
Copy link
Member

yosifkit commented Apr 1, 2020

  1. ARG SONARQUBE_VERSION (and SONARQUBE_ZIP_URL) should be as late as possible in the Dockerfile (i.e. right before a RUN line that uses it)

    • any Dockerfile line that could be above it, should be (then some layers could be shared across versions)
  2. FROM adoptopenjdk/openjdk11:alpine-jre is not allowed in official-images. "This repo provides Unofficial AdoptOpenJDK Docker Images"

    No official images can be derived from, or depend on, non-official images

    - official-images readme

  3. Since this image does a multi-stage build to basically prevent a single line of apk del --no-network gnupg unzip curl, this is not an acceptable use of a multi-stage build for official-images. (see also https://github.com/docker-library/faq/#multi-stage-builds)

    We try hard to avoid multi-stage builds in almost every instance. One of the major issues we have with multi-stage builds is below.

    On the official-images build infrastructure, "we don't have a clean way to preserve the cache for the intermediate stages", so the layers will get deleted when we clean up images that are "ripe". The practical implication of this is that since the build cache for these untagged stages could be deleted at any time, we will end up spending extra time rebuilding them and users will pull "new" images that are unchanged.

    (Ref Update jetty to include jdk13 and slim images #7134 (comment) and Add initial "multi-stage" support in bashbrew #5929 (comment))

  4. upgrade is often going to cause problems -- we prefer to instead update the base image and rebuild

    Avoid RUN apt-get upgrade and dist-upgrade, as many of the “essential” packages from the parent images cannot upgrade inside an unprivileged container. If a package contained in the parent image is out-of-date, contact its maintainers.

    - https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#apt-get

  5. --no-cache implies --update (so apk update and --update can be left out)

  6. may want quotes on your "$@" in sonar.sh (since it is always quoted before that point)

  7. 👍 to the run.sh; it all looks fine to me

@michal-duda-sonarsource
Copy link
Contributor Author

Thanks for the detailed feedback @yosifkit! I want to ask about point 2: would it be fine if we used official alpine image as base image and install openjdk JRE in it (with glibc probably)?

Let me give you some context for why we need to switch in the first place. We received complaints from our users that our images have vulnerabilities (reported by a couple of different SCA tools). Unfortunately we can't do much about them since they come from debian base image of openjdk:11-jre-slim. For reference here is a link to a vulnerability analysis done by one of these tools. Overall it seems like debian based images have quite a large number of discovered vulnerabilities.

We looked at some alternatives and adoptopenjdk/openjdk11:alpine-jre looked best according to criteria we've set. Overall alpine based images seem to have a better track record when it comes to the number of discovered vulnerabilities and how quickly they are addressed.

@michal-duda-sonarsource
Copy link
Contributor Author

@yosifkit can I get an answer to my question?

@yosifkit
Copy link
Member

would it be fine if we used official alpine image as base image and install openjdk JRE in it (with glibc probably)?

I don't see a problem from the official-images perspective, it is up to you to run on the distro that is best for your software. I'm still wary of running any Java based application on Alpine Linux given that openjdk doesn't really support it (docker-library/openjdk#235 (comment)).

As far as perceived vulnerabilities, I would point to our FAQ entry that attempts to explain that security scanners are often wrong (false positive) and that CVE's are commonly left unpatched in Distro packaging (like Debian, Ubuntu, RedHat, etc) for a variety of reasons (for example, too intrusive to backport). I would also point out that every current Debian (and Ubuntu) image is regenerated at least monthly and all official-images FROM them get rebuilt, but only some Alpine image get updated and thus only official-images FROM the changed versions get rebuilt.

@michal-duda-sonarsource michal-duda-sonarsource force-pushed the master branch 2 times, most recently from 81d1cc9 to c505bbf Compare April 15, 2020 15:06
@michal-duda-sonarsource
Copy link
Contributor Author

@yosifkit I applied changes based on your feedback and switched base image to alpine. Can you have another look please? Just as before, please don't merge it yet even if it's ok now. Thanks!

@yosifkit
Copy link
Member

Diff:
diff --git a/_bashbrew-list b/_bashbrew-list
index 3eacb14..813ce8d 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -3,9 +3,9 @@ sonarqube:7.9.3-community
 sonarqube:8-community
 sonarqube:8-developer
 sonarqube:8-enterprise
-sonarqube:8.2-community
-sonarqube:8.2-developer
-sonarqube:8.2-enterprise
+sonarqube:8.3-community
+sonarqube:8.3-developer
+sonarqube:8.3-enterprise
 sonarqube:community
 sonarqube:developer
 sonarqube:enterprise
diff --git a/sonarqube_developer/Dockerfile b/sonarqube_developer/Dockerfile
index 8516748..01445e8 100644
--- a/sonarqube_developer/Dockerfile
+++ b/sonarqube_developer/Dockerfile
@@ -1,46 +1,120 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+RUN apk add --no-cache --virtual .build-deps curl binutils \
+    && GLIBC_VER="2.31-r0" \
+    && ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" \
+    && GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz" \
+    && GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08" \
+    && ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz" \
+    && ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5 \
+    && curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
+    && SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2" \
+    && echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c - \
+    && curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk \
+    && curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk \
+    && curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk \
+    && /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true \
+    && echo "export LANG=$LANG" > /etc/profile.d/locale.sh \
+    && curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz \
+    && echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c - \
+    && mkdir /tmp/gcc \
+    && tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc \
+    && mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib \
+    && strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so* \
+    && curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz \
+    && echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c - \
+    && mkdir /tmp/libz \
+    && tar -xf /tmp/libz.tar.xz -C /tmp/libz \
+    && mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib \
+    && apk del --purge .build-deps glibc-i18n \
+    && rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
 ARG SONARQUBE_VERSION=8.2.0.32929
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-developer/sonarqube-developer-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_developer/run.sh b/sonarqube_developer/run.sh
index d7fc3a4..0ecb519 100755
--- a/sonarqube_developer/run.sh
+++ b/sonarqube_developer/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[*]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_developer/sonar.sh b/sonarqube_developer/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_developer/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"
diff --git a/sonarqube_enterprise/Dockerfile b/sonarqube_enterprise/Dockerfile
index 3d17bf5..bd07e3a 100644
--- a/sonarqube_enterprise/Dockerfile
+++ b/sonarqube_enterprise/Dockerfile
@@ -1,46 +1,120 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+RUN apk add --no-cache --virtual .build-deps curl binutils \
+    && GLIBC_VER="2.31-r0" \
+    && ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" \
+    && GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz" \
+    && GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08" \
+    && ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz" \
+    && ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5 \
+    && curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
+    && SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2" \
+    && echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c - \
+    && curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk \
+    && curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk \
+    && curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk \
+    && /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true \
+    && echo "export LANG=$LANG" > /etc/profile.d/locale.sh \
+    && curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz \
+    && echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c - \
+    && mkdir /tmp/gcc \
+    && tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc \
+    && mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib \
+    && strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so* \
+    && curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz \
+    && echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c - \
+    && mkdir /tmp/libz \
+    && tar -xf /tmp/libz.tar.xz -C /tmp/libz \
+    && mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib \
+    && apk del --purge .build-deps glibc-i18n \
+    && rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
 ARG SONARQUBE_VERSION=8.2.0.32929
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-enterprise/sonarqube-enterprise-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "${SONARQUBE_ZIP_URL}" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
     
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_enterprise/run.sh b/sonarqube_enterprise/run.sh
index d7fc3a4..0ecb519 100755
--- a/sonarqube_enterprise/run.sh
+++ b/sonarqube_enterprise/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[*]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_enterprise/sonar.sh b/sonarqube_enterprise/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_enterprise/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"
diff --git a/sonarqube_latest/Dockerfile b/sonarqube_latest/Dockerfile
index ccdcdfe..20c6fcd 100644
--- a/sonarqube_latest/Dockerfile
+++ b/sonarqube_latest/Dockerfile
@@ -1,46 +1,120 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+RUN apk add --no-cache --virtual .build-deps curl binutils \
+    && GLIBC_VER="2.31-r0" \
+    && ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" \
+    && GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz" \
+    && GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08" \
+    && ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz" \
+    && ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5 \
+    && curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
+    && SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2" \
+    && echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c - \
+    && curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk \
+    && curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk \
+    && curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk \
+    && apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk \
+    && /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true \
+    && echo "export LANG=$LANG" > /etc/profile.d/locale.sh \
+    && curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz \
+    && echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c - \
+    && mkdir /tmp/gcc \
+    && tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc \
+    && mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib \
+    && strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so* \
+    && curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz \
+    && echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c - \
+    && mkdir /tmp/libz \
+    && tar -xf /tmp/libz.tar.xz -C /tmp/libz \
+    && mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib \
+    && apk del --purge .build-deps glibc-i18n \
+    && rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
 ARG SONARQUBE_VERSION=8.2.0.32929
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_latest/run.sh b/sonarqube_latest/run.sh
index d7fc3a4..0ecb519 100755
--- a/sonarqube_latest/run.sh
+++ b/sonarqube_latest/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[*]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_latest/sonar.sh b/sonarqube_latest/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_latest/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"

@yosifkit
Copy link
Member

I noticed two bugs:

  1. the RUN line that installs glibc will not work as expected since && has higher association than ||, so it essentially becomes ( lines 7-23 ) || (lines 24-37)

    • the clearest fix would be to make the RUN start with set -eux; \ and swap to ; instead of && like the RUN that downloads OpenJDK
  2. run.sh moved to set -- "$@" "${sq_opts[*]}" which means that all values in sq_opts become a single quoted argument with spaces in it, so you probably want to switch back to "${sq_opts[@]}" so that each value in the array becomes its own quoted argument

    sq_opts=( "-Dfoo=bar" "-Dbaz=buzz" )
    # becomes
    bin/sonar.sh "$@" "-Dfoo=bar -Dbaz=buzz"

@michal-duda-sonarsource
Copy link
Contributor Author

Thanks, fixed both.

@michal-duda-sonarsource
Copy link
Contributor Author

@yosifkit is everything good then for merging this PR when we release SonarQube 8.3?

@yosifkit
Copy link
Member

curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \

I noticed that one curl was missing a -f. Everything else looks fine. cc @tianon

Diff:
diff --git a/_bashbrew-list b/_bashbrew-list
index 3eacb14..813ce8d 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -3,9 +3,9 @@ sonarqube:7.9.3-community
 sonarqube:8-community
 sonarqube:8-developer
 sonarqube:8-enterprise
-sonarqube:8.2-community
-sonarqube:8.2-developer
-sonarqube:8.2-enterprise
+sonarqube:8.3-community
+sonarqube:8.3-developer
+sonarqube:8.3-enterprise
 sonarqube:community
 sonarqube:developer
 sonarqube:enterprise
diff --git a/sonarqube_developer/Dockerfile b/sonarqube_developer/Dockerfile
index 8516748..c434ef9 100644
--- a/sonarqube_developer/Dockerfile
+++ b/sonarqube_developer/Dockerfile
@@ -1,46 +1,130 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+#
+# glibc setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .build-deps curl binutils; \
+    GLIBC_VER="2.31-r0"; \
+    ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download"; \
+    GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz"; \
+    GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08"; \
+    ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz"; \
+    ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5; \
+    curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub; \
+    SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2"; \
+    echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c -; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true; \
+    echo "export LANG=$LANG" > /etc/profile.d/locale.sh; \
+    curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz; \
+    echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/gcc; \
+    tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc; \
+    mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib; \
+    strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so*; \
+    curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz; \
+    echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/libz; \
+    tar -xf /tmp/libz.tar.xz -C /tmp/libz; \
+    mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib; \
+    apk del --purge .build-deps glibc-i18n; \
+    rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*;
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+#
+# AdoptOpenJDK/openjdk11 setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
+#
+# SonarQube setup
+#
 ARG SONARQUBE_VERSION=8.2.0.32929
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-developer/sonarqube-developer-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_developer/run.sh b/sonarqube_developer/run.sh
index d7fc3a4..e3770a0 100755
--- a/sonarqube_developer/run.sh
+++ b/sonarqube_developer/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[@]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_developer/sonar.sh b/sonarqube_developer/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_developer/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"
diff --git a/sonarqube_enterprise/Dockerfile b/sonarqube_enterprise/Dockerfile
index 3d17bf5..0d1590b 100644
--- a/sonarqube_enterprise/Dockerfile
+++ b/sonarqube_enterprise/Dockerfile
@@ -1,46 +1,130 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+#
+# glibc setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .build-deps curl binutils; \
+    GLIBC_VER="2.31-r0"; \
+    ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download"; \
+    GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz"; \
+    GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08"; \
+    ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz"; \
+    ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5; \
+    curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub; \
+    SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2"; \
+    echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c -; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true; \
+    echo "export LANG=$LANG" > /etc/profile.d/locale.sh; \
+    curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz; \
+    echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/gcc; \
+    tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc; \
+    mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib; \
+    strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so*; \
+    curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz; \
+    echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/libz; \
+    tar -xf /tmp/libz.tar.xz -C /tmp/libz; \
+    mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib; \
+    apk del --purge .build-deps glibc-i18n; \
+    rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*;
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+#
+# AdoptOpenJDK/openjdk11 setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
+#
+# SonarQube setup
+#
 ARG SONARQUBE_VERSION=8.2.0.32929
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-enterprise/sonarqube-enterprise-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "${SONARQUBE_ZIP_URL}" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
     
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_enterprise/run.sh b/sonarqube_enterprise/run.sh
index d7fc3a4..e3770a0 100755
--- a/sonarqube_enterprise/run.sh
+++ b/sonarqube_enterprise/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[@]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_enterprise/sonar.sh b/sonarqube_enterprise/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_enterprise/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"
diff --git a/sonarqube_latest/Dockerfile b/sonarqube_latest/Dockerfile
index ccdcdfe..069edca 100644
--- a/sonarqube_latest/Dockerfile
+++ b/sonarqube_latest/Dockerfile
@@ -1,46 +1,130 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+#
+# glibc setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .build-deps curl binutils; \
+    GLIBC_VER="2.31-r0"; \
+    ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download"; \
+    GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz"; \
+    GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08"; \
+    ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz"; \
+    ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5; \
+    curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub; \
+    SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2"; \
+    echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c -; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true; \
+    echo "export LANG=$LANG" > /etc/profile.d/locale.sh; \
+    curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz; \
+    echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/gcc; \
+    tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc; \
+    mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib; \
+    strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so*; \
+    curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz; \
+    echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/libz; \
+    tar -xf /tmp/libz.tar.xz -C /tmp/libz; \
+    mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib; \
+    apk del --purge .build-deps glibc-i18n; \
+    rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*;
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+#
+# AdoptOpenJDK/openjdk11 setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
+#
+# SonarQube setup
+#
 ARG SONARQUBE_VERSION=8.2.0.32929
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_latest/run.sh b/sonarqube_latest/run.sh
index d7fc3a4..e3770a0 100755
--- a/sonarqube_latest/run.sh
+++ b/sonarqube_latest/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[@]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_latest/sonar.sh b/sonarqube_latest/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_latest/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"

@michal-duda-sonarsource
Copy link
Contributor Author

@yosifkit @tianon I've fixed the release version of SonarQube and added missing -f to curl. I updated this PR with the correct commit. Everything is ready on our side so if everything looks good to you, please merge this PR as soon as possible. Thank you!

@yosifkit
Copy link
Member

Diff:
diff --git a/_bashbrew-list b/_bashbrew-list
index 3eacb14..813ce8d 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -3,9 +3,9 @@ sonarqube:7.9.3-community
 sonarqube:8-community
 sonarqube:8-developer
 sonarqube:8-enterprise
-sonarqube:8.2-community
-sonarqube:8.2-developer
-sonarqube:8.2-enterprise
+sonarqube:8.3-community
+sonarqube:8.3-developer
+sonarqube:8.3-enterprise
 sonarqube:community
 sonarqube:developer
 sonarqube:enterprise
diff --git a/sonarqube_developer/Dockerfile b/sonarqube_developer/Dockerfile
index 8516748..5a2ce31 100644
--- a/sonarqube_developer/Dockerfile
+++ b/sonarqube_developer/Dockerfile
@@ -1,46 +1,130 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+#
+# glibc setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .build-deps curl binutils; \
+    GLIBC_VER="2.31-r0"; \
+    ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download"; \
+    GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz"; \
+    GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08"; \
+    ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz"; \
+    ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5; \
+    curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub; \
+    SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2"; \
+    echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c -; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true; \
+    echo "export LANG=$LANG" > /etc/profile.d/locale.sh; \
+    curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz; \
+    echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/gcc; \
+    tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc; \
+    mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib; \
+    strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so*; \
+    curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz; \
+    echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/libz; \
+    tar -xf /tmp/libz.tar.xz -C /tmp/libz; \
+    mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib; \
+    apk del --purge .build-deps glibc-i18n; \
+    rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*;
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+#
+# AdoptOpenJDK/openjdk11 setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
-ARG SONARQUBE_VERSION=8.2.0.32929
+#
+# SonarQube setup
+#
+ARG SONARQUBE_VERSION=8.3.0.34182
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-developer/sonarqube-developer-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_developer/run.sh b/sonarqube_developer/run.sh
index d7fc3a4..e3770a0 100755
--- a/sonarqube_developer/run.sh
+++ b/sonarqube_developer/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[@]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_developer/sonar.sh b/sonarqube_developer/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_developer/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"
diff --git a/sonarqube_enterprise/Dockerfile b/sonarqube_enterprise/Dockerfile
index 3d17bf5..b16a430 100644
--- a/sonarqube_enterprise/Dockerfile
+++ b/sonarqube_enterprise/Dockerfile
@@ -1,46 +1,130 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+#
+# glibc setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .build-deps curl binutils; \
+    GLIBC_VER="2.31-r0"; \
+    ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download"; \
+    GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz"; \
+    GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08"; \
+    ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz"; \
+    ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5; \
+    curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub; \
+    SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2"; \
+    echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c -; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true; \
+    echo "export LANG=$LANG" > /etc/profile.d/locale.sh; \
+    curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz; \
+    echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/gcc; \
+    tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc; \
+    mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib; \
+    strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so*; \
+    curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz; \
+    echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/libz; \
+    tar -xf /tmp/libz.tar.xz -C /tmp/libz; \
+    mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib; \
+    apk del --purge .build-deps glibc-i18n; \
+    rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*;
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+#
+# AdoptOpenJDK/openjdk11 setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
-ARG SONARQUBE_VERSION=8.2.0.32929
+#
+# SonarQube setup
+#
+ARG SONARQUBE_VERSION=8.3.0.34182
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/CommercialDistribution/sonarqube-enterprise/sonarqube-enterprise-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "${SONARQUBE_ZIP_URL}" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
     
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_enterprise/run.sh b/sonarqube_enterprise/run.sh
index d7fc3a4..e3770a0 100755
--- a/sonarqube_enterprise/run.sh
+++ b/sonarqube_enterprise/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[@]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_enterprise/sonar.sh b/sonarqube_enterprise/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_enterprise/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"
diff --git a/sonarqube_latest/Dockerfile b/sonarqube_latest/Dockerfile
index ccdcdfe..33ac883 100644
--- a/sonarqube_latest/Dockerfile
+++ b/sonarqube_latest/Dockerfile
@@ -1,46 +1,130 @@
-FROM openjdk:11-jre-slim
+FROM alpine:3.11
+ENV JAVA_VERSION="jdk-11.0.6+10" \
+    LANG='en_US.UTF-8' \
+    LANGUAGE='en_US:en' \
+    LC_ALL='en_US.UTF-8'
 
-RUN apt-get update \
-    && apt-get install -y curl unzip gnupg2 libfreetype6 libfontconfig1 \
-    && rm -rf /var/lib/apt/lists/*
+#
+# glibc setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .build-deps curl binutils; \
+    GLIBC_VER="2.31-r0"; \
+    ALPINE_GLIBC_REPO="https://github.com/sgerrand/alpine-pkg-glibc/releases/download"; \
+    GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz"; \
+    GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08"; \
+    ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz"; \
+    ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5; \
+    curl -LfsS https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub; \
+    SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2"; \
+    echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c -; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-bin-${GLIBC_VER}.apk; \
+    curl -LfsS ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    apk add --no-cache /tmp/glibc-i18n-${GLIBC_VER}.apk; \
+    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true; \
+    echo "export LANG=$LANG" > /etc/profile.d/locale.sh; \
+    curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz; \
+    echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/gcc; \
+    tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc; \
+    mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib; \
+    strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so*; \
+    curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz; \
+    echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c -; \
+    mkdir /tmp/libz; \
+    tar -xf /tmp/libz.tar.xz -C /tmp/libz; \
+    mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib; \
+    apk del --purge .build-deps glibc-i18n; \
+    rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*;
 
-# Http port
-EXPOSE 9000
-
-RUN groupadd -r sonarqube && useradd -r -g sonarqube sonarqube
+#
+# AdoptOpenJDK/openjdk11 setup
+#
+RUN set -eux; \
+    apk add --no-cache --virtual .fetch-deps curl; \
+    ARCH="$(apk --print-arch)"; \
+    case "${ARCH}" in \
+       aarch64|arm64) \
+         ESUM='7ed04ed9ed7271528e7f03490f1fd7dfbbc2d391414bd6fe4dd80ec3bad76d30'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       ppc64el|ppc64le) \
+         ESUM='49231f2c36487b53141ade3f7eb291e2855138b14b1129f9acf435ea9cc0e899'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_ppc64le_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       s390x) \
+         ESUM='bcb3f46cbad742b08c81e922e313549c029f436ac7d91ef3c9bed8e4049d67d2'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_s390x_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       amd64|x86_64) \
+         ESUM='c5a4e69e2be0e3e5f5bb7c759960b20650967d0f571baad4a7f15b2c03bda352'; \
+         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz'; \
+         ;; \
+       *) \
+         echo "Unsupported arch: ${ARCH}"; \
+         exit 1; \
+         ;; \
+    esac; \
+    curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \
+    echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \
+    mkdir -p /opt/java/openjdk; \
+    cd /opt/java/openjdk; \
+    tar -xf /tmp/openjdk.tar.gz --strip-components=1; \
+    apk del --purge .fetch-deps; \
+    rm -rf /var/cache/apk/*; \
+    rm -rf /tmp/openjdk.tar.gz;
 
-ARG SONARQUBE_VERSION=8.2.0.32929
+#
+# SonarQube setup
+#
+ARG SONARQUBE_VERSION=8.3.0.34182
 ARG SONARQUBE_ZIP_URL=https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-${SONARQUBE_VERSION}.zip
-ENV SONAR_VERSION=${SONARQUBE_VERSION} \
-    SONARQUBE_HOME=/opt/sonarqube
+ENV JAVA_HOME=/opt/java/openjdk \
+    PATH="/opt/java/openjdk/bin:$PATH" \
+    SONARQUBE_HOME=/opt/sonarqube \
+    SONAR_VERSION="${SONARQUBE_VERSION}" \
+    SQ_DATA_DIR="/opt/sonarqube/data" \
+    SQ_EXTENSIONS_DIR="/opt/sonarqube/extensions" \
+    SQ_LOGS_DIR="/opt/sonarqube/logs" \
+    SQ_TEMP_DIR="/opt/sonarqube/temp"
 
-SHELL ["/bin/bash", "-c"]
-RUN sed -i -e "s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" \
-  "$JAVA_HOME/conf/security/java.security"
-
-# pub   2048R/D26468DE 2015-05-25
-#       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
-# uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
-# sub   2048R/06855C1D 2015-05-25
-RUN for server in $(shuf -e ha.pool.sks-keyservers.net \
+RUN set -ex \
+    && addgroup -S -g 1000 sonarqube \
+    && adduser -S -D -u 1000 -G sonarqube sonarqube \
+    && apk add --no-cache --virtual build-dependencies gnupg unzip curl \
+    && apk add --no-cache bash su-exec ttf-dejavu \
+    # pub   2048R/D26468DE 2015-05-25
+    #       Key fingerprint = F118 2E81 C792 9289 21DB  CAB4 CFCA 4A29 D264 68DE
+    # uid                  sonarsource_deployer (Sonarsource Deployer) <[email protected]>
+    # sub   2048R/06855C1D 2015-05-25
+    && sed --in-place --expression="s?securerandom.source=file:/dev/random?securerandom.source=file:/dev/urandom?g" "${JAVA_HOME}/conf/security/java.security" \
+    && for server in $(shuf -e ha.pool.sks-keyservers.net \
                             hkp://p80.pool.sks-keyservers.net:80 \
                             keyserver.ubuntu.com \
                             hkp://keyserver.ubuntu.com:80 \
                             pgp.mit.edu) ; do \
-      gpg --batch --keyserver "$server" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
+        gpg --batch --keyserver "${server}" --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE && break || : ; \
     done \
-    && set -x \
+    && mkdir --parents /opt \
     && cd /opt \
-    && curl -o sonarqube.zip -fsSL "$SONARQUBE_ZIP_URL" \
-    && curl -o sonarqube.zip.asc -fSL "${SONARQUBE_ZIP_URL}.asc" \
+    && curl --fail --location --output sonarqube.zip --silent --show-error "${SONARQUBE_ZIP_URL}" \
+    && curl --fail --location --output sonarqube.zip.asc --silent --show-error "${SONARQUBE_ZIP_URL}.asc" \
     && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
     && unzip -q sonarqube.zip \
     && mv "sonarqube-${SONARQUBE_VERSION}" sonarqube \
     && rm sonarqube.zip* \
-    && chown --recursive sonarqube:sonarqube "$SONARQUBE_HOME"
+    && rm -rf ${SONARQUBE_HOME}/bin/* \
+    && chown -R sonarqube:sonarqube ${SONARQUBE_HOME} \
+    # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
+    && chmod -R 777 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" \
+    && apk del --purge build-dependencies
 
-COPY --chown=sonarqube:sonarqube run.sh "$SONARQUBE_HOME/bin/"
+COPY --chown=sonarqube:sonarqube run.sh sonar.sh ${SONARQUBE_HOME}/bin/
 
-USER sonarqube
-WORKDIR $SONARQUBE_HOME
-ENTRYPOINT ["./bin/run.sh"]
+WORKDIR ${SONARQUBE_HOME}
+EXPOSE 9000
+ENTRYPOINT ["bin/run.sh"]
+CMD ["bin/sonar.sh"]
diff --git a/sonarqube_latest/run.sh b/sonarqube_latest/run.sh
index d7fc3a4..e3770a0 100755
--- a/sonarqube_latest/run.sh
+++ b/sonarqube_latest/run.sh
@@ -2,36 +2,44 @@
 
 set -euo pipefail
 
-if [[ "${1:-}" != -* ]]; then
-  exec "$@"
-fi
-
-declare -a sq_opts
-
+declare -a sq_opts=()
 set_prop_from_env_var() {
   if [ "$2" ]; then
     sq_opts+=("-D$1=$2")
   fi
 }
 
-# Parse Docker env vars to customize SonarQube
-#
-# e.g. Setting the env var sonar.jdbc.username=foo
-#
-# will cause SonarQube to be invoked with -Dsonar.jdbc.username=foo
-while IFS='=' read -r envvar_key envvar_value
-do
+# if first arg looks like a flag, assume we want to run sonarqube server
+if [ "${1:0:1}" = '-' ]; then
+    set -- bin/sonar.sh "$@"
+fi
+
+if [[ "$1" = 'bin/sonar.sh' ]]; then
+    chown -R "$(id -u):$(id -g)" "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+    chmod -R 700 "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}" 2>/dev/null || :
+
+    # Allow the container to be started with `--user`
+    if [[ "$(id -u)" = '0' ]]; then
+        chown -R sonarqube:sonarqube "${SQ_DATA_DIR}" "${SQ_EXTENSIONS_DIR}" "${SQ_LOGS_DIR}" "${SQ_TEMP_DIR}"
+        exec su-exec sonarqube "$0" "$@"
+    fi
+
+    # Legacy setting parsing to customize SonarQube. Please use environment variables instead.
+    while IFS='=' read -r envvar_key envvar_value
+    do
         if [[ "$envvar_key" =~ sonar.* ]] || [[ "$envvar_key" =~ ldap.* ]]; then
             sq_opts+=("-D${envvar_key}=${envvar_value}")
         fi
-done < <(env)
-# map legacy env variables
-set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
-set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
-set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
-set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
-
-exec java -jar "lib/sonar-application-$SONAR_VERSION.jar" \
-  -Dsonar.log.console=true \
-  "${sq_opts[@]}" \
-  "$@"
+    done < <(env)
+
+    # map legacy env variables
+    set_prop_from_env_var "sonar.jdbc.username" "${SONARQUBE_JDBC_USERNAME:-}"
+    set_prop_from_env_var "sonar.jdbc.password" "${SONARQUBE_JDBC_PASSWORD:-}"
+    set_prop_from_env_var "sonar.jdbc.url" "${SONARQUBE_JDBC_URL:-}"
+    set_prop_from_env_var "sonar.web.javaAdditionalOpts" "${SONARQUBE_WEB_JVM_OPTS:-}"
+    if [ ${#sq_opts[@]} -ne 0 ]; then
+        set -- "$@" "${sq_opts[@]}"
+    fi
+fi
+
+exec "$@"
diff --git a/sonarqube_latest/sonar.sh b/sonarqube_latest/sonar.sh
new file mode 100755
index 0000000..0be3fe9
--- /dev/null
+++ b/sonarqube_latest/sonar.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec java -jar lib/sonar-application-"${SONAR_VERSION}".jar -Dsonar.log.console=true "$@"

@yosifkit
Copy link
Member

Build test of #7703; 99a31e9; amd64 (sonarqube):

$ bashbrew build sonarqube:7.9.3-community
Using bashbrew/cache:1b948b87008e1c1ec8b1a5975103108e0162730b69152c78176ef140b7fcae83 (sonarqube:7.9.3-community)
Tagging sonarqube:7.9.3-community
Tagging sonarqube:7.9-community
Tagging sonarqube:lts

$ test/run.sh sonarqube:7.9.3-community
testing sonarqube:7.9.3-community
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed


$ bashbrew build sonarqube:8.3-community
Using bashbrew/cache:09bb950f6b901052509a149c8cd4dafd276139aee1db63699ad87d6b84ed77c6 (sonarqube:8.3-community)
Tagging sonarqube:8.3-community
Tagging sonarqube:8-community
Tagging sonarqube:community
Tagging sonarqube:latest

$ test/run.sh sonarqube:8.3-community
testing sonarqube:8.3-community
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed


$ bashbrew build sonarqube:8.3-developer
Using bashbrew/cache:1ca7d385fc1190b43be75ccf776d7110ac39c714456a44ffba9a7f22d1e31619 (sonarqube:8.3-developer)
Tagging sonarqube:8.3-developer
Tagging sonarqube:8-developer
Tagging sonarqube:developer

$ test/run.sh sonarqube:8.3-developer
testing sonarqube:8.3-developer
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed


$ bashbrew build sonarqube:8.3-enterprise
Using bashbrew/cache:6f43d5cfee679c4b54da114049c65aeebbbd86ac559b1f0368b51b6d24edb95c (sonarqube:8.3-enterprise)
Tagging sonarqube:8.3-enterprise
Tagging sonarqube:8-enterprise
Tagging sonarqube:enterprise

$ test/run.sh sonarqube:8.3-enterprise
testing sonarqube:8.3-enterprise
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants