[docker] Refactor container to be more developer-friendly Clean up the Docker container image to make it more developer-friendly. - Ensure that all OpenTitan dependencies are available. - Provide a convenient way to run commands within the container as current local user, ensuring that file permissions of mounted volumes match. - Give the user within the container sudo rights, if it wants to use it e.g. to install additional packages. - Provide a convenient way to load additional configuration into the environment, e.g. the path to a license server. - Generally clean up the Dockerfile and make it consistent. - Remove some additionally installed packages where we don't know what they are used for. We can always add them back if we find out the use case. - Use the general mailing list as "maintainer" email address. Signed-off-by: Philipp Wagner <phw@lowrisc.org>
diff --git a/util/container/Dockerfile b/util/container/Dockerfile index 9d9e14e..c64eb47 100644 --- a/util/container/Dockerfile +++ b/util/container/Dockerfile
@@ -20,12 +20,13 @@ ARG RUST_VERSION LABEL version="1.0" -LABEL description="OpenTitan container for hardware development." -LABEL maintainer="miguelosorio@google.com" +LABEL description="OpenTitan development container." +LABEL maintainer="opentitan-dev@opentitan.org" -WORKDIR /tools +# Use bash as default shell. +RUN ln -sf /bin/bash /bin/sh -# Add OBS repository to apt sources +# Add OBS repository to apt sources. RUN OBS_URL="https://download.opensuse.org/repositories"; \ OBS_PATH="/home:/phiwag:/edatools/xUbuntu_18.04"; \ REPO_URL="${OBS_URL}${OBS_PATH}"; \ @@ -41,68 +42,76 @@ } && \ echo "$EDATOOLS_REPO" > "$TMPDIR/obs.list" && \ mv "$TMPDIR/obs.asc" /etc/apt/trusted.gpg.d/obs.asc && \ - mv "$TMPDIR/obs.list" /etc/apt/sources.list.d/edatools.list && \ - apt-get update + mv "$TMPDIR/obs.list" /etc/apt/sources.list.d/edatools.list -# Install (and cleanup) required packages (from apt-requirements.txt) -# The list of extra packages is leftover from before this Dockerfile used -# apt-requirements.txt +# Install system packages # -# This also adds `locales` and `locales-all` so we can set the locale to utf-8 +# Install (and cleanup) required packages (from apt-requirements.txt). +# Also add some additional packages for the use within this container and for +# developer convenience: +# - gosu and sudo are used by the scripting to make the image more convenient +# to use. +# - locales and locales-all are required to set the locale. +# - minicom and screen are useful to see UART communication. +# - dc and time are requirements of Synopsys VCS. COPY apt-requirements.txt /tmp/apt-requirements.txt -RUN echo "verilator-${VERILATOR_VERSION}" >>/tmp/apt-requirements.txt && \ - echo "openocd-${OPENOCD_VERSION}" >>/tmp/apt-requirements.txt && \ - sed -i -e '/^$/d' -e '/^#/d' -e 's/#.*//' /tmp/apt-requirements.txt && \ - xargs apt-get install -y </tmp/apt-requirements.txt && \ - apt-get update && apt-get install -y \ +RUN echo "verilator-${VERILATOR_VERSION}" >>/tmp/apt-requirements.txt \ + && echo "openocd-${OPENOCD_VERSION}" >>/tmp/apt-requirements.txt \ + && sed -i -e '/^$/d' -e '/^#/d' -e 's/#.*//' /tmp/apt-requirements.txt \ + && apt-get update \ + && xargs apt-get install -y </tmp/apt-requirements.txt \ + && apt-get install -y \ + sudo \ + gosu \ locales \ locales-all \ - gnupg2 \ - libc6-i386 \ - libtool \ minicom \ - screen && \ - apt-get clean; \ + screen \ + dc \ + time \ + && apt-get clean; \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* +# RISC-V device toolchain +COPY util/get-toolchain.py /tmp/get-toolchain.py +RUN /tmp/get-toolchain.py -r ${RISCV_TOOLCHAIN_TAR_VERSION} \ + && rm -f /tmp/get-toolchain.py + # Set Locale to utf-8 everywhere ENV LC_ALL en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en -ENV PATH "/root/.local/bin:${PATH}" +# Scripting for use within this container. +COPY util/container/start.sh /start.sh +COPY util/container/sudoconf /etc/sudoers.d/dev + +# Add the development user (UID/GID to be replaced). +RUN groupadd dev \ + && useradd --create-home -g dev dev \ + && usermod -p '*' dev \ + && passwd -u dev + +# All subsequent steps are performed as user. +USER dev + +# Install Rust plus packages. +COPY sw/vendor/rustup/rustup-init.sh /tmp/rustup-init.sh +RUN /tmp/rustup-init.sh -y --default-toolchain ${RUST_VERSION} + +# Install Python plus packages. +# # Explicitly updating pip and setuptools is required to have these tools # properly parse Python-version metadata, which some packages uses to # specify that an older version of a package must be used for a certain # Python version. If that information is not read, pip installs the latest # version, which then fails to run. -RUN python3 -m pip install --user -U pip setuptools - +ENV PATH "/home/dev/.local/bin:${PATH}" COPY python-requirements.txt /tmp/python-requirements.txt -RUN pip3 install --user -r /tmp/python-requirements.txt +RUN python3 -m pip install --user -U pip setuptools \ + && python3 -m pip install --user -r /tmp/python-requirements.txt \ + --no-warn-script-location -COPY util/get-toolchain.py /tmp/get-toolchain.py -RUN /tmp/get-toolchain.py -r ${RISCV_TOOLCHAIN_TAR_VERSION} -RUN rm /tmp/python-requirements.txt /tmp/get-toolchain.py +USER root -COPY sw/vendor/rustup/rustup-init.sh /tmp/rustup-init.sh -# This file does not create a user, so we install rustup and cargo under -# /tools. -ENV RUSTUP_HOME /tools/.rustup -ENV CARGO_HOME /tools/.cargo -# Permissions are relaxed so that the container user can also download -# dependencies during build. -RUN /tmp/rustup-init.sh -y \ - --default-toolchain ${RUST_VERSION} && \ - chmod -R o=u ${RUSTUP_HOME} ${CARGO_HOME} - -# Use bash as default shell -RUN ln -sf /bin/bash /bin/sh - -# Include tools in PATH. -ENV PATH "/tools/verilator/${VERILATOR_VERSION}/bin:${CARGO_HOME}/bin:${PATH}" - -# Configures default container user. -ENV USER ot - -ENTRYPOINT /bin/bash +ENTRYPOINT [ "/start.sh" ]
diff --git a/util/container/README.md b/util/container/README.md index 256984b..b4fa6cc 100644 --- a/util/container/README.md +++ b/util/container/README.md
@@ -16,8 +16,25 @@ ## Using the Container -To run container in interactive mode: +Run the container with `docker run`, mapping the current working directory to +`/home/dev/src`. The user `dev` will have the same user ID as the current user +on the host (you!), causing all files created by the `dev` user in the container +to be owned by the current user on the host. -```shell -$ docker run -it -v $REPO_TOP:/repo -w /repo opentitan --user $(id -u):$(id -g) +If you'd like to initialize your shell environment in a specific way, you can +pass an environment variable `USER_CONFIG=/path/to/a/script.sh`. Otherwise, +remove the `--env USER_CONFIG` argument from the invocation shown below. + +The script passed through this mechanism will be sourced. The path of the script +must be within the container, e.g. in the OpenTitan repository directory. + ``` +docker run -t -i \ + -v $(pwd):/home/dev/src \ + --env DEV_UID=$(id -u) --env DEV_GID=$(id -g) \ + --env USER_CONFIG=/home/dev/src/docker-user-config.sh \ + opentitan:latest \ + bash +``` + +You can use `sudo` within the container to gain root permissions.
diff --git a/util/container/start.sh b/util/container/start.sh new file mode 100755 index 0000000..07fde16 --- /dev/null +++ b/util/container/start.sh
@@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Map the "dev" user to an UID passed in as environment variable to ensure +# files are written by the same UID/GID into mounted volumes. +DEV_UID=${DEV_UID:-1000} +DEV_GID=${DEV_GID:-1000} +groupmod -o -g "$DEV_GID" dev >/dev/null 2>&1 +usermod -o -u "$DEV_UID" dev >/dev/null 2>&1 + +# Load user configuration. +test -f "${USER_CONFIG}" && export BASH_ENV=${USER_CONFIG} + +cd /home/dev +exec gosu dev:dev /bin/bash -c "$@"
diff --git a/util/container/sudoconf b/util/container/sudoconf new file mode 100644 index 0000000..0f89e62 --- /dev/null +++ b/util/container/sudoconf
@@ -0,0 +1,2 @@ +# Give dev user account root permissions in container +dev ALL=(ALL) NOPASSWD:ALL