Skip to content

Commit f458cbe

Browse files
committed
Make start.sh the entrypoint
Closes jupyter#1528
1 parent a4ede5d commit f458cbe

File tree

18 files changed

+42
-43
lines changed

18 files changed

+42
-43
lines changed

docs/using/common.md

+3-8
Original file line numberDiff line numberDiff line change
@@ -225,21 +225,16 @@ docker run -it --rm \
225225

226226
### `start.sh`
227227

228-
The `start-notebook.py` script inherits most of its option handling capability from a more generic `start.sh` script.
229-
The `start.sh` script supports all the features described above but allows you to specify an arbitrary command to execute.
228+
Most of the configuration options in the `start-notebook.py` script are handled by an internal `start.sh` script tha automatically runs before the command provided to the container (it's set as the container entrypoint).
229+
This allows you to specify an arbitrary command that takes advantage of all these features.
230230
For example, to run the text-based `ipython` console in a container, do the following:
231231

232232
```bash
233-
docker run -it --rm quay.io/jupyter/base-notebook start.sh ipython
233+
docker run -it --rm quay.io/jupyter/base-notebook ipython
234234
```
235235

236236
This script is handy when you derive a new Dockerfile from this image and install additional Jupyter applications with subcommands like `jupyter console`, `jupyter kernelgateway`, etc.
237237

238-
### Others
239-
240-
You can bypass the provided scripts and specify an arbitrary start command.
241-
If you do, keep in mind that features, supported by the `start.sh` script and its kin, will not function (e.g., `GRANT_SUDO`).
242-
243238
## Conda Environments
244239

245240
The default Python 3.x [Conda environment](https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) resides in `/opt/conda`.

docs/using/selecting.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ It contains:
3434
- [mamba](https://github.com/mamba-org/mamba): "reimplementation of the conda package manager in C++". We use this package manager by default when installing packages.
3535
- Unprivileged user `jovyan` (`uid=1000`, configurable, [see options in the common features section](./common.md) of this documentation) in group `users` (`gid=100`)
3636
with ownership over the `/home/jovyan` and `/opt/conda` paths
37-
- `tini` as the container entry point
38-
- A `start.sh` script as the default command - useful for running alternative commands in the container as applications are added (e.g. `ipython`, `jupyter kernelgateway`, `jupyter lab`)
37+
- `tini` and a `start.sh` script as the container entry point - useful for running alternative commands in the container as applications are added (e.g. `ipython`, `jupyter kernelgateway`, `jupyter lab`)
3938
- A `run-hooks.sh` script, which can source/run files in a given directory
4039
- Options for a passwordless sudo
4140
- Common system libraries like `bzip2`, `ca-certificates`, `locales`

images/base-notebook/start-notebook.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
os.execvp(command[0], command)
1515

1616

17-
# Wrap everything in start.sh, no matter what
18-
command = ["/usr/local/bin/start.sh"]
17+
# Entrypoint is start.sh
18+
command = []
1919

2020
# If we want to survive restarts, tell that to start.sh
2121
if os.environ.get("RESTARTABLE") == "yes":

images/base-notebook/start-singleuser.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import shlex
66
import sys
77

8-
command = ["/usr/local/bin/start.sh", "jupyterhub-singleuser"]
8+
# Entrypoint is start.sh
9+
command = ["jupyterhub-singleuser"]
910

1011
# set default ip to 0.0.0.0
1112
if "--ip=" not in os.environ.get("NOTEBOOK_ARGS", ""):

images/docker-stacks-foundation/Dockerfile

+1-2
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ RUN set -x && \
124124
fix-permissions "/home/${NB_USER}"
125125

126126
# Configure container startup
127-
ENTRYPOINT ["tini", "-g", "--"]
128-
CMD ["start.sh"]
127+
ENTRYPOINT ["tini", "-g", "--", "start.sh"]
129128

130129
# Copy local files as late as possible to avoid cache busting
131130
COPY run-hooks.sh start.sh /usr/local/bin/

images/docker-stacks-foundation/start.sh

+11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ else
3434
cmd=( "$@" )
3535
fi
3636

37+
# Backwards compatibility: start.sh is executed by default in ENTRYPOINT so
38+
# should no longer be specified in CMD
39+
if [ "${_START_SH_EXECUTED}" = "1" ]; then
40+
_log "WARNING: start.sh is the default ENTRYPOINT, do not include it in CMD"
41+
_log "Executing the command:" "${cmd[@]}"
42+
exec "${cmd[@]}"
43+
else
44+
export _START_SH_EXECUTED=1
45+
fi
46+
47+
3748
# NOTE: This hook will run as the user the container was started with!
3849
# shellcheck disable=SC1091
3950
source /usr/local/bin/run-hooks.sh /usr/local/bin/start-notebook.d

tests/all-spark-notebook/test_spark_notebooks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_nbconvert(container: TrackedContainer, test_file: str) -> None:
3333
timeout=60,
3434
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
3535
tty=True,
36-
command=["start.sh", "bash", "-c", command],
36+
command=["bash", "-c", command],
3737
)
3838

3939
expected_file = f"{output_dir}/{test_file}.md"

tests/base-notebook/test_container_options.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
3535
tty=True,
3636
user="root",
3737
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
38-
command=["start.sh", "bash", "-c", "sleep infinity"],
38+
command=["bash", "-c", "sleep infinity"],
3939
)
4040

