Skip to content

Commit

Permalink
Merge pull request #102 from RoboTeamTwente/feature/docker-v2
Browse files Browse the repository at this point in the history
Simplify composes structure using profiles, add diff profile, rename …
  • Loading branch information
JornJorn authored Nov 27, 2023
2 parents d455446 + 73b69f9 commit c64302b
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 205 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/docker-action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,16 @@ jobs:
target: development
tags: roboteamtwente/roboteam:development
-
name: Build sources
name: Build sources from development
uses: addnab/docker-run-action@v3
with:
image: roboteamtwente/roboteam:development
options: -v ${{ github.workspace }}:/home/roboteamtwente/
run: |
sudo ./build.sh
sudo chown -R $(id -u):$(id -g) .
./build.sh
-
name: Build and push release
name: Build and push release from sources
uses: docker/build-push-action@v4
with:
context: .
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ cmake-build-debug/
cmake-build-release/
.cmake/
**/build
**/build_old
.cache
/.vscode
.DS_Store
Expand Down
123 changes: 88 additions & 35 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,51 +15,104 @@ error() {

trap 'error $LINENO' ERR

if [ "$1" == "-y" ];
then
OK=1
fi
help() {
echo "Usage: build.sh [-y] [-o / -o <COMMIT>]
-y : ignore docker enviroment check
-o : build AI from given commit (or origin/main~1 if not specified) and save output in build_old folder
-s : skip external
Example: ./build.sh -o origin/main~3
./build.sh -o bedd8e7ed
'./build.sh -h' to print this help msg."
exit 0
}

OK=0
OLD=0
SKIP=0
COMMIT=origin/main~1

while getopts ":yo:s" opt; do
case ${opt} in
y ) OK=1
;;
o ) OLD=1
COMMIT=${OPTARG}
;;
s ) SKIP=1
;;
\? ) help
;;
esac
done

