forked from pyodide/pyodide
-
Notifications
You must be signed in to change notification settings - Fork 3
/
run_docker
executable file
·160 lines (140 loc) · 4.05 KB
/
run_docker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env bash
PYODIDE_IMAGE_REPO="pyodide"
PYODIDE_IMAGE_TAG="20240312-chrome122-firefox122"
DEFAULT_PYODIDE_DOCKER_IMAGE="${PYODIDE_IMAGE_REPO}/pyodide-env:${PYODIDE_IMAGE_TAG}"
DEFAULT_PYODIDE_SYSTEM_PORT="none"
DOCKER_COMMAND="/bin/bash"
DOCKER_INTERACTIVE="--interactive"
USER_HOME="/src/.docker_home"
USER_NAME="$(id -u -n)"
USER_ID="$(id -u)"
USER_GID="$(id -g)"
USER_COMMENT_FIELD="${USER_NAME} pyodide user alias"
USER_INTERPRETER="/sbin/nologin"
USER_FLAG=("--user" "$USER_ID:$USER_GID")
HEALTHCHECK_MESSAGE="Done initialization"
set -eo pipefail
# If docker does not exist, podman is used instead.
if ! command -v docker &> /dev/null; then
USER_FLAG=()
docker() {
podman "$@"
}
fi
function usage() {
cat > /dev/stdout <<EOF
Usage: run_docker [OPTIONS] [COMMAND] [ARG...]
Runs COMMAND in a new Pyodide docker container. If no COMMAND is provided, starts a bash
shell in the container.
Options:
-h, --help Show this information and exit.
-p, --port <port> System port to which to forward.
This is ignored if the env var PYODIDE_SYSTEM_PORT is set.
If set to 'none', docker instance will not bind to any port.
--non-interactive Run docker without the --interactive flag.
Useful for running in headless mode on CI server.
--root Run as root user inside the container
Prerequisites:
Docker has to be set up on your system.
EOF
}
function error() {
usage
exit 255
}
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-h|--help)
usage
exit 0
;;
-p|--port)
if [ "$#" -lt 2 ]; then
>&2 echo "port cannot be empty"
error
fi
if [[ -n ${PYODIDE_SYSTEM_PORT} ]]; then
echo "WARNING: will use the env var PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT} instead of the provided port"
else
PYODIDE_SYSTEM_PORT=$2
fi
shift 2
;;
--non-interactive)
DOCKER_INTERACTIVE="--interactive=false"
shift
;;
--root)
USER_FLAG=()
shift
;;
-*)
>&2 echo "Unknown option $1"
error
;;
*)
DOCKER_COMMAND="$*"
break
;;
esac
done
PYODIDE_DOCKER_PORT=${PYODIDE_DOCKER_PORT:-"8000"}
PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT:-${DEFAULT_PYODIDE_SYSTEM_PORT}}
PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE:-${DEFAULT_PYODIDE_DOCKER_IMAGE}}
# in case the port is not a number, do not bind the port
case $PYODIDE_SYSTEM_PORT in
none)
PORT_CONFIGURATION_LINE=()
;;
''|*[!0-9]*) # contains a non-digit character, therefore it is not a number
echo "WARNING: Invalid port argument '$PYODIDE_SYSTEM_PORT'. Port binding disabled."
PORT_CONFIGURATION_LINE=()
;;
*)
PORT_CONFIGURATION_LINE=("-p" "$PYODIDE_SYSTEM_PORT:$PYODIDE_DOCKER_PORT")
;;
esac
mkdir -p .docker_home
# Start a detached container as root, add the host uname and uid to /etc/passwd,
# then run forever
cat << EOF >.docker_home/entrypoint.sh
groupadd --gid '$USER_GID' '$USER_NAME';
useradd\
--home '$USER_HOME'\
--uid '$USER_ID'\
--gid '$USER_GID'\
--comment '$USER_COMMENT_FIELD'\
--shell '$USER_INTERPRETER'\
--groups sudo\
$USER_NAME\
;
echo 'export PATH=\$PATH:$USER_HOME/.local/bin' >> /etc/profile;
echo '%sudo ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers ;
echo '$HEALTHCHECK_MESSAGE';
tail -f /dev/null
EOF
CONTAINER=$(\
docker run \
"${PORT_CONFIGURATION_LINE[@]}" \
-d --rm \
-v "$PWD":/src \
--user root \
--shm-size 2g \
"${PYODIDE_DOCKER_IMAGE}" \
/bin/bash .docker_home/entrypoint.sh \
)
until docker logs "$CONTAINER" 2>&1 | grep -q "$HEALTHCHECK_MESSAGE"; do
echo "Waiting for initialization to finish..."
sleep 0.2
done
EXIT_STATUS=0
# Execute the provided command as the host user with HOME=/src
docker exec \
"$DOCKER_INTERACTIVE" --tty \
"${USER_FLAG[@]}" \
"$CONTAINER" \
/bin/bash -lc "${DOCKER_COMMAND}" || EXIT_STATUS=$?
docker kill "$CONTAINER" > /dev/null
exit $EXIT_STATUS