SetUp Docker - dingdongdengdong/astra_ws GitHub Wiki
if you don't know docker, must learn.
How to Run
code detail
.devcontainer
Let's break down Dockerfile
, devcontainer.json
, and ros_entrypoint.sh
.
Dockerfile
The Dockerfile
defines the steps to build a Docker image, which serves as the base for your development environment.
FROM ros:humble-ros-base
ARG USERNAME=rosdev
ARG UID=1000
ARG GID=$UID
# Install some dependencies packages
RUN apt update -q \
&& apt upgrade -q -y \
&& apt install -y --no-install-recommends \
software-properties-common \
python3-pip \
python-is-python3 \
xauth \
ros-humble-desktop \
&& apt clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Create and switch to user
RUN groupadd -g $GID $USERNAME \
&& useradd -lm -u $UID -g $USERNAME -s /bin/bash $USERNAME \
&& echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
USER $USERNAME
# Create workspace so that user own this directory
RUN mkdir -p /home/$USERNAME/ros2_ws/src
WORKDIR /home/$USERNAME/ros2_ws
# Copy configuration files
RUN echo 'source /opt/ros/'$ROS_DISTRO'/setup.bash' >> /home/$USERNAME/.bashrc \
&& echo 'source /home/'$USERNAME'/ros2_ws/install/setup.bash' >> /home/$USERNAME/.bashrc \
&& echo 'export PATH="$HOME/.local/bin:$PATH"' >> /home/$USERNAME/.bashrc
# RUN echo 'export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages:/opt/ros/humble/lib/python3.10/site-packages/' >> /home/$USERNAME/.bashrc
# Setup entrypoint
COPY ./ros_entrypoint.sh /
ENTRYPOINT ["/ros_entrypoint.sh"]
CMD ["bash"]
Line-by-Line Explanation:
FROM ros:humble-ros-base
:- This is the base image for your Docker container. It specifies that your image will be built on top of the official ROS 2 Humble Hawksbill
ros-base
image.ros-base
includes the core ROS 2 packages and build tools but doesn't include desktop tools or GUI components.
- This is the base image for your Docker container. It specifies that your image will be built on top of the official ROS 2 Humble Hawksbill
ARG USERNAME=rosdev
:- Declares a build-time argument
USERNAME
with a default value ofrosdev
. This allows you to customize the username when building the image without modifying theDockerfile
.
- Declares a build-time argument
ARG UID=1000
:- Declares a build-time argument
UID
with a default value of1000
. This is the User ID for the new user. Using1000
is common as it often corresponds to the first non-root user on Linux systems.
- Declares a build-time argument
ARG GID=$UID
:- Declares a build-time argument
GID
(Group ID) and sets its default value to be the same asUID
. This creates a group with the same ID as the user's ID.
- Declares a build-time argument
RUN apt update -q \ ...
:- This command block executes several
apt
commands in a single layer to minimize image size and improve build performance.apt update -q
: Updates the package lists quietly.apt upgrade -q -y
: Upgrades all installed packages quietly and without prompting.apt install -y --no-install-recommends ...
: Installs essential packages:software-properties-common
: Providesadd-apt-repository
.python3-pip
: Python package installer.python-is-python3
: Ensurespython
command points topython3
.xauth
: Required for X11 forwarding (GUI applications).ros-humble-desktop
: Crucially, this installs the full ROS 2 desktop environment including RViz, Gazebo (if available for humble-desktop), and other GUI tools. This is a significant addition compared to theros-base
base image.
&& apt clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
: Cleans up the APT cache and temporary files to reduce the final image size.
- This command block executes several
RUN groupadd -g $GID $USERNAME \ ...
:- This block creates a new user and configures sudo access.
groupadd -g $GID $USERNAME
: Creates a new user group with the specified GID and username.useradd -lm -u $UID -g $USERNAME -s /bin/bash $USERNAME
: Creates a new user with the specified UID, GID, home directory (-m
), and sets/bin/bash
as their default shell.echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
: Adds the new user to thesudoers
file, allowing them to runsudo
commands without being prompted for a password. This is common in development containers for convenience.
- This block creates a new user and configures sudo access.
USER $USERNAME
:- Switches the user context from
root
to the newly created$USERNAME
for subsequent commands. This is a security best practice, as running processes as root is generally discouraged.
- Switches the user context from
RUN mkdir -p /home/$USERNAME/ros2_ws/src
:- Creates the ROS 2 workspace directory structure (
ros2_ws/src
) in the user's home directory. The-p
flag ensures that parent directories are created if they don't exist.
- Creates the ROS 2 workspace directory structure (
WORKDIR /home/$USERNAME/ros2_ws
:- Sets the working directory for any subsequent
RUN
,CMD
,ENTRYPOINT
,COPY
, orADD
instructions to/home/$USERNAME/ros2_ws
. This means when you enter the container, you'll land in this directory.
- Sets the working directory for any subsequent
RUN echo 'source /opt/ros/'$ROS_DISTRO'/setup.bash' >> /home/$USERNAME/.bashrc \ ...
:- Appends commands to the
.bashrc
file of therosdev
user. This ensures that these commands are executed every time a new bash shell is started by the user.source /opt/ros/$ROS_DISTRO/setup.bash
: Sources the main ROS 2 installation setup file. This sets up ROS 2 environment variables likeROS_DISTRO
,AMENT_PREFIX_PATH
, etc.source /home/$USERNAME/ros2_ws/install/setup.bash
: Sources the setup file for your custom ROS 2 workspace. This allows the system to find packages you build within/home/$USERNAME/ros2_ws
.export PATH="$HOME/.local/bin:$PATH"
: Adds the user's local binary directory to the systemPATH
, useful for executables installed viapip --user
or other local installations.
- Appends commands to the
# RUN echo 'export PYTHONPATH=...'
:- This line is commented out. If uncommented, it would add specific Python paths to
PYTHONPATH
. This can be necessary for certain Python packages or ROS 2 environments where Python modules are installed in non-standard locations.
- This line is commented out. If uncommented, it would add specific Python paths to
COPY ./ros_entrypoint.sh /
:- Copies the
ros_entrypoint.sh
script from your local directory into the root directory (/
) of the Docker image.
- Copies the
ENTRYPOINT ["/ros_entrypoint.sh"]
:- Sets the default command that will be executed when a container is started from this image. This means
ros_entrypoint.sh
will always run first.
- Sets the default command that will be executed when a container is started from this image. This means
CMD ["bash"]
:- Provides default arguments to the
ENTRYPOINT
. In this case, if you run the container without specifying a command (e.g.,docker run my_ros_image
),bash
will be passed as an argument toros_entrypoint.sh
. This effectively meansros_entrypoint.sh bash
will be executed, giving you an interactive bash shell after the entrypoint script has set up the environment.
- Provides default arguments to the
ros_entrypoint.sh
This script is the entry point for your Docker container. It's designed to set up the necessary ROS 2 environment before the main command (usually bash
) is executed.
#!/bin/bash
# shellcheck disable=SC1090,SC1091
set -e
# setup ros2 environment
source /opt/ros/"$ROS_DISTRO"/setup.bash --
source ~/ros2_ws/install/setup.bash --
export PATH="$HOME/.local/bin:$PATH"
# export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages:/opt/ros/humble/lib/python3.10/site-packages/
exec "$@"
Line-by-Line Explanation:
#!/bin/bash
:- Shebang line, specifying that the script should be executed with
bash
.
- Shebang line, specifying that the script should be executed with
# shellcheck disable=SC1090,SC1091
:- These are comments for
shellcheck
, a static analysis tool for shell scripts. They disable specific warnings related tosource
commands, whichshellcheck
can sometimes flag for dynamic paths.
- These are comments for
set -e
:- This is an important shell option. It means that the script will exit immediately if any command fails (returns a non-zero exit status). This helps in debugging, as you'll know if an environment setup step failed.
# setup ros2 environment
:- A comment indicating the purpose of the following lines.
source /opt/ros/"$ROS_DISTRO"/setup.bash --
:- Sources the main ROS 2 installation setup file. The
ROS_DISTRO
variable is set by theros-humble-ros-base
image. The--
at the end is often used to ensuresource
doesn't interpret subsequent arguments as options. This command sets up all the core ROS 2 environment variables.
- Sources the main ROS 2 installation setup file. The
source ~/ros2_ws/install/setup.bash --
:- Sources the setup file for your custom ROS 2 workspace. This is crucial for your system to find and use any ROS 2 packages you develop and build within your
ros2_ws
. It overlays your workspace on top of the base ROS 2 installation.
- Sources the setup file for your custom ROS 2 workspace. This is crucial for your system to find and use any ROS 2 packages you develop and build within your
export PATH="$HOME/.local/bin:$PATH"
:- Adds the
~/.local/bin
directory to the beginning of thePATH
environment variable. This ensures that any executables installed in this user-specific directory (e.g., viapip install --user
) are found first when you run commands.
- Adds the
# export PYTHONPATH=...
:- This line is commented out. Similar to the
Dockerfile
, if uncommented, it would extend thePYTHONPATH
to include specific Python directories. This is useful if you encounter Python module import issues with ROS 2 or other Python libraries installed in non-standard locations.
- This line is commented out. Similar to the
exec "$@"
:- This is the final and crucial command.
"$@"
expands to all the arguments passed to theros_entrypoint.sh
script. As per theDockerfile
'sCMD ["bash"]
, this will typically bebash
.exec
replaces the current shell process with the command specified by"$@"
. This means that afterros_entrypoint.sh
has finished setting up the environment, it doesn't just runbash
as a child process; it becomes thebash
process. This is good practice for Docker entry points as it avoids an extra shell process and correctly passes signals (like Ctrl+C) to the main application.
- This is the final and crucial command.
devcontainer.json
This file is a configuration file used by the VS Code Dev Containers extension. It tells VS Code how to set up and interact with your development environment inside a Docker container.
{
"name": "ROS 2 Workspace humble-ros-base", // Thx https://github.com/BrunoB81HK/ros2-workspace-devcontainer-template/tree/main/src/ros2-workspace
"remoteUser": "rosdev",
"build": {
"dockerfile": "Dockerfile",
"args": {
"USERNAME": "rosdev",
"GID": "1000",
"UID": "1000"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"charliermarsh.ruff",
"ms-vscode.cpptools-extension-pack",
"ms-iot.vscode-ros",
"smilerobotics.urdf",
"redhat.vscode-xml",
"tamasfe.even-better-toml",
"timonwong.shellcheck",
"yzhang.markdown-all-in-one"
],
"settings": {
"files.associations": {
"*.rviz": "yaml",
"*.srdf": "xml",
"*.urdf": "xml",
"*.xacro": "xml"
}
}
}
},
"workspaceFolder": "/home/rosdev/ros2_ws",
"workspaceMount": "source=${localWorkspaceFolder},target=/home/rosdev/ros2_ws,type=bind",
"mounts": [],
"runArgs": [
"--net=host",
"-v", "/dev:/dev",
"--privileged",
"-v=/tmp/.X11-unix:/tmp/.X11-unix:rw", "--env=DISPLAY",
"--gpus=all", "-e", "NVIDIA_DRIVER_CAPABILITIES=all"
],
"features": {
// "ghcr.io/rocker-org/devcontainer-features/miniforge:1": {}
}
}
Line-by-Line Explanation:
"name": "ROS 2 Workspace humble-ros-base"
:- This is a human-readable name for your development container that will appear in VS Code.
"remoteUser": "rosdev"
:- Specifies the default user that VS Code will connect as inside the container. This should match the
USERNAME
you created in yourDockerfile
.
- Specifies the default user that VS Code will connect as inside the container. This should match the
"build"
:- This section configures how the Docker image for the container is built.
"dockerfile": "Dockerfile"
: Points to yourDockerfile
in the same directory, telling VS Code to build the image from it."args"
: Passes build arguments to yourDockerfile
. These values will override any defaultARG
values in theDockerfile
."USERNAME": "rosdev"
,"GID": "1000"
,"UID": "1000"
: Ensures the userrosdev
with specified IDs is created during the image build process.
- This section configures how the Docker image for the container is built.
"customizations"
:- This section allows you to customize VS Code's behavior specifically for this dev container.
"vscode"
: Contains VS Code-specific customizations."extensions"
: An array of VS Code extension IDs. These extensions will be automatically installed and enabled within the dev container environment."ms-python.python"
: Python extension for linting, debugging, etc."charliermarsh.ruff"
: Ruff linter for Python."ms-vscode.cpptools-extension-pack"
: C/C++ extension pack for IntelliSense, debugging, etc."ms-iot.vscode-ros"
: Official Microsoft ROS extension, providing ROS-specific features."smilerobotics.urdf"
: URDF (Unified Robot Description Format) file support."redhat.vscode-xml"
: XML language support."tamasfe.even-better-toml"
: TOML (Tom's Obvious, Minimal Language) file support."timonwong.shellcheck"
: Shell script linting."yzhang.markdown-all-in-one"
: Comprehensive Markdown support.
"settings"
: VS Code workspace settings that will be applied when you open the project in the container."files.associations"
: Maps file extensions to specific language modes, improving syntax highlighting and IntelliSense."*.rviz": "yaml"
: Treats.rviz
files as YAML."*.srdf": "xml"
: Treats.srdf
(Semantic Robot Description Format) files as XML."*.urdf": "xml"
: Treats.urdf
files as XML."*.xacro": "xml"
: Treats.xacro
(XML macro) files as XML.
- This section allows you to customize VS Code's behavior specifically for this dev container.
"workspaceFolder": "/home/rosdev/ros2_ws"
:- Sets the default working directory for the VS Code workspace inside the container. When you open a terminal in VS Code, it will typically start in this directory.
"workspaceMount": "source=${localWorkspaceFolder},target=/home/rosdev/ros2_ws,type=bind"
:- This crucial setting mounts your local project folder into the container.
source=${localWorkspaceFolder}
: Refers to the path of your local folder opened in VS Code.target=/home/rosdev/ros2_ws
: Specifies the destination path inside the container where your local folder will be mounted.type=bind
: Uses a bind mount, meaning changes on your local machine are immediately reflected in the container and vice-versa.
- This crucial setting mounts your local project folder into the container.
"mounts": []
:- An empty array, but this is where you would define additional mounts (e.g., named volumes, other bind mounts) if needed.
"runArgs"
:- An array of additional arguments that are passed directly to the
docker run
command when the container is created. These are critical for specific container functionalities."--net=host"
: Configures the container to use the host's network namespace. This allows the container to directly access network services on the host and vice-versa, which can simplify ROS 2 communication, especially if you have other ROS nodes running outside the container."-v", "/dev:/dev"
: Mounts the host's/dev
directory into the container. This is essential for the container to access hardware devices (e.g., USB ports, serial devices) connected to the host machine. The comment// See: https://micro.ros.org/docs/tutorials/core/first_application_linux/
suggests its relevance for micro-ROS development."--privileged"
: Grants extended privileges to the container. This can be necessary for certain operations that require direct hardware access or low-level system calls (e.g., runningffmpeg
as mentioned in the comment). Use with caution as it reduces isolation."-v=/tmp/.X11-unix:/tmp/.X11-unix:rw", "--env=DISPLAY"
: These arguments enable X11 forwarding, allowing GUI applications (like RViz or Gazebo) running inside the Docker container to display their windows on your host machine's desktop.-v=/tmp/.X11-unix:/tmp/.X11-unix:rw
: Mounts the X11 socket, which is how X clients communicate with the X server.--env=DISPLAY
: Passes theDISPLAY
environment variable from the host to the container, telling GUI applications where to connect to the X server.
"--gpus=all", "-e", "NVIDIA_DRIVER_CAPABILITIES=all"
: These arguments enable GPU access within the container, which is vital for applications requiring hardware acceleration (e.g., simulation, machine learning inference). This requires NVIDIA drivers and Docker's NVIDIA Container Toolkit to be installed on your host system.--gpus=all
: Exposes all available GPUs to the container.-e NVIDIA_DRIVER_CAPABILITIES=all
: Specifies that the container should have access to all NVIDIA driver capabilities.
- An array of additional arguments that are passed directly to the
"features": {}
:- This section allows you to add pre-built Dev Container Features to your environment. Features are self-contained bundles of installation scripts and configurations. The commented-out line
"ghcr.io/rocker-org/devcontainer-features/miniforge:1": {}
shows an example of how to add a feature (in this case, Miniforge for Conda environments).
- This section allows you to add pre-built Dev Container Features to your environment. Features are self-contained bundles of installation scripts and configurations. The commented-out line