Allow passing in uid and username of user built into image
This allows volumes to properly respect the uid of the user
from the host. Much easier than using user namespaces
MODIFY
repo2docker/app.py
repo2docker/app.py
@@ -19,7 +19,7 @@ import escapism
from traitlets.config import Application
-from traitlets import Unicode, List, default, Tuple, Dict
+from traitlets import Unicode, List, default, Tuple, Dict, Int
import docker
from docker.utils import kwargs_from_env
@@ -117,6 +117,29 @@ class Repo2Docker(Application):
config=True
)
+ user_id = Int(
+ 1000,
+ help="""
+ UID of the user to create inside the built image.
+
+ Should be a uid that is not currently used by anything in the image.
+
+ Might not affect Dockerfile builds.
+ """,
+ config=True
+ )
+
+ user_name = Unicode(
+ 'jovyan',
+ help="""
+ Username of the user to create inside the built image.
+
+ Should be a uid that is not currently used by anything in the image,
+ and should conform to the restrictions on user names for Linux.
+ """,
+ config=True
+ )
+
def fetch(self, url, ref, checkout_path):
try:
for line in execute_cmd(['git', 'clone', url, checkout_path],
@@ -224,6 +247,19 @@ class Repo2Docker(Application):
default=[]
)
+ argparser.add_argument(
+ '--user-id',
+ help='User id the primary user in the image',
+ default=1000,
+ type=int
+ )
+
+ argparser.add_argument(
+ '--user-name',
+ help='User name of primary user in the image',
+ default='jovyan'
+ )
+
return argparser
def json_excepthook(self, etype, evalue, traceback):
@@ -307,6 +343,9 @@ class Repo2Docker(Application):
self.run_cmd = args.cmd
+ self.user_id = int(args.user_id)
+ self.user_name = args.user_name
+
if args.build_memory_limit:
self.build_memory_limit = args.build_memory_limit
@@ -424,9 +463,13 @@ class Repo2Docker(Application):
extra=dict(phase='building'))
if self.build:
+ build_args = {
+ 'NB_USER': self.user_name,
+ 'NB_UID': str(self.user_id)
+ }
self.log.info('Using %s builder\n', bp.name,
extra=dict(phase='building'))
- for l in picked_buildpack.build(self.output_image_spec, self.build_memory_limit):
+ for l in picked_buildpack.build(self.output_image_spec, self.build_memory_limit, build_args):
if 'stream' in l:
self.log.info(l['stream'],
extra=dict(phase='building'))

MODIFY
repo2docker/buildpacks/base.py
repo2docker/buildpacks/base.py
@@ -30,8 +30,8 @@ ENV LANGUAGE en_US.UTF-8
ENV SHELL /bin/bash
# Set up user
-ENV NB_USER jovyan
-ENV NB_UID 1000
+ARG NB_USER
+ARG NB_UID
ENV HOME /home/${NB_USER}
RUN adduser --disabled-password \
@@ -360,7 +360,7 @@ class BuildPack(LoggingConfigurable):
post_build_scripts=self.post_build_scripts,
)
- def build(self, image_spec, memory_limit):
+ def build(self, image_spec, memory_limit, build_args):
tarf = io.BytesIO()
tar = tarfile.open(fileobj=tarf, mode='w')
dockerfile_tarinfo = tarfile.TarInfo("Dockerfile")
@@ -406,7 +406,7 @@ class BuildPack(LoggingConfigurable):
fileobj=tarf,
tag=image_spec,
custom_context=True,
- buildargs={},
+ buildargs=build_args,
decode=True,
forcerm=True,
rm=True,

MODIFY
repo2docker/buildpacks/docker.py
repo2docker/buildpacks/docker.py
@@ -18,7 +18,7 @@ class DockerBuildPack(BuildPack):
with open(Dockerfile) as f:
return f.read()
- def build(self, image_spec, memory_limit):
+ def build(self, image_spec, memory_limit, build_args):
limits = {
# Always disable memory swap for building, since mostly
# nothing good can come of that.
@@ -31,7 +31,7 @@ class DockerBuildPack(BuildPack):
path=os.getcwd(),
dockerfile=self.binder_path(self.dockerfile),
tag=image_spec,
- buildargs={},
+ buildargs=build_args,
decode=True,
forcerm=True,
rm=True,

MODIFY
tests/volumes.py
tests/volumes.py
@@ -12,9 +12,12 @@ def test_volume_abspath():
"""
ts = str(time.time())
with tempfile.TemporaryDirectory() as tmpdir:
+ username = os.getlogin()
subprocess.check_call([
'repo2docker',
- '-v', '{}:/home/jovyan'.format(tmpdir),
+ '-v', '{}:/home/{}'.format(tmpdir, username),
+ '--user-id', str(os.geteuid()),
+ '--user-name', username,
tmpdir,
'--',
'/bin/bash',
@@ -37,6 +40,8 @@ def test_volume_relpath():
subprocess.check_call([
'repo2docker',
'-v', '.:.',
+ '--user-id', str(os.geteuid()),
+ '--user-name', os.getlogin(),
tmpdir,
'--',
'/bin/bash',

Allow passing in uid and username of user built into image

This allows volumes to properly respect the uid of the user
from the host. Much easier than using user namespaces