# Check if the script is being executed from inside container or explicitly
# asked to run it on host environment
if [ -f /.dockerenv ] || [ "$OK" = "1" ];
then
if [ "$0" == "./build.sh" ];
then
echo -e "${GREEN}Checking submodules${RESET}"
git submodule update --init --recursive
echo "Done"
#rm -rf build
mkdir -p build
pushd build
echo -e "${GREEN}Building RoboTeamTwente software${RESET}"
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc) roboteam_observer roboteam_ai roboteam_robothub
popd
echo -e "${GREEN}Installing interface${RESET}"
pushd roboteam_interface
yarn install
popd
pushd external
echo -e "${GREEN}Building external${RESET}"
pushd framework
echo -e "${GREEN}Building external/framework${RESET}"
mkdir -p build
pushd build
cmake ..
make simulator-cli -j$(nproc)
popd
if [ $OLD == 0 ];
then
echo -e "${GREEN}Checking submodules${RESET}"
git submodule update --init --recursive
echo "Done"
#rm -rf build
mkdir -p build
pushd build
echo -e "${GREEN}Building RoboTeamTwente software${RESET}"
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc) roboteam_observer roboteam_ai roboteam_robothub
popd
pushd autoref
echo -e "${GREEN}Building external/autoref${RESET}"
mkdir -p build
pushd build
cmake ..
make autoref-cli -j$(nproc)
echo -e "${GREEN}Installing interface${RESET}"
pushd roboteam_interface
yarn install
popd
if [ $SKIP == 0 ];
then
pushd external
echo -e "${GREEN}Building external${RESET}"
pushd framework
echo -e "${GREEN}Building external/framework${RESET}"
mkdir -p build
pushd build
cmake ..
make simulator-cli -j$(nproc)
popd
popd
pushd autoref
echo -e "${GREEN}Building external/autoref${RESET}"
mkdir -p build
pushd build
cmake ..
make autoref-cli -j$(nproc)
popd
popd
popd
fi
echo -e "${GREEN}Done, exiting builder..${RESET}"
else
echo -e "${GREEN}Checking submodules${RESET}"
git submodule update --init --recursive
echo "Done"
rm -rf build_old # Delete previously built folder, otherwise compose starts with wrong version
mkdir -p build_old/release
pushd build_old
echo -e "${GREEN}Building old RoboTeamTwente AI${RESET}"
git clone https://github.com/RoboTeamTwente/roboteam.git /tmp/roboteam || true # Do not fail if directory already exist
pushd /tmp/roboteam/
echo -e "${GREEN}Building old commit: $(git describe --always --dirty)${RESET}"
git reset --hard --recurse-submodule $COMMIT
echo -e "${GREEN}Calling 'build.sh' in the old commit repo${RESET}"
./build.sh -s
popd
cp -a /tmp/roboteam/build/release/* release/
# Start with a fresh repo in next build, otherwise problems when moving HEAD
rm -rf /tmp/roboteam
popd
popd
echo -e "${GREEN}Done, exiting builder..${RESET}"
echo -e "${GREEN}Done, exiting builder..${RESET}"
fi
else
echo -e "${RED}E: The script must be called from the root folder${RESET}"
exit 1
Expand Down
11 changes: 7 additions & 4 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
#
# =========================================================================== #
#
# Manually build the container:
# docker build -t rtt-build-env .
# Manually build the development container:
# docker build -t roboteamtwente/roboteam:development --target development .
#
# Spin-up the container:
# docker run -itd --name rtt-build-env -h rtt-build-env -v <abs_path_to_the_repo_root>/:/home/roboteamtwente/roboteam rtt-build-env
# Spin-up the development container:
# docker run -itd --name rtt-build-env -h rtt-build-env -v <abs_path_to_the_repo_root>/:/home/roboteamtwente/roboteam roboteamtwente/roboteam:development
#
# Start/Stop container:
# docker <start/stop> rtt-build-env
Expand Down Expand Up @@ -80,6 +80,9 @@ RUN adduser -D $USER && \
USER $USER
WORKDIR $HOME

# Add roboteam libraries to LD path
ENV LD_LIBRARY_PATH=$HOME/lib/

# Copy just build binaries (roboteam software) from volume to container home
# Note: cannot COPY from outside context, build from parent folder
COPY --chown=$USER:$USER ../build/release/ $HOME/
83 changes: 65 additions & 18 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ For a simulation tournament (2022/04), every team had to put their program in a
## Structure
The description of the environment is located in the Dockerfile inside the `docker` folder. The file is divided in two targets: "development" and "release".

Release target is only intended as a GitHub Action target, its purpose is to create the Docker image containing runnable binaries that can be pushed into a Registry. If you really want to build it locally you can do it by first building the development target, then compile sources with it and then build the release target. Note that release target contains only RoboTeamTwente binaries and not external ones like erforce simulator or erforce autoref.
**Release target is only intended as a GitHub Action target**, its purpose is to create the Docker image containing runnable binaries that can be pushed into a Registry. If you really want to build it locally you can do it by first building the development target, then compile sources with it and then build the release target. Note that release target contains only RoboTeamTwente binaries and not external ones like erforce simulator or erforce autoref, it does not contain RTT autoref either.
Development target is instead intended as a normal usage target.

Inside `docker` folder there are three subdirectories: `builder` `game` and `simulator`.
Inside `docker` folder there are three subdirectories: `builder` and `runner`.
Every folder contains a convenient docker compose file:
- builder is used by lazy people like me to build sources without building and then directly executing command on a container
- simulator is used to start every service needed to start a simulation (apart from some external software, see [Normal Usage](#normal-usage)
- game is used to start roboteam software in real game mode
- builder is used by lazy people like me to build sources without building and then directly executing command on a container.
Builder contains two (default and `diff`) profiles: one is used to simply build current source while the second is used to build both current sources and and an old commit of the current repo, this is used to start `diff` compose to compare current ai with an old version to evaluate performances after changes.
- runner is used to start every service needed to start a simulation (with current ai vs current ai or current ai vs and old version) or a game (game needs also some external software, see [Normal Usage](#normal-usage)).
This is again done through docker compose profiles specifying `simulation`, `diff` or `game` profile.

Docker composes use volumes because this way it's possible to compile sources and start up just built services without rebuilding any container.
NOTE: Docker composes use volumes because this way it's possible to compile sources and start up just built services without rebuilding any container.

## How to use?
First things first: for convenience create an ENV VAR containing the path to this repo (change rc file accordingly to your shell). Make sure to be in the repo root folder (should be one level up from the folder in which this README is) and then:
Expand All @@ -34,15 +35,29 @@ git submodule update --init --recursive
Then, install prerequisite: install Docker https://docs.docker.com/engine/install/, if you want you can add yourself to docker group in order to run Docker command without invoking root user https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user and finally install docker compose.

Every subproject is meant to be executed as a service using its own container from a docker compose.
Every RTT subproject (service) runs in its own 'rtt-build-env' container, this way that all dependencies and requirements are satisfied.
Every RTT subproject (service) runs in its own container (based on the same roboteamtwente image), this way that all dependencies and requirements are satisfied.
Subproject containers start their own software from `build/release/bin` folder mounted as a volume.

### Normal usage
### Basestation
In order to access Basestation tty from inside Docker container we first need to set a persistent name to the tty device:
```
echo "SUBSYSTEM==\"tty\", ATTRS{idVendor}==\"0483\", ATTRS{idProduct}==\"5740\", ATTRS{serial}==\"*\", SYMLINK+=\"rtt-basestation\"" | sudo tee -a /etc/udev/rules.d/99-rtt-basestation.rules
```

Add yourself to the dialout group:
```
sudo usermod -a -G dialout $USER
```
Finally, reboot your pc to apply.

### Normal/development usage
1) Make your edits on RTT sources
2) Spin-up "builder" compose
3) Spin-up "simulator"/"game" compose
3) Spin-up "runner" compose
4) (Game-only) Download, install and run ssl-vision
5) (Game-only) Configure udev rule for Basestation, see [Basestation](#basestation)
5) You can now reach game controller UI on localhost:8081 and roboteam interface on localhost:8080, connect to primary_ai (port 12676) or secondary_ai (port 12677).
6) If you started "game" open interface and select "basestation"

As simple as that.

Expand All @@ -51,32 +66,53 @@ As simple as that.
cd $ROBOTEAM_REPO/docker/builder
docker compose up
```
or, if you want to build diff (compare current ai with a previous version):
```
COMMIT=<commit> docker compose --profile diff up
```
NOTE: if you dont't specify COMMIT=<commit>, the default will be origin/main~1

2. Start services:
```
cd $ROBOTEAM_REPO/docker/<simulator / game>
docker compose up <-d>
cd $ROBOTEAM_REPO/docker/runner
docker compose --profile <simulator / diff / game> up -d
```
When you want to stop services:
```
docker compose down
docker compose --profile <simulator / diff /game> down
```

Note: you may want to use `docker logs -t <container_name>` to see command output of a specific container (service).
Note: you may want to use `docker logs -t <container_name>` to see output of a container (service).
Example: `docker logs -t RTT_roboteam_primary_ai`

NOTE: If you notice USB errors when running "game" compose, do a `docker compose --profile game down`, detach and re-attach basestation and the start game again.

### Release usage
Pull release image:
```
docker pull roboteamtwente/roboteam:latest
```
Run the image:
```
docker run -itd --name rtt-release-env -h rtt-release-env roboteamtwente/roboteam:latest
```

#### TODO
https://lemariva.com/blog/2020/10/vscode-c-development-and-debugging-containers

### Docker geeks
#### Build environment
You can manually build the 'build environment' container doing:
We highly discourage executing command under this section unless you know what you are doing and for some reason you need to edit dockerfiles or composes structure.

Note: remember that our "composes" download image from Dockerhub if not available locally, thus, if you want to test with a new image you need to build the new image and tag it with the same name (`roboteamtwente/roboteam:development` or `roboteamtwente/roboteam:latest`).
#### Development environment
You can manually build the 'development environment' container executing:
```
docker build -t rtt-build-env .
docker build -t roboteamtwente/roboteam:development --target development .
```

Spin-up the just built container:
```
docker run -itd --name rtt-build-env -h rtt-build-env -v $ROBOTEAM_REPO:/home/roboteamtwente/roboteam rtt-build-env
docker run -itd --name rtt-build-env -h rtt-build-env -v $ROBOTEAM_REPO:/home/roboteamtwente/roboteam roboteamtwente/roboteam:development
```

Then, you can compile sources using `build.sh` script located in the repo root folder from inside the container.
Expand All @@ -94,7 +130,18 @@ Remember that you can stop/start 'rtt-build-env' container simply using:
docker <start/stop> rtt-build-env
```

Note: avoid tagging the "run" stage container with the same name "rtt-build-env", otherwise when you will start the "build" compose you won't be able to compile sources (because the compose will be re-using the container with that name).
#### Release environment
Note: **if you really want to build the release container** (highly discouraged) you must first build the development container as explained in the previous section, then you need to compile sources using `build.sh` script and lastly you can build the container.

Note that the release container can be downloaded from Dockerhub (highly recommended) by a simple:
`docker pull roboteamtwente/roboteam:latest`.

In order to build the release container, you must call the `docker build` command from parent folder, otherwise docker is not able to copy files from outside context:
```
cd ../
docker build -t roboteamtwente/roboteam:latest --target release -f ./docker/Dockerfile .
```

#### Manually starting a service
You can start a service by simply executing the binary from the rtt-build-env container.
Example:
Expand Down
20 changes: 15 additions & 5 deletions docker/builder/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@ version: '3'
services:

roboteam_builder:
build:
context: ../
target: development
image: rtt-build-env:latest
image: roboteamtwente/roboteam:development
container_name: RTT_roboteam_builder
restart: "no"
working_dir: "/home/roboteamtwente/"
command: sh -c "./build.sh"
volumes:
- ../../:/home/roboteamtwente/
- ../../:/home/roboteamtwente/

roboteam_builder_old:
image: roboteamtwente/roboteam:development
container_name: RTT_roboteam_builder_old
restart: "no"
depends_on:
roboteam_builder:
condition: service_completed_successfully
working_dir: "/home/roboteamtwente/"
command: sh -c "./build.sh -o $COMMIT"
volumes:
- ../../:/home/roboteamtwente/
profiles: ["diff"]
Loading

0 comments on commit c64302b

Please sign in to comment.