Docker Deploymentο
Deploy FlexStack V2X applications in isolated, reproducible containers using Docker. This guide shows you how to containerize your C-ITS stations and run multiple instances that communicate with each other.
Note
Docker is the easiest way to deploy FlexStack β no system dependencies to manage, consistent environments across machines, and easy scaling.
Why Use Docker?ο
Benefit |
Description |
|---|---|
π¦ Isolation |
Each C-ITS station runs in its own container |
π Reproducibility |
Same environment on development and production |
π Scalability |
Easily spawn multiple stations with Docker Compose |
π Networking |
Built-in virtual networks for V2X communication |
π Easy Deployment |
Single command to start your entire V2X system |
Architectureο
flowchart TB
subgraph "Docker Host"
subgraph "Container 1"
FS1[FlexStack<br/>Station 1]
end
subgraph "Container 2"
FS2[FlexStack<br/>Station 2]
end
subgraph "Container 3"
FS3[FlexStack<br/>Station 3]
end
NET[Docker Network<br/>v2xnet]
end
FS1 <-->|"VAM/CAM"| NET
FS2 <-->|"VAM/CAM"| NET
FS3 <-->|"VAM/CAM"| NET
style NET fill:#e3f2fd,stroke:#1565c0
Quick Startο
Step 1: Create Project Structureο
Create a directory with the following files:
my-v2x-project/
βββ app.py # Your FlexStack application
βββ Dockerfile # Container definition
βββ docker-compose.yml # Multi-container setup
Step 2: Create the Dockerfileο
1FROM python:3.9-slim
2
3WORKDIR /app
4
5# Install system dependencies
6RUN apt-get update && apt-get install -y \
7 gcc \
8 python3-dev \
9 build-essential \
10 && rm -rf /var/lib/apt/lists/*
11
12# Install FlexStack
13RUN pip install --no-cache-dir v2xflexstack
14
15# Copy application
16COPY app.py .
17
18# Run the application
19CMD ["python", "app.py"]
What this does:
Line |
Description |
|---|---|
|
Use lightweight Python 3.9 base image |
|
Install C compiler for native extensions |
|
Install FlexStack package |
|
Run your application on container start |
Step 3: Create the Applicationο
Create app.py β a VRU station that broadcasts VAMs:
1#!/usr/bin/env python3
2"""
3FlexStack Docker Application
4
5A C-ITS VRU station that sends and receives VAMs.
6"""
7
8import argparse
9import logging
10
11from flexstack.facilities.vru_awareness_service.vru_awareness_service import (
12 VRUAwarenessService,
13)
14from flexstack.facilities.vru_awareness_service.vam_transmission_management import (
15 DeviceDataProvider,
16)
17from flexstack.utils.static_location_service import (
18 ThreadStaticLocationService as LocationService,
19)
20from flexstack.btp.router import Router as BTPRouter
21from flexstack.geonet.router import Router as GNRouter
22from flexstack.geonet.mib import MIB
23from flexstack.geonet.gn_address import GNAddress, M, ST, MID
24from flexstack.linklayer.raw_link_layer import RawLinkLayer
25
26
27def parse_mac_address(mac_str: str) -> bytes:
28 """Convert MAC address string to bytes."""
29 parts = mac_str.split(":")
30 return bytes(int(x, 16) for x in parts)
31
32
33def main():
34 # Parse command line arguments
35 parser = argparse.ArgumentParser(description="FlexStack C-ITS Station")
36 parser.add_argument(
37 "--station-id",
38 type=int,
39 default=1,
40 help="Unique station identifier",
41 )
42 parser.add_argument(
43 "--mac-address",
44 type=str,
45 default="aa:bb:cc:11:22:33",
46 help="MAC address (e.g., aa:bb:cc:dd:ee:ff)",
47 )
48 parser.add_argument(
49 "--interface",
50 type=str,
51 default="eth0",
52 help="Network interface to use",
53 )
54 args = parser.parse_args()
55
56 logging.basicConfig(
57 level=logging.INFO,
58 format="[%(levelname)s] Station %(station_id)s: %(message)s",
59 defaults={"station_id": args.station_id},
60 )
61 logger = logging.getLogger(__name__)
62
63 mac_address = parse_mac_address(args.mac_address)
64
65 # GeoNetworking
66 mib = MIB(
67 itsGnLocalGnAddr=GNAddress(
68 m=M.GN_MULTICAST,
69 st=ST.CYCLIST,
70 mid=MID(mac_address),
71 ),
72 )
73 gn_router = GNRouter(mib=mib, sign_service=None)
74
75 # Link Layer
76 link_layer = RawLinkLayer(
77 iface=args.interface,
78 mac_address=mac_address,
79 receive_callback=gn_router.gn_data_indicate,
80 )
81 gn_router.link_layer = link_layer
82
83 # BTP
84 btp_router = BTPRouter(gn_router)
85 gn_router.register_indication_callback(btp_router.btp_data_indication)
86
87 # Location Service
88 location_service = LocationService()
89 location_service.add_callback(gn_router.refresh_ego_position_vector)
90
91 # VRU Awareness Service
92 device_data = DeviceDataProvider(
93 station_id=args.station_id,
94 station_type=2, # Cyclist
95 )
96 vru_service = VRUAwarenessService(
97 btp_router=btp_router,
98 device_data_provider=device_data,
99 )
100 location_service.add_callback(
101 vru_service.vam_transmission_management.location_service_callback
102 )
103
104 logger.info(f"οΏ½οΏ½ Station {args.station_id} started on {args.interface}")
105 logger.info(f"π‘ MAC: {args.mac_address}")
106 logger.info("Broadcasting VAMs...")
107
108 # Keep running
109 location_service.location_service_thread.join()
110
111
112if __name__ == "__main__":
113 main()
Running a Single Containerο
Build and Runο
Build the Docker image:
docker build -t flexstack .
Run a single C-ITS station:
docker run --network host --privileged flexstack
Warning
The --network host and --privileged flags are required for raw socket
access to network interfaces. This allows FlexStack to send/receive Ethernet frames.
With Custom Argumentsο
Override the station ID and MAC address:
docker run --network host --privileged flexstack \
python app.py --station-id 42 --mac-address aa:bb:cc:dd:ee:ff
Running Multiple Stationsο
Use Docker Compose to run multiple C-ITS stations that communicate with each other.
Docker Compose Setupο
Create docker-compose.yml:
1version: '3.8'
2
3services:
4 # First C-ITS Station (Cyclist)
5 station1:
6 build: .
7 container_name: flexstack_station_1
8 command: ["python", "app.py", "--station-id", "1", "--mac-address", "aa:bb:cc:11:22:01"]
9 networks:
10 - v2xnet
11 cap_add:
12 - NET_ADMIN
13 - NET_RAW
14
15 # Second C-ITS Station (Cyclist)
16 station2:
17 build: .
18 container_name: flexstack_station_2
19 command: ["python", "app.py", "--station-id", "2", "--mac-address", "aa:bb:cc:11:22:02"]
20 networks:
21 - v2xnet
22 cap_add:
23 - NET_ADMIN
24 - NET_RAW
25
26 # Third C-ITS Station (Cyclist)
27 station3:
28 build: .
29 container_name: flexstack_station_3
30 command: ["python", "app.py", "--station-id", "3", "--mac-address", "aa:bb:cc:11:22:03"]
31 networks:
32 - v2xnet
33 cap_add:
34 - NET_ADMIN
35 - NET_RAW
36
37networks:
38 v2xnet:
39 driver: bridge
Key Configuration:
Setting |
Purpose |
|---|---|
|
All stations share the same virtual network |
|
Required capabilities for raw socket access |
|
Override default command with station-specific args |
Start All Stationsο
Launch all stations:
docker-compose up
Or run in background:
docker-compose up -d
View logs:
docker-compose logs -f
Stop all stations:
docker-compose down
Communication Flowο
When multiple stations run in Docker Compose, they communicate through the shared network:
sequenceDiagram
participant S1 as Station 1<br/>(Cyclist)
participant NET as Docker Network<br/>(v2xnet)
participant S2 as Station 2<br/>(Cyclist)
participant S3 as Station 3<br/>(Cyclist)
loop Every ~500ms
S1->>NET: Broadcast VAM
NET->>S2: Receive VAM
NET->>S3: Receive VAM
S2->>NET: Broadcast VAM
NET->>S1: Receive VAM
NET->>S3: Receive VAM
S3->>NET: Broadcast VAM
NET->>S1: Receive VAM
NET->>S2: Receive VAM
end
Scaling Stationsο
Easily scale to many stations:
# Run 5 instances of the station service
docker-compose up --scale station1=5
Or define a scalable service in docker-compose.yml:
services:
cyclist:
build: .
networks:
- v2xnet
cap_add:
- NET_ADMIN
- NET_RAW
deploy:
replicas: 10
Advanced Configurationο
Environment Variablesο
Use environment variables for configuration:
services:
station:
build: .
environment:
- STATION_ID=1
- MAC_ADDRESS=aa:bb:cc:11:22:33
- LOG_LEVEL=DEBUG
Then in your app.py:
import os
station_id = int(os.getenv("STATION_ID", "1"))
mac_address = os.getenv("MAC_ADDRESS", "aa:bb:cc:11:22:33")
log_level = os.getenv("LOG_LEVEL", "INFO")
Volume Mountingο
Mount local files for development (changes reflect immediately):
services:
station:
build: .
volumes:
- ./app.py:/app/app.py
networks:
- v2xnet
Health Checksο
Add health checks to monitor station status:
services:
station:
build: .
healthcheck:
test: ["CMD", "python", "-c", "import flexstack"]
interval: 30s
timeout: 10s
retries: 3
Troubleshootingο
Issue |
Solution |
|---|---|
Permission denied |
Add |
Interface not found |
Check interface name with |
Stations not communicating |
Ensure all stations are on the same Docker network |
Build fails |
Check that |
Debug Commandsο
Enter a running container:
docker exec -it flexstack_station_1 /bin/bash
Check network interfaces:
docker exec flexstack_station_1 ip link
View container logs:
docker logs -f flexstack_station_1
Complete Projectο
Hereβs the complete project structure with all files:
my-v2x-project/
βββ app.py # Application code (see Step 3)
βββ Dockerfile # Container definition (see Step 2)
βββ docker-compose.yml # Multi-container setup
Quick commands:
# Build
docker-compose build
# Start all stations
docker-compose up -d
# View logs
docker-compose logs -f
# Stop everything
docker-compose down
See Alsoο
Getting Started β Complete V2X tutorial
VRU Awareness Service β VRU Awareness Service details
Cooperative Awareness (CA) Basic Service β For vehicle CAM stations
Link Layer β Network interface configuration