Dockerized ROS 2 Galactic RViz2 environment with browser access through noVNC and a small Node.js control panel for launching isolated AWS ECS Fargate tasks.
- ROS 2 Galactic base image with RViz2 installed.
- Browser terminal through
ttyd. - Virtual desktop stack using
Xvfb,openbox,x11vnc,websockify, and noVNC. rviz2-wrapperscript that starts RViz2 on the virtual display.- Express control-panel API that launches ECS Fargate tasks per student.
- GitHub Actions workflow for building the Docker image, pushing it to ECR, and rendering an ECS task definition.
.
|-- control-panel/
| |-- package.json
| `-- server.js
|-- docker/
| |-- Dockerfile
| |-- ros_entrypoint.sh
| |-- rviz-novnc.html
| |-- rviz2-wrapper.sh
| `-- supervisord.conf
|-- .github/workflows/deploy.yml
|-- docker-compose.yml
|-- task-definition.json
`-- README.md
- Docker and Docker Compose.
- Node.js 18 or newer for the control panel.
- AWS account with ECS, ECR, IAM, VPC subnet, and security group configured.
- AWS credentials with permission to run ECS tasks and push images to ECR.
Build and start the container:
docker compose up --buildOpen the browser services:
- noVNC desktop: http://localhost:6090
- browser terminal: http://localhost:8081
- direct VNC:
localhost:5901
From the browser terminal, launch RViz2:
rviz2-wrapperThe wrapper sets DISPLAY=:98, sources ROS Galactic, and starts rviz2 inside the virtual desktop session.
Install dependencies:
cd control-panel
npm installCreate a .env file in control-panel/:
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
PORT=3000Start the API server:
npm startLaunch a lab environment:
curl -X POST http://localhost:3000/api/launch-lab \
-H "Content-Type: application/json" \
-d "{\"studentId\":\"student-001\"}"The API launches the ECS task definition rviz2-novnc-task in the ros-learning-cluster cluster and passes STUDENT_ID into the container.
Deployment is handled by .github/workflows/deploy.yml on pushes to main.
The workflow:
- Authenticates to AWS.
- Logs in to Amazon ECR.
- Builds the Docker image from
docker/. - Pushes the image to the
rviz2-novncECR repository. - Replaces
REPLACE_ME_IN_PIPELINEintask-definition.jsonwith the pushed image URI. - Registers/deploys the task definition to ECS.
Required GitHub environment/secrets:
- Environment:
v2_snare_light AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY
Current AWS settings are configured for:
- Region:
ap-northeast-1 - ECS cluster:
ros-learning-cluster - ECR repository:
rviz2-novnc - ECS task family:
rviz2-novnc-task - Container name:
rviz2-container
The task definition exposes:
8080: ttyd browser terminal inside the container.6090: noVNC web UI.
The local Docker Compose file maps these as:
- Host
8081to container8080. - Host
6090to container6090. - Host
5901to container5901.
The ECS cluster, subnet, security group, and task definition names are currently hard-coded in control-panel/server.js. Update these values before using a different AWS account or VPC:
cluster: 'ros-learning-cluster'
taskDefinition: 'rviz2-novnc-task'
subnets: ['subnet-08f8aad16309319ec']
securityGroups: ['sg-02390fef96a5c1ea4']The task execution role is configured in task-definition.json:
"executionRoleArn": "arn:aws:iam::221131121759:role/ecsTaskExecutionRole"- Do not commit
.envfiles or AWS credentials. - Remove credential debug logging from
control-panel/server.jsbefore production use. - Restrict security group ingress for ports
8080,6090, and5901. - Consider using IAM roles or OIDC for GitHub Actions instead of long-lived AWS access keys.
Build the RViz2 image directly:
docker build -t rviz2-novnc ./dockerRun the control panel:
cd control-panel
npm startCheck running Docker services:
docker compose psStop local services:
docker compose down