diff mbox

[RFC] tests/docker: add basic user mapping support

Message ID 20161213132205.9114-1-alex.bennee@linaro.org
State Superseded
Headers show

Commit Message

Alex Bennée Dec. 13, 2016, 1:22 p.m. UTC
Currently all docker builds are done by exporting a tarball to the
docker container and running the build as the containers root user.
Other use cases are possible however and it is possible to map a part
of users file-system to the container. This is useful for example for
doing cross-builds of arbitrary source trees. For this to work
smoothly the container needs to have a user created that maps cleanly
to the host system.

This adds a -u option to the docker script so that:

  DEB_ARCH=armhf DEB_TYPE=stable ./tests/docker/docker.py build \
    -u --include-executable=arm-linux-user/qemu-arm \
    debian:armhf ./tests/docker/dockerfiles/debian-bootstrap.docker

Will build a container that can then be run like:

  docker run --rm -it -v /home/alex/lsrc/qemu/risu.git/:/src \
    --user=alex:alex -w /src/ debian:armhf \
    sh -c "make clean && ./configure -s && make"

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
 tests/docker/docker.py                           | 19 +++++++++++++++++++
 tests/docker/dockerfiles/debian-bootstrap.docker |  3 +++
 2 files changed, 22 insertions(+)

-- 
2.11.0

Comments

Fam Zheng Jan. 17, 2017, 9:49 a.m. UTC | #1
On Tue, 12/13 13:22, Alex Bennée wrote:
> Currently all docker builds are done by exporting a tarball to the

> docker container and running the build as the containers root user.

> Other use cases are possible however and it is possible to map a part

> of users file-system to the container. This is useful for example for

> doing cross-builds of arbitrary source trees. For this to work

> smoothly the container needs to have a user created that maps cleanly

> to the host system.

> 

> This adds a -u option to the docker script so that:

> 

>   DEB_ARCH=armhf DEB_TYPE=stable ./tests/docker/docker.py build \

>     -u --include-executable=arm-linux-user/qemu-arm \

>     debian:armhf ./tests/docker/dockerfiles/debian-bootstrap.docker

> 

> Will build a container that can then be run like:

> 

>   docker run --rm -it -v /home/alex/lsrc/qemu/risu.git/:/src \

>     --user=alex:alex -w /src/ debian:armhf \

>     sh -c "make clean && ./configure -s && make"


Sorry for the late reply!

> 

> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

> ---

>  tests/docker/docker.py                           | 19 +++++++++++++++++++

>  tests/docker/dockerfiles/debian-bootstrap.docker |  3 +++

>  2 files changed, 22 insertions(+)

> 

> diff --git a/tests/docker/docker.py b/tests/docker/docker.py

> index 37d83199e7..59baac6bae 100755

> --- a/tests/docker/docker.py

> +++ b/tests/docker/docker.py

> @@ -12,6 +12,7 @@

>  # the top-level directory.

>  

>  import os

> +import stat

>  import sys

>  import subprocess

>  import json

> @@ -25,6 +26,7 @@ import signal

>  from tarfile import TarFile, TarInfo

>  from StringIO import StringIO

>  from shutil import copy, rmtree

> +from pwd import getpwuid

>  

>  

>  DEVNULL = open(os.devnull, 'wb')

> @@ -225,6 +227,8 @@ class BuildCommand(SubCommand):

>                              help="""Specify a binary that will be copied to the

>                              container together with all its dependent

>                              libraries""")

> +        parser.add_argument("--user", "-u", action="store_true",

> +                            help="Add the current user to images passwd")


Maybe use --add-current-user for the full argument name?

>          parser.add_argument("tag",

>                              help="Image Tag")

