diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 830fdfb..ee626dd 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -2,17 +2,15 @@ name: build-docker-images on: push: - branches: [ main ] - paths-ignore: - - "*.md" + branches: [ "main" ] + paths-ignore: [ "*.md" ] pull_request: - branches: [ main ] - paths-ignore: - - "*.md" + branches: [ "main" ] + paths-ignore: [ "*.md" ] + + workflow_dispatch: # Allows you to run this workflow manually from the Actions tab - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: env: BUILDKIT_PROGRESS: "plain" # Full logs for CI build. @@ -100,7 +98,8 @@ jobs: build_image data-science-dev latest docker_dev_box/dev.Dockerfile \ --build-arg "BASE_IMG=data-science-stack" \ --build-arg "ARG_PROFILE_JUPYTER=base,kernels,extensions" \ - --build-arg "ARG_PROFILE_VSCODE=base" + --build-arg "ARG_PROFILE_VSCODE=base" \ + --build-arg "ARG_PROFILE_R=rstudio,rshiny" push_image ## DevBox - full stack @@ -114,7 +113,8 @@ jobs: build_image full-stack-dev latest docker_dev_box/dev.Dockerfile \ --build-arg "BASE_IMG=full-stack" \ --build-arg "ARG_PROFILE_JUPYTER=base,kernels,extensions" \ - --build-arg "ARG_PROFILE_VSCODE=base" + --build-arg "ARG_PROFILE_VSCODE=base" \ + --build-arg "ARG_PROFILE_R=rstudio,rshiny" push_image ## DevBox - cuda diff --git a/docker_dev_box/dev.Dockerfile b/docker_dev_box/dev.Dockerfile index fa669f2..d69c933 100644 --- a/docker_dev_box/dev.Dockerfile +++ b/docker_dev_box/dev.Dockerfile @@ -12,26 +12,34 @@ ARG ARG_PROFILE_JUPYTER=base # base ARG ARG_PROFILE_VSCODE=base +# rstudio,rshiny +ARG ARG_PROFILE_R + ARG ARG_KEEP_NODEJS=true COPY work /opt/utils/ RUN set -eux && source /opt/utils/script-utils.sh \ - # Setup Jupyter: Basic Configurations and Extensions + # ----------------------------- Setup Jupyter: Basic Configurations and Extensions && mkdir -pv /opt/conda/etc/jupyter/ \ && mv /opt/utils/etc_jupyter/* /opt/conda/etc/jupyter/ && rm -rf /opt/utils/etc_jupyter \ && mv /opt/utils/start-*.sh /usr/local/bin/ && chmod +x /usr/local/bin/start-*.sh \ && source /opt/utils/script-devbox-jupyter.sh \ && for profile in $(echo $ARG_PROFILE_JUPYTER | tr "," "\n") ; do ( setup_jupyter_${profile} || true ) ; done \ - # If installing coder-server # https://github.com/cdr/code-server/releases + # ----------------------------- If installing coder-server # https://github.com/cdr/code-server/releases && source /opt/utils/script-devbox-vscode.sh \ && for profile in $(echo $ARG_PROFILE_VSCODE | tr "," "\n") ; do ( setup_vscode_${profile} || true ) ; done \ - # If not keeping NodeJS, remove NoedJS to reduce image size + # ----------------------------- If not keeping NodeJS, remove NoedJS to reduce image size && if [ ${ARG_KEEP_NODEJS} = "false" ] ; then \ echo "Removing Node/NPM..." && rm -rf /usr/bin/node /usr/bin/npm /usr/bin/npx /opt/node ; \ else \ echo "Keep NodeJS as ARG_KEEP_NODEJS defiend as: ${ARG_KEEP_NODEJS}" ; \ fi \ + # ----------------------------- If installing R IDEs: R_rstudio and R_rshiny + && source /opt/utils/script-devbox-rstudio.sh \ + && for profile in $(echo $ARG_PROFILE_R | tr "," "\n") ; do ( setup_R_${profile} ) ; done \ + # ----------------------------- Install supervisord + && source /opt/utils/script-supervisord.sh && setup_supervisord \ # Clean up and display components version information... && install__clean && list_installed_packages @@ -44,6 +52,6 @@ ENTRYPOINT ["tini", "-g", "--"] # '--login': make bash first reads and executes commands from the file /etc/profile, if that file exists. # After that, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. SHELL ["/bin/bash", "--login", "-o", "pipefail", "-c"] -CMD ["start-notebook.sh"] +CMD ["start-jupyterlab.sh"] WORKDIR $HOME_DIR EXPOSE 8888 diff --git a/docker_dev_box/work/script-devbox-rstudio.sh b/docker_dev_box/work/script-devbox-rstudio.sh new file mode 100644 index 0000000..52eebde --- /dev/null +++ b/docker_dev_box/work/script-devbox-rstudio.sh @@ -0,0 +1,54 @@ +source /opt/utils/script-utils.sh + + +setup_R_rstudio() { + # https://posit.co/download/rstudio-server/ + RSTUDIO_VERSION=$(curl -sL https://download2.rstudio.org/current.ver | cut -d'.' -f'1-3' | sed 's/+/-/g' ) \ + && RSTUDIO_URL="https://download2.rstudio.org/server/jammy/amd64/rstudio-server-${RSTUDIO_VERSION}-amd64.deb" \ + && curl -sL -o /tmp/rstudio.deb ${RSTUDIO_URL} \ + && dpkg -x /tmp/rstudio.deb /tmp && mv /tmp/usr/lib/rstudio-server/ /opt/ \ + && ln -sf /opt/rstudio-server /usr/lib/ \ + && ln -sf /opt/rstudio-server/bin/rs* /usr/bin/ + + # Allow RStudio server run as root user + # Configuration to make RStudio server disable authentication and do not run as daemon + mkdir -pv /etc/rstudio \ + && echo "server-daemonize=0" >> /etc/rstudio/rserver.conf \ + && echo "server-user=root" >> /etc/rstudio/rserver.conf \ + && echo "auth-none=1" >> /etc/rstudio/rserver.conf \ + && echo "auth-minimum-user-id=0" >> /etc/rstudio/rserver.conf \ + && echo "auth-validate-users=0" >> /etc/rstudio/rserver.conf \ + && echo "www-allow-origin=*" >> /etc/rstudio/rserver.conf \ + && echo "www-same-site=none" >> /etc/rstudio/rserver.conf \ + && echo "www-frame-origin=same" >> /etc/rstudio/rserver.conf \ + && echo "www-verify-user-agent=0">> /etc/rstudio/rserver.conf \ + && echo "database-config-file=/etc/rstudio/db.conf" >> /etc/rstudio/rserver.conf \ + && echo "provider=sqlite" >> /etc/rstudio/db.conf \ + && echo "directory=/etc/rstudio/" >> /etc/rstudio/db.conf ; + + type rstudio-server && echo "@ Version of rstudio-server: $(rstudio-server version)" || return -1 ; +} + + +setup_R_rshiny() { + # https://posit.co/download/shiny-server/ + RSHINY_VERSION=$(curl -sL https://s3.amazonaws.com/rstudio-shiny-server-os-build/ubuntu-18.04/x86_64/VERSION) \ + && RSHINY_URL="https://download3.rstudio.org/ubuntu-18.04/x86_64/shiny-server-${RSHINY_VERSION}-amd64.deb" \ + && curl -sL -o /tmp/rshiny.deb ${RSHINY_URL} \ + && dpkg -i /tmp/rshiny.deb \ + && sed -i "s/run_as shiny;/run_as root;/g" /etc/shiny-server/shiny-server.conf \ + && sed -i "s/3838/8888/g" /etc/shiny-server/shiny-server.conf \ + && printf "USER=root shiny-server" > /usr/local/bin/start-shiny-server.sh \ + && chmod u+x /usr/local/bin/start-shiny-server.sh + + # Remove shiny's pandoc and pandoc-proc to reduce size if they are already installed in the jpy-latex step. + ( which pandoc && rm -rf /opt/shiny-server/ext/pandoc/pandoc || true ) \ + && ( which pandoc-citeproc && rm -rf /opt/shiny-server/ext/pandoc/pandoc-citeproc || true ) \ + && rm -rf /opt/shiny-server/ext/node/bin/shiny-server \ + && ln -sf /opt/shiny-server/ext/node/bin/node /opt/shiny-server/ext/node/bin/shiny-server + + # hack shiny-server to allow run in root user: https://github.com/rstudio/shiny-server/pull/391 + sed -i "s/throw new Error/logger.warn/g" /opt/shiny-server/lib/worker/app-worker.js + + type shiny-server && echo "@ Version of shiny-server: $(shiny-server --version)" || return -1 ; +} diff --git a/docker_dev_box/work/script-devbox-vscode.sh b/docker_dev_box/work/script-devbox-vscode.sh index aa90e7e..3e94f81 100644 --- a/docker_dev_box/work/script-devbox-vscode.sh +++ b/docker_dev_box/work/script-devbox-vscode.sh @@ -3,14 +3,14 @@ source /opt/utils/script-utils.sh setup_vscode_base() { ## ref: https://github.com/coder/code-server - VERSION_CODER=$(curl -sL https://github.com/cdr/code-server/releases.atom | grep "releases/tag" | head -1 | grep -Po '(\d[\d|.]+)') \ - && install_tar_gz "https://github.com/cdr/code-server/releases/download/v${VERSION_CODER}/code-server-${VERSION_CODER}-linux-amd64.tar.gz" \ + VER_CODER=$(curl -sL https://github.com/cdr/code-server/releases.atom | grep "releases/tag" | grep -v 'rc.' | head -1 | grep -Po '(\d[\d|.]+)') \ + && URL_CODER="https://github.com/cdr/code-server/releases/download/v${VER_CODER}/code-server-${VER_CODER}-linux-amd64.tar.gz" \ + && echo "Downloading cdr/code-server version ${VER_CODER} from: ${URL_CODER}" \ + && install_tar_gz $URL_CODER \ && mv /opt/code-server* /opt/code-server \ - && ln -s /opt/code-server/bin/code-server /usr/bin/ \ - && printf "#! /usr/bin/env bash\n/opt/code-server/bin/code-server --port=8888 --auth=none --disable-telemetry ${HOME}\n" > /usr/local/bin/start-code-server.sh \ - && chmod u+x /usr/local/bin/start-code-server.sh + && ln -s /opt/code-server/bin/code-server /usr/bin/ ; - type code-server && echo "@ Version of coder-server: $(code-server -v)" || return -1; + type code-server && echo "@ Version of coder-server: $(code-server -v)" || return -1 ; } @@ -24,9 +24,7 @@ setup_vscode_base2() { && mv /opt/openvscode-server* /opt/code-server \ && ( which node && ( echo "Replacing with system node" && ln -sf $(which node) /opt/code-server/ ) || echo "No system node found" ) \ && ln -sf /opt/code-server/bin/openvscode-server /opt/code-server/bin/code-server \ - && ln -sf /opt/code-server/bin/openvscode-server /usr/bin/code-server \ - && printf "#! /usr/bin/env bash\n/opt/code-server/bin/code-server --host=0.0.0.0 --port=8888 --telemetry-level=off \"${HOME:-~}\"\n" > /usr/local/bin/start-code-server.sh \ - && chmod u+x /usr/local/bin/start-code-server.sh + && ln -sf /opt/code-server/bin/openvscode-server /usr/bin/code-server ; - type code-server && echo "@ Version of openvscoder-server: $(code-server -v)" || return -1; + type code-server && echo "@ Version of openvscoder-server: $(code-server -v)" || return -1 ; } diff --git a/docker_dev_box/work/script-supervisord.sh b/docker_dev_box/work/script-supervisord.sh new file mode 100644 index 0000000..d7d87a0 --- /dev/null +++ b/docker_dev_box/work/script-supervisord.sh @@ -0,0 +1,12 @@ +source /opt/utils/script-utils.sh + + +setup_supervisord() { + OS="linux" && ARCH="amd64" \ + && VER_SUPERVISORD=$(curl -sL https://github.com/QPod/supervisord/releases.atom | grep "releases/tag" | head -1 | grep -Po '(\d[\d|.]+)') \ + && URL_SUPERVISORD="https://github.com/QPod/supervisord/releases/download/v${VER_SUPERVISORD}/supervisord_${VER_SUPERVISORD}_${OS}_${ARCH}.tar.gz" \ + && echo "Downloading Supervisord ${VER_SUPERVISORD} from ${URL_SUPERVISORD}" \ + && curl -o /tmp/TMP.tgz -sL $URL_SUPERVISORD && tar -C /tmp/ -xzf /tmp/TMP.tgz && rm /tmp/TMP.tgz \ + && mkdir -pv /opt/bin/ && mv /tmp/supervisord /opt/bin/ && ln -sf /opt/bin/supervisord /usr/local/bin/ \ + && supervisord version +} diff --git a/docker_dev_box/work/start-code-server.sh b/docker_dev_box/work/start-code-server.sh new file mode 100644 index 0000000..971bdb8 --- /dev/null +++ b/docker_dev_box/work/start-code-server.sh @@ -0,0 +1,13 @@ +#! /usr/bin/env bash +[ $BASH ] && [ -f /etc/profile ] && [ -z $ENTER_PROFILE ] && . /etc/profile + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + + + +if [[ "$CODER_ARGS $@" != *"--bind-addr="* ]]; then + CODER_ARGS="--bind-addr=0.0.0.0:9999 $CODER_ARGS" +fi + + +exec /opt/code-server/bin/code-server --auth=none --disable-telemetry --disable-update-check ${CODER_ARGS} $@ /root diff --git a/docker_dev_box/work/start-notebook.sh b/docker_dev_box/work/start-jupyterlab.sh similarity index 100% rename from docker_dev_box/work/start-notebook.sh rename to docker_dev_box/work/start-jupyterlab.sh diff --git a/docker_dev_box/work/start-rserver.sh b/docker_dev_box/work/start-rserver.sh new file mode 100644 index 0000000..9283c0a --- /dev/null +++ b/docker_dev_box/work/start-rserver.sh @@ -0,0 +1,13 @@ +#! /usr/bin/env bash +[ $BASH ] && [ -f /etc/profile ] && [ -z $ENTER_PROFILE ] && . /etc/profile + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + + + +if [[ "$RSTUDIO_ARGS $@" != *"--www-port="* ]]; then + RSTUDIO_ARGS="--www-port=8787 $RSTUDIO_ARGS" +fi + + +USER=root /opt/rstudio-server/bin/rserver ${RSTUDIO_ARGS} $@ diff --git a/docker_dev_box/work/start-singleuser.sh b/docker_dev_box/work/start-singleuser.sh index 8c9a609..6ce41e1 100644 --- a/docker_dev_box/work/start-singleuser.sh +++ b/docker_dev_box/work/start-singleuser.sh @@ -4,6 +4,8 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" . $DIR/start--pre.sh +# ref: https://github.com/jupyter/docker-stacks/blob/main/images/base-notebook/start-singleuser.py + if [[ "$NOTEBOOK_ARGS $@" != *"--ip="* ]]; then NOTEBOOK_ARGS="--ip=0.0.0.0 $NOTEBOOK_ARGS" fi diff --git a/docker_openresty/Dockerfile b/docker_openresty/Dockerfile index b4f4571..68208c2 100644 --- a/docker_openresty/Dockerfile +++ b/docker_openresty/Dockerfile @@ -18,7 +18,7 @@ RUN set -eux \ && chown -R nginx:www-data /var/cache/nginx /var/log/nginx \ && source /opt/utils/script-setup.sh && setup_lua_base && setup_lua_rocks \ && source /opt/utils/script-setup-openresty.sh && setup_openresty \ - && source /opt/utils/script-setup-acme.sh && setup_acme \ + && source /opt/utils/script-setup-acme.sh && setup_acme && setup_lego \ && pip install certbot \ && mv /opt/utils/entrypoint/* / && rm -rf /opt/utils/entrypoint \ && cp -rf /opt/utils/nginx/* /etc/nginx/ && rm -rf /opt/utils/nginx \ diff --git a/docker_openresty/work/script-setup-acme.sh b/docker_openresty/work/script-setup-acme.sh index a8a6c0d..eea603b 100755 --- a/docker_openresty/work/script-setup-acme.sh +++ b/docker_openresty/work/script-setup-acme.sh @@ -16,3 +16,15 @@ setup_acme() { type acme.sh && echo "@ Version info of acme.sh: $(acme.sh -v)" || return -1 ; } + + +setup_lego() { + # Install the latest release of lego (go-acme): https://go-acme.github.io/lego/usage/cli/obtain-a-certificate/index.html + VER_LEGO=$(curl -sL https://github.com/go-acme/lego/releases.atom | grep 'releases/tag' | head -1 | grep -Po '\d[\d.]+' ) \ + && URL_LEGO="https://github.com/go-acme/lego/releases/download/v${VER_LEGO}/lego_v${VER_LEGO}_linux_amd64.tar.gz" \ + && echo "Downloading lego version ${VER_LEGO} from: ${URL_LEGO}" \ + && install_tar_gz $URL_LEGO lego \ + && mv /opt/lego /opt/bin/ && ln -sf /opt/bin/lego /usr/bin/ ; + + type lego && echo "@ Version info of lego: $(lego -v)" || return -1 ; +}