4141
# Give the chown time to complete.

tests/base-notebook/test_pandoc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ def test_pandoc(container: TrackedContainer) -> None:
1212
logs = container.run_and_wait(
1313
timeout=10,
1414
tty=True,
15-
command=["start.sh", "bash", "-c", 'echo "**BOLD**" | pandoc'],
15+
command=["bash", "-c", 'echo "**BOLD**" | pandoc'],
1616
)
1717
assert "<p><strong>BOLD</strong></p>" in logs

tests/base-notebook/test_start_container.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,7 @@ def test_tini_entrypoint(
7676
https://superuser.com/questions/632979/if-i-know-the-pid-number-of-a-process-how-can-i-get-its-name
7777
"""
7878
LOGGER.info(f"Test that {command} is launched as PID {pid} ...")
79-
running_container = container.run_detached(
80-
tty=True,
81-
command=["start.sh"],
82-
)
79+
running_container = container.run_detached(tty=True)
8380
# Select the PID 1 and get the corresponding command
8481
cmd = running_container.exec_run(f"ps -p {pid} -o comm=")
8582
output = cmd.output.decode("utf-8").strip("\n")

tests/docker-stacks-foundation/test_units.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ def test_units(container: TrackedContainer) -> None:
3434
timeout=30,
3535
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
3636
tty=True,
37-
command=["start.sh", "python", f"{cont_data_dir}/{test_file_name}"],
37+
command=["python", f"{cont_data_dir}/{test_file_name}"],
3838
)

tests/docker-stacks-foundation/test_user_options.py

+12-14
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def test_uid_change(container: TrackedContainer) -> None:
1818
tty=True,
1919
user="root",
2020
environment=["NB_UID=1010"],
21-
command=["start.sh", "bash", "-c", "id && touch /opt/conda/test-file"],
21+
command=["bash", "-c", "id && touch /opt/conda/test-file"],
2222
)
2323
assert "uid=1010(jovyan)" in logs
2424

@@ -30,7 +30,7 @@ def test_gid_change(container: TrackedContainer) -> None:
3030
tty=True,
3131
user="root",
3232
environment=["NB_GID=110"],
33-
command=["start.sh", "id"],
33+
command=["id"],
3434
)
3535
assert "gid=110(jovyan)" in logs
3636
assert "groups=110(jovyan),100(users)" in logs
@@ -43,7 +43,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
4343
tty=True,
4444
user="root",
4545
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
46-
command=["start.sh", "bash", "-c", "sleep infinity"],
46+
command=["bash", "-c", "sleep infinity"],
4747
)
4848

4949
# Give the chown time to complete.
@@ -99,7 +99,6 @@ def test_chown_extra(container: TrackedContainer) -> None:
9999
"CHOWN_EXTRA_OPTS=-R",
100100
],
101101
command=[
102-
"start.sh",
103102
"bash",
104103
"-c",
105104
"stat -c '%n:%u:%g' /home/jovyan/.bashrc /opt/conda/bin/jupyter",
@@ -123,7 +122,7 @@ def test_chown_home(container: TrackedContainer) -> None:
123122
"NB_UID=1010",
124123
"NB_GID=101",
125124
],
126-
command=["start.sh", "bash", "-c", "stat -c '%n:%u:%g' /home/kitten/.bashrc"],
125+
command=["bash", "-c", "stat -c '%n:%u:%g' /home/kitten/.bashrc"],
127126
)
128127
assert "/home/kitten/.bashrc:1010:101" in logs
129128

@@ -135,7 +134,7 @@ def test_sudo(container: TrackedContainer) -> None:
135134
tty=True,
136135
user="root",
137136
environment=["GRANT_SUDO=yes"],
138-
command=["start.sh", "sudo", "id"],
137+
command=["sudo", "id"],
139138
)
140139
assert "uid=0(root)" in logs
141140

@@ -147,7 +146,7 @@ def test_sudo_path(container: TrackedContainer) -> None:
147146
tty=True,
148147
user="root",
149148
environment=["GRANT_SUDO=yes"],
150-
command=["start.sh", "sudo", "which", "jupyter"],
149+
command=["sudo", "which", "jupyter"],
151150
)
152151
assert logs.rstrip().endswith("/opt/conda/bin/jupyter")
153152

@@ -158,7 +157,7 @@ def test_sudo_path_without_grant(container: TrackedContainer) -> None:
158157
timeout=10,
159158
tty=True,
160159
user="root",
161-
command=["start.sh", "which", "jupyter"],
160+
command=["which", "jupyter"],
162161
)
163162
assert logs.rstrip().endswith("/opt/conda/bin/jupyter")
164163

@@ -173,7 +172,7 @@ def test_group_add(container: TrackedContainer) -> None:
173172
no_warnings=False,
174173
user="1010:1010",
175174
group_add=["users"], # Ensures write access to /home/jovyan
176-
command=["start.sh", "id"],
175+
command=["id"],
177176
)
178177
warnings = TrackedContainer.get_warnings(logs)
179178
assert len(warnings) == 1
@@ -191,7 +190,7 @@ def test_set_uid(container: TrackedContainer) -> None:
191190
timeout=5,
192191
no_warnings=False,
193192
user="1010",
194-
command=["start.sh", "id"],
193+
command=["id"],
195194
)
196195
assert "uid=1010(jovyan) gid=0(root)" in logs
197196
warnings = TrackedContainer.get_warnings(logs)
@@ -207,7 +206,7 @@ def test_set_uid_and_nb_user(container: TrackedContainer) -> None:
207206
user="1010",
208207
environment=["NB_USER=kitten"],
209208
group_add=["users"], # Ensures write access to /home/jovyan
210-
command=["start.sh", "id"],
209+
command=["id"],
211210
)
212211
assert "uid=1010(kitten) gid=0(root)" in logs
213212
warnings = TrackedContainer.get_warnings(logs)
@@ -236,7 +235,7 @@ def test_container_not_delete_bind_mount(
236235
"CHOWN_HOME=yes",
237236
],
238237
volumes={d: {"bind": "/home/jovyan/data", "mode": "rw"}},
239-
command=["start.sh", "ls"],
238+
command=["ls"],
240239
)
241240
assert p.read_text() == "some-content"
242241
assert len(list(tmp_path.iterdir())) == 1
@@ -259,7 +258,6 @@ def test_jupyter_env_vars_to_unset(
259258
"SECRET_FRUIT=mango",
260259
],
261260
command=[
262-
"start.sh",
263261
"bash",
264262
"-c",
265263
"echo I like $FRUIT and ${SECRET_FRUIT:-stuff}, and love ${SECRET_ANIMAL:-to keep secrets}!",
@@ -284,7 +282,7 @@ def test_secure_path(container: TrackedContainer, tmp_path: pathlib.Path) -> Non
284282
tty=True,
285283
user="root",
286284
volumes={p: {"bind": "/usr/bin/python", "mode": "ro"}},
287-
command=["start.sh", "python", "--version"],
285+
command=["python", "--version"],
288286
)
289287
assert "Wrong python" not in logs
290288
assert "Python" in logs

tests/minimal-notebook/test_nbconvert.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_nbconvert(
2828
timeout=30,
2929
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
3030
tty=True,
31-
command=["start.sh", "bash", "-c", command],
31+
command=["bash", "-c", command],
3232
)
3333
expected_file = f"{output_dir}/{test_file}.{output_format}"
3434
assert expected_file in logs, f"Expected file {expected_file} not generated"

tests/package_helper.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def start_container(container: TrackedContainer) -> Container:
5555
LOGGER.info(f"Starting container {container.image_name} ...")
5656
return container.run_detached(
5757
tty=True,
58-
command=["start.sh", "bash", "-c", "sleep infinity"],
58+
command=["bash", "-c", "sleep infinity"],
5959
)
6060

6161
@staticmethod

tests/run_command.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ def run_command(
1818
return container.run_and_wait(
1919
timeout=timeout,
2020
tty=True,
21-
command=["start.sh", "bash", "-c", command],
21+
command=["bash", "-c", command],
2222
)

tests/scipy-notebook/test_cython.py

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ def test_cython(container: TrackedContainer) -> None:
1616
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
1717
tty=True,
1818
command=[
19-
"start.sh",
2019
"bash",
2120
"-c",
2221
# We copy our data to a temporary folder to be able to modify the directory

tests/scipy-notebook/test_extensions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ def test_check_extension(container: TrackedContainer, extension: str) -> None:
3030
container.run_and_wait(
3131
timeout=10,
3232
tty=True,
33-
command=["start.sh", "jupyter", "labextension", "check", extension],
33+
command=["jupyter", "labextension", "check", extension],
3434
)

tests/scipy-notebook/test_matplotlib.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_matplotlib(
4242
running_container = container.run_detached(
4343
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
4444
tty=True,
45-
command=["start.sh", "bash", "-c", command],
45+
command=["bash", "-c", command],
4646
)
4747
command = f"python {cont_data_dir}/{test_file}"
4848
cmd = running_container.exec_run(command)

0 commit comments

Comments
 (0)