>          parser.add_argument("dockerfile",

> @@ -260,6 +264,21 @@ class BuildCommand(SubCommand):

>                  _copy_binary_with_libs(args.include_executable,

>                                         docker_dir)

>  

> +            if args.user:

> +                uid = os.getuid()

> +                uname = getpwuid(uid).pw_name

> +                scriptlet = docker_dir+"/setup_user.sh"

> +

> +                # write scriptlet

> +                setup = open(scriptlet, "w")

> +                setup.write("#!/bin/sh\n")

> +                setup.write("useradd -u %d -U %s" % (uid, uname))

> +                setup.close()

> +

> +                st = os.stat(scriptlet)

> +                os.chmod(scriptlet,

> +                         st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)


Is it cleaner we inject commands into the docker file directly?

> +

>              dkr.build_image(tag, docker_dir, dockerfile,

>                              quiet=args.quiet, argv=argv)

>  

> diff --git a/tests/docker/dockerfiles/debian-bootstrap.docker b/tests/docker/dockerfiles/debian-bootstrap.docker

> index 3a9125e497..127782eedf 100644

> --- a/tests/docker/dockerfiles/debian-bootstrap.docker

> +++ b/tests/docker/dockerfiles/debian-bootstrap.docker

> @@ -14,6 +14,9 @@ RUN sed -i 's/in_target mount/echo not for docker in_target mount/g' /debootstra

>  # Run stage 2

>  RUN /debootstrap/debootstrap --second-stage

>  

> +# Do we want to tweak the user?

> +RUN if test -e /setup_user.sh; then /setup_user.sh; fi


If we do above, there is no need to manually add this in dockerfile.

> +

>  # At this point we can install additional packages if we want

>  # Duplicate deb line as deb-src

>  RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list

> -- 

> 2.11.0

> 

> 


Fam
Alex Bennée Jan. 17, 2017, 11:19 a.m. UTC | #2
Fam Zheng <famz@redhat.com> writes:

> On Tue, 12/13 13:22, Alex Bennée wrote:

>> Currently all docker builds are done by exporting a tarball to the

>> docker container and running the build as the containers root user.

>> Other use cases are possible however and it is possible to map a part

>> of users file-system to the container. This is useful for example for

>> doing cross-builds of arbitrary source trees. For this to work

>> smoothly the container needs to have a user created that maps cleanly

>> to the host system.

>>

>> This adds a -u option to the docker script so that:

>>

>>   DEB_ARCH=armhf DEB_TYPE=stable ./tests/docker/docker.py build \

>>     -u --include-executable=arm-linux-user/qemu-arm \

>>     debian:armhf ./tests/docker/dockerfiles/debian-bootstrap.docker

>>

>> Will build a container that can then be run like:

>>

>>   docker run --rm -it -v /home/alex/lsrc/qemu/risu.git/:/src \

>>     --user=alex:alex -w /src/ debian:armhf \

>>     sh -c "make clean && ./configure -s && make"

>

> Sorry for the late reply!


No worries - I only got back to work last week myself ;-)

>

>>

>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

>> ---

>>  tests/docker/docker.py                           | 19 +++++++++++++++++++

>>  tests/docker/dockerfiles/debian-bootstrap.docker |  3 +++

>>  2 files changed, 22 insertions(+)

>>

>> diff --git a/tests/docker/docker.py b/tests/docker/docker.py

>> index 37d83199e7..59baac6bae 100755

>> --- a/tests/docker/docker.py

>> +++ b/tests/docker/docker.py

>> @@ -12,6 +12,7 @@

>>  # the top-level directory.

>>

>>  import os

>> +import stat

>>  import sys

>>  import subprocess

>>  import json

>> @@ -25,6 +26,7 @@ import signal

>>  from tarfile import TarFile, TarInfo

>>  from StringIO import StringIO

>>  from shutil import copy, rmtree

>> +from pwd import getpwuid

>>

>>

>>  DEVNULL = open(os.devnull, 'wb')

>> @@ -225,6 +227,8 @@ class BuildCommand(SubCommand):

>>                              help="""Specify a binary that will be copied to the

>>                              container together with all its dependent

>>                              libraries""")

>> +        parser.add_argument("--user", "-u", action="store_true",

>> +                            help="Add the current user to images passwd")

>

> Maybe use --add-current-user for the full argument name?


Sounds good.

>

>>          parser.add_argument("tag",

>>                              help="Image Tag")

