From 6324bf1a0f4ec6756a2e5b5f2a7f961454421f2e Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Wed, 25 Jul 2018 09:28:17 -0700 Subject: [PATCH 1/7] strawman implementation of launch script --- repo2docker/buildpacks/base.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index dee6249a..a11a7339 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -118,6 +118,14 @@ RUN ./{{ s }} {% endfor %} {% endif -%} +# Run launch script +{% if launch_scripts -%} +{% for s in launch_scripts -%} +RUN chmod +x {{ s }} +ENTRYPOINT ./{{ s }} +{% endfor %} +{% endif -%} + # Specify the default command to run CMD ["jupyter", "notebook", "--ip", "0.0.0.0"] @@ -283,6 +291,21 @@ class BuildPack: """ return [] + def get_launch_scripts(self): + """ + An ordered list of executable scripts to be executated at runtime. + These scripts are added as an `ENTRYPOINT` to the container. + + Is run as a non-root user, and must be executable. Used for doing + things that are currently not supported by other means and need to be + applied at runtime (set environment variables). + + The scripts should be as deterministic as possible - running it twice + should not produce different results.! + + """ + return [] + def binder_path(self, path): """Locate a file""" if os.path.exists('binder'): @@ -329,6 +352,7 @@ class BuildPack: build_script_files=self.get_build_script_files(), base_packages=sorted(self.get_base_packages()), post_build_scripts=self.get_post_build_scripts(), + launch_scripts=self.get_launch_scripts(), appendix=self.appendix, ) @@ -432,3 +456,9 @@ class BaseImage(BuildPack): if os.path.exists(post_build): return [post_build] return [] + + def get_launch_scripts(self): + launch = self.binder_path('launch') + if os.path.exists(launch): + return [launch] + return [] From f40e4ecdcbdd5bd055ee56d8c82f5b97fce1d3b4 Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Mon, 30 Jul 2018 16:03:32 -0700 Subject: [PATCH 2/7] update entrypoint logic --- repo2docker/buildpacks/base.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index a11a7339..7a422391 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -118,13 +118,17 @@ RUN ./{{ s }} {% endfor %} {% endif -%} -# Run launch script -{% if launch_scripts -%} -{% for s in launch_scripts -%} -RUN chmod +x {{ s }} -ENTRYPOINT ./{{ s }} -{% endfor %} +# Add launch script +{% if start_script -%} +RUN echo '#!/bin/bash \nexec {{ start_script }} $@ \n' > ./launch +RUN chmod +x {{ start_script }} +{% else %} +RUN echo '#!/bin/bash \nexec $@ \n' > ./launch {% endif -%} +RUN chmod +x ./launch + +# Run launch script +ENTRYPOINT ["./launch"] # Specify the default command to run CMD ["jupyter", "notebook", "--ip", "0.0.0.0"] @@ -291,7 +295,7 @@ class BuildPack: """ return [] - def get_launch_scripts(self): + def get_start_script(self): """ An ordered list of executable scripts to be executated at runtime. These scripts are added as an `ENTRYPOINT` to the container. @@ -352,7 +356,7 @@ class BuildPack: build_script_files=self.get_build_script_files(), base_packages=sorted(self.get_base_packages()), post_build_scripts=self.get_post_build_scripts(), - launch_scripts=self.get_launch_scripts(), + start_script=self.get_start_script(), appendix=self.appendix, ) @@ -457,8 +461,8 @@ class BaseImage(BuildPack): return [post_build] return [] - def get_launch_scripts(self): - launch = self.binder_path('launch') + def get_start_script(self): + launch = self.binder_path('start') if os.path.exists(launch): - return [launch] - return [] + return launch + return '' From b99ec0587f7be6561d03d68121a8ee69ebf3d1c5 Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Tue, 31 Jul 2018 11:07:59 -0700 Subject: [PATCH 3/7] add start script test --- tests/venv/start/postBuild/README.rst | 8 ++++++++ tests/venv/start/postBuild/postBuild | 2 ++ tests/venv/start/postBuild/requirements.txt | 1 + tests/venv/start/postBuild/start | 5 +++++ tests/venv/start/postBuild/verify | 9 +++++++++ 5 files changed, 25 insertions(+) create mode 100644 tests/venv/start/postBuild/README.rst create mode 100755 tests/venv/start/postBuild/postBuild create mode 100644 tests/venv/start/postBuild/requirements.txt create mode 100644 tests/venv/start/postBuild/start create mode 100755 tests/venv/start/postBuild/verify diff --git a/tests/venv/start/postBuild/README.rst b/tests/venv/start/postBuild/README.rst new file mode 100644 index 00000000..1a9851f3 --- /dev/null +++ b/tests/venv/start/postBuild/README.rst @@ -0,0 +1,8 @@ +System - Post-build scripts +--------------------------- + +It is possible to run scripts after you've built the environment specified in +your other files. This could be used to, for example, download data or run +some configuration scripts. + +In this example, we download and install a Jupyter Notebook extension. diff --git a/tests/venv/start/postBuild/postBuild b/tests/venv/start/postBuild/postBuild new file mode 100755 index 00000000..28b840f0 --- /dev/null +++ b/tests/venv/start/postBuild/postBuild @@ -0,0 +1,2 @@ +#!/bin/bash +jupyter nbextension enable --py --sys-prefix ipyleaflet diff --git a/tests/venv/start/postBuild/requirements.txt b/tests/venv/start/postBuild/requirements.txt new file mode 100644 index 00000000..5a2f5096 --- /dev/null +++ b/tests/venv/start/postBuild/requirements.txt @@ -0,0 +1 @@ +ipyleaflet diff --git a/tests/venv/start/postBuild/start b/tests/venv/start/postBuild/start new file mode 100644 index 00000000..c458c91a --- /dev/null +++ b/tests/venv/start/postBuild/start @@ -0,0 +1,5 @@ +#!/bin/bash + +export TEST_START_VAR="var is set" + +exec "$@" diff --git a/tests/venv/start/postBuild/verify b/tests/venv/start/postBuild/verify new file mode 100755 index 00000000..cc0d9ea7 --- /dev/null +++ b/tests/venv/start/postBuild/verify @@ -0,0 +1,9 @@ +#!/bin/bash +set -euo pipefail +jupyter nbextension list | grep 'jupyter-leaflet' | grep enabled + +if [ "$TEST_START_VAR" != "var is set" ] +then + echo "TEST_START_VAR is not set" + exit 1 +fi From ea16742b8fe0bd6e4656ff939b2c49b7d216dfbf Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Tue, 31 Jul 2018 12:48:55 -0700 Subject: [PATCH 4/7] add docs --- docs/source/config_files.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/source/config_files.rst b/docs/source/config_files.rst index ceb0ee0f..38f4c748 100644 --- a/docs/source/config_files.rst +++ b/docs/source/config_files.rst @@ -119,6 +119,20 @@ An example usecase of ``postBuild`` file is JupyterLab's demo on mybinder.org. It uses a ``postBuild`` file in a folder called ``binder`` to `prepare their demo for binder `_. +.. _start: + +``start`` +^^^^^^^^^^^^^ + +A script that can contain arbitrary commands to be run at runtime (as an +`ENTRYPOINT ` +to the docker container). If you want this to be a shell script, make sure the +first line is ```#!/bin/bash``. The last line must be ```exec "$@"``` +equivalent. + +.. TODO: Discuss runtime limits, best practices, etc. + Also, point to an example. + .. _runtime.txt: ``runtime.txt`` From 907732cdc0050ca0a83cc854980e5c518e6ab578 Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Thu, 2 Aug 2018 23:21:57 -0700 Subject: [PATCH 5/7] fix typos --- docs/source/config_files.rst | 2 +- docs/source/dev_newbuildpack.md | 2 +- repo2docker/buildpacks/base.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/config_files.rst b/docs/source/config_files.rst index 38f4c748..27ee3db1 100644 --- a/docs/source/config_files.rst +++ b/docs/source/config_files.rst @@ -122,7 +122,7 @@ their demo for binder ` diff --git a/docs/source/dev_newbuildpack.md b/docs/source/dev_newbuildpack.md index 05ac93bf..fd6dd7c6 100644 --- a/docs/source/dev_newbuildpack.md +++ b/docs/source/dev_newbuildpack.md @@ -23,4 +23,4 @@ Note that this doesn't apply to adding additional libraries / UI to existing buildpacks. For example, if we had an R buildpack and it supported IRKernel, it is much easier to just support RStudio / Shiny with it, since those are library additions than entirely -new buildpacks. \ No newline at end of file +new buildpacks. diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index 7a422391..5380a37d 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -305,7 +305,7 @@ class BuildPack: applied at runtime (set environment variables). The scripts should be as deterministic as possible - running it twice - should not produce different results.! + should not produce different results. """ return [] From 0595471f2df726a652f4d9c26b1c6a085eafc427 Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Mon, 13 Aug 2018 14:44:08 -0600 Subject: [PATCH 6/7] put launch script in home directory --- repo2docker/buildpacks/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index e0c61c88..9f0e2a93 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -133,15 +133,15 @@ RUN ./{{ s }} # Add launch script {% if start_script -%} -RUN echo '#!/bin/bash \nexec {{ start_script }} $@ \n' > ./launch +RUN echo '#!/bin/bash \nexec {{ start_script }} $@ \n' > ${HOME}/launch RUN chmod +x {{ start_script }} {% else %} -RUN echo '#!/bin/bash \nexec $@ \n' > ./launch +RUN echo '#!/bin/bash \nexec $@ \n' > ${HOME}/launch {% endif -%} -RUN chmod +x ./launch +RUN chmod +x ${HOME}/launch # Run launch script -ENTRYPOINT ["./launch"] +ENTRYPOINT ["${HOME}/launch"] # Specify the default command to run CMD ["jupyter", "notebook", "--ip", "0.0.0.0"] From 915fc8d8ff35874ade180fcf26162f1c02e9a668 Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Tue, 14 Aug 2018 17:08:48 -0600 Subject: [PATCH 7/7] update after talking to @yuvipanda --- repo2docker/buildpacks/base.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index 9f0e2a93..545f3d85 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -131,17 +131,11 @@ RUN ./{{ s }} {% endfor %} {% endif -%} -# Add launch script +# Add start script {% if start_script -%} -RUN echo '#!/bin/bash \nexec {{ start_script }} $@ \n' > ${HOME}/launch -RUN chmod +x {{ start_script }} -{% else %} -RUN echo '#!/bin/bash \nexec $@ \n' > ${HOME}/launch +RUN chmod +x "{{ start_script }}" +ENTRYPOINT ["{{ start_script }}"] {% endif -%} -RUN chmod +x ${HOME}/launch - -# Run launch script -ENTRYPOINT ["${HOME}/launch"] # Specify the default command to run CMD ["jupyter", "notebook", "--ip", "0.0.0.0"] @@ -358,7 +352,7 @@ class BuildPack: should not produce different results. """ - return [] + return '' def binder_path(self, path): """Locate a file""" @@ -549,7 +543,7 @@ class BaseImage(BuildPack): return [] def get_start_script(self): - launch = self.binder_path('start') - if os.path.exists(launch): - return launch + start = self.binder_path('start') + if os.path.exists(start): + return start return ''