>>          parser.add_argument("dockerfile",

>> @@ -260,6 +264,21 @@ class BuildCommand(SubCommand):

>>                  _copy_binary_with_libs(args.include_executable,

>>                                         docker_dir)

>>

>> +            if args.user:

>> +                uid = os.getuid()

>> +                uname = getpwuid(uid).pw_name

>> +                scriptlet = docker_dir+"/setup_user.sh"

>> +

>> +                # write scriptlet

>> +                setup = open(scriptlet, "w")

>> +                setup.write("#!/bin/sh\n")

>> +                setup.write("useradd -u %d -U %s" % (uid, uname))

>> +                setup.close()

>> +

>> +                st = os.stat(scriptlet)

>> +                os.chmod(scriptlet,

>> +                         st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)

>

> Is it cleaner we inject commands into the docker file directly?


How do you mean? Running a second docker run command after we have built
the image?

IIRC I'd previously tried having a template approach where we took a
docker.in and generated a final template for the build but we abandoned
that approach.

>

>> +

>>              dkr.build_image(tag, docker_dir, dockerfile,

>>                              quiet=args.quiet, argv=argv)

>>

>> diff --git a/tests/docker/dockerfiles/debian-bootstrap.docker b/tests/docker/dockerfiles/debian-bootstrap.docker

>> index 3a9125e497..127782eedf 100644

>> --- a/tests/docker/dockerfiles/debian-bootstrap.docker

>> +++ b/tests/docker/dockerfiles/debian-bootstrap.docker

>> @@ -14,6 +14,9 @@ RUN sed -i 's/in_target mount/echo not for docker in_target mount/g' /debootstra

>>  # Run stage 2

>>  RUN /debootstrap/debootstrap --second-stage

>>

>> +# Do we want to tweak the user?

>> +RUN if test -e /setup_user.sh; then /setup_user.sh; fi

>

> If we do above, there is no need to manually add this in dockerfile.

>

>> +

>>  # At this point we can install additional packages if we want

>>  # Duplicate deb line as deb-src

>>  RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list

>> --

>> 2.11.0

>>

>>

>

> Fam



--
Alex Bennée
Fam Zheng Jan. 17, 2017, 11:34 a.m. UTC | #3
On Tue, 01/17 11:19, Alex Bennée wrote:
> >> +            if args.user:

> >> +                uid = os.getuid()

> >> +                uname = getpwuid(uid).pw_name

> >> +                scriptlet = docker_dir+"/setup_user.sh"

> >> +

> >> +                # write scriptlet

> >> +                setup = open(scriptlet, "w")

> >> +                setup.write("#!/bin/sh\n")

> >> +                setup.write("useradd -u %d -U %s" % (uid, uname))

> >> +                setup.close()

> >> +

> >> +                st = os.stat(scriptlet)

> >> +                os.chmod(scriptlet,

> >> +                         st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)

> >

> > Is it cleaner we inject commands into the docker file directly?

> 

> How do you mean? Running a second docker run command after we have built

> the image?

> 

> IIRC I'd previously tried having a template approach where we took a

> docker.in and generated a final template for the build but we abandoned

> that approach.


build_image() generates a tmp_df, for "LABEL com.qemu..." (I should have named
it org.qemu.., really, it was a silly mistake). We can add an additional "RUN
useradd -u ..." line there just as well.

Fam

> 

> >

> >> +

> >>              dkr.build_image(tag, docker_dir, dockerfile,

> >>                              quiet=args.quiet, argv=argv)

> >>
diff mbox

Patch

diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index 37d83199e7..59baac6bae 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -12,6 +12,7 @@ 
 # the top-level directory.
 
 import os
+import stat
 import sys
 import subprocess
 import json
@@ -25,6 +26,7 @@  import signal
 from tarfile import TarFile, TarInfo
 from StringIO import StringIO
 from shutil import copy, rmtree
+from pwd import getpwuid
 
 
 DEVNULL = open(os.devnull, 'wb')
@@ -225,6 +227,8 @@  class BuildCommand(SubCommand):
                             help="""Specify a binary that will be copied to the
                             container together with all its dependent
                             libraries""")
+        parser.add_argument("--user", "-u", action="store_true",
+                            help="Add the current user to images passwd")
         parser.add_argument("tag",
                             help="Image Tag")
         parser.add_argument("dockerfile",
@@ -260,6 +264,21 @@  class BuildCommand(SubCommand):
                 _copy_binary_with_libs(args.include_executable,
                                        docker_dir)
 
+            if args.user:
+                uid = os.getuid()
+                uname = getpwuid(uid).pw_name
+                scriptlet = docker_dir+"/setup_user.sh"
+
+                # write scriptlet
+                setup = open(scriptlet, "w")
+                setup.write("#!/bin/sh\n")
+                setup.write("useradd -u %d -U %s" % (uid, uname))
+                setup.close()
+
+                st = os.stat(scriptlet)
+                os.chmod(scriptlet,
+                         st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+
             dkr.build_image(tag, docker_dir, dockerfile,
                             quiet=args.quiet, argv=argv)
 
diff --git a/tests/docker/dockerfiles/debian-bootstrap.docker b/tests/docker/dockerfiles/debian-bootstrap.docker
index 3a9125e497..127782eedf 100644
--- a/tests/docker/dockerfiles/debian-bootstrap.docker
+++ b/tests/docker/dockerfiles/debian-bootstrap.docker
@@ -14,6 +14,9 @@  RUN sed -i 's/in_target mount/echo not for docker in_target mount/g' /debootstra
 # Run stage 2
 RUN /debootstrap/debootstrap --second-stage
 
+# Do we want to tweak the user?
+RUN if test -e /setup_user.sh; then /setup_user.sh; fi
+
 # At this point we can install additional packages if we want
 # Duplicate deb line as deb-src
 RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list