diff --git a/server/docker/metrics/prometheus.yml b/server/docker/metrics/prometheus.yml index 1aeeea227..c53fb620a 100644 --- a/server/docker/metrics/prometheus.yml +++ b/server/docker/metrics/prometheus.yml @@ -8,7 +8,7 @@ scrape_configs: - job_name: 'simulator-publisher' static_configs: - - targets: ['host.docker.internal:9998'] + - targets: ['simulator-publisher:9998'] metrics_path: '/metrics' scheme: 'http' relabel_configs: @@ -18,7 +18,7 @@ scrape_configs: - job_name: 'simulator-consumer' static_configs: - - targets: ['host.docker.internal:9997'] + - targets: ['simulator-consumer:9997'] metrics_path: '/metrics' scheme: 'http' relabel_configs: diff --git a/server/docs/configuration.md b/server/docs/configuration.md index 69f880d59..c01d219ba 100644 --- a/server/docs/configuration.md +++ b/server/docs/configuration.md @@ -21,4 +21,4 @@ defaults and can be left unchanged. It is recommended to browse the properties b | MEDIATOR_RING_BUFFER_SIZE | Size of the ring buffer used by the mediator (must be a power of 2) | 67108864 | | NOTIFIER_RING_BUFFER_SIZE | Size of the ring buffer used by the notifier (must be a power of 2) | 2048 | | SERVER_PORT | The port the server will listen on | 8080 | -| SERVER_MAX_MESSAGE_SIZE_BYTES | The maximum size of a message frame in bytes | 1048576 | +| SERVER_MAX_MESSAGE_SIZE_BYTES | The maximum size of a message frame in bytes | 1048576 | \ No newline at end of file diff --git a/simulator/build.gradle.kts b/simulator/build.gradle.kts index 040b539b4..a0e5e14bb 100644 --- a/simulator/build.gradle.kts +++ b/simulator/build.gradle.kts @@ -93,3 +93,61 @@ tasks.register("untarTestBlockStream") { tasks.named("processResources") { dependsOn(tasks.named("untarTestBlockStream")) } tasks.named("sourcesJar") { dependsOn(tasks.named("untarTestBlockStream")) } + +// Vals +val dockerProjectRootDirectory: Directory = layout.projectDirectory.dir("docker") +var resourcesProjectRootDirectory: Directory = layout.projectDirectory.dir("src/main/resources") +var distributionBuildRootDirectory: Directory = layout.buildDirectory.dir("distributions").get() +val dockerBuildRootDirectory: Directory = layout.buildDirectory.dir("docker").get() + +// Docker related tasks +val copyDockerFolder: TaskProvider = + tasks.register("copyDockerFolder") { + description = "Copies the docker folder to the build root directory" + group = "docker" + + from(dockerProjectRootDirectory) + into(dockerBuildRootDirectory) + } + +// Docker related tasks +val copyDependenciesFolders: TaskProvider = + tasks.register("copyDependenciesFolders") { + description = "Copies the docker folder to the build root directory" + group = "docker" + + dependsOn(copyDockerFolder, tasks.assemble) + from(resourcesProjectRootDirectory) + from(distributionBuildRootDirectory) + into(dockerBuildRootDirectory) + } + +val createDockerImage: TaskProvider = + tasks.register("createDockerImage") { + description = "Creates the docker image of the Block Stream Simulator" + group = "docker" + + dependsOn(copyDependenciesFolders, tasks.assemble) + workingDir(dockerBuildRootDirectory) + commandLine("sh", "-c", "docker buildx build -t hedera-block-simulator:latest .") + } + +val startDockerContainer: TaskProvider = + tasks.register("startDockerContainer") { + description = "Creates and starts the docker image of the Block Stream Simulator" + group = "docker" + + dependsOn(createDockerImage, tasks.assemble) + workingDir(dockerBuildRootDirectory) + + commandLine("sh", "-c", "./update-env.sh && docker compose -p simulator up -d") + } + +tasks.register("stopDockerContainer") { + description = "Stops running docker containers of the Block Stream Simulator" + group = "docker" + + dependsOn(copyDockerFolder) + workingDir(dockerBuildRootDirectory) + commandLine("sh", "-c", "docker compose -p simulator stop") +} diff --git a/simulator/docker/Dockerfile b/simulator/docker/Dockerfile new file mode 100644 index 000000000..777b6d328 --- /dev/null +++ b/simulator/docker/Dockerfile @@ -0,0 +1,37 @@ +FROM eclipse-temurin:21 + +# Create a non-root user and group +ARG UNAME=hedera +ARG UID=2000 +ARG GID=2000 +RUN groupadd -g $GID -o $UNAME +RUN useradd -m -u $UID -g $GID -o -s /bin/bash $UNAME + +WORKDIR /app + +# Copy the distribution and resources +COPY simulator-*.tar ./simulator.tar +COPY logging.properties . + +# Create resources directory and copy block data +RUN mkdir -p src/main/resources +COPY block-0.0.3.tar.gz src/main/resources/ + +# Extract the distribution and block data +RUN tar -xf simulator.tar && \ + rm simulator.tar && \ + cd src/main/resources && \ + tar -xzf block-0.0.3.tar.gz && \ + rm block-0.0.3.tar.gz && \ + cd /app && \ + chown -R $UNAME:$UNAME /app + +# Switch to non-root user +USER $UNAME + +# Run the simulator using the extracted directory name +RUN SIMULATOR_DIR=$(ls -d simulator-*/) && \ + echo "#!/bin/bash\n/app/${SIMULATOR_DIR}bin/simulator" > /app/start.sh && \ + chmod +x /app/start.sh + +ENTRYPOINT ["/app/start.sh"] diff --git a/simulator/docker/docker-compose.yml b/simulator/docker/docker-compose.yml new file mode 100644 index 000000000..5663bab05 --- /dev/null +++ b/simulator/docker/docker-compose.yml @@ -0,0 +1,41 @@ +services: + simulator-publisher: + container_name: simulator-publisher + build: + context: . + dockerfile: Dockerfile + image: hedera-block-simulator:latest + networks: + - block-node_default + env_file: + - .env + environment: + - BLOCK_STREAM_SIMULATOR_MODE=${PUBLISHER_BLOCK_STREAM_SIMULATOR_MODE} + - PROMETHEUS_ENDPOINT_PORT_NUMBER=${PUBLISHER_PROMETHEUS_ENDPOINT_PORT_NUMBER} + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9998/metrics"] + interval: 3s + timeout: 10s + retries: 5 + + simulator-consumer: + container_name: simulator-consumer + build: + context: . + dockerfile: Dockerfile + image: hedera-block-simulator:latest + networks: + - block-node_default + env_file: + - .env + environment: + - BLOCK_STREAM_SIMULATOR_MODE=${CONSUMER_BLOCK_STREAM_SIMULATOR_MODE} + - PROMETHEUS_ENDPOINT_PORT_NUMBER=${CONSUMER_PROMETHEUS_ENDPOINT_PORT_NUMBER} + depends_on: + simulator-publisher: + condition: service_healthy + +networks: + block-node_default: + name: block-node_default + external: true diff --git a/simulator/docker/update-env.sh b/simulator/docker/update-env.sh new file mode 100755 index 000000000..08e79dfd9 --- /dev/null +++ b/simulator/docker/update-env.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# This script creates a '.env' file that is used for docker-compose as input for environment variables +# for the simulator services. + +echo "Creating .env file for simulator services..." + +# Generate .env file with default values +cat > .env << EOL +GRPC_SERVER_ADDRESS=block-node-server +PROMETHEUS_ENDPOINT_ENABLED=true + +# For publisher service +PUBLISHER_BLOCK_STREAM_SIMULATOR_MODE=PUBLISHER +PUBLISHER_PROMETHEUS_ENDPOINT_PORT_NUMBER=9998 + +# For consumer service +CONSUMER_BLOCK_STREAM_SIMULATOR_MODE=CONSUMER +CONSUMER_PROMETHEUS_ENDPOINT_PORT_NUMBER=9997 +EOL + +# Output the values +echo ".env properties:" +cat .env +echo diff --git a/simulator/docs/configuration.md b/simulator/docs/configuration.md index 939ea5213..33f16ee05 100644 --- a/simulator/docs/configuration.md +++ b/simulator/docs/configuration.md @@ -38,3 +38,12 @@ Uses the prefix `grpc` so all properties should start with `grpc.` |:---|:---|---:| | `serverAddress` | The host of the Block-Node | `localhost` | | `port` | The port of the Block-Node | `8080` | + +## PrometheusConfig + +Uses the prefix `prometheus` so all properties should start with `prometheus.` + +| Key | Description | Default Value | +|:---|:---|--------------:| +| `endpointEnabled` | Whether Prometheus endpoint is enabled | `false` | +| `endpointPortNumber` | Port number for Prometheus endpoint | `9998` | \ No newline at end of file diff --git a/simulator/docs/quickstart.md b/simulator/docs/quickstart.md index b0202b012..fa5a8a17b 100644 --- a/simulator/docs/quickstart.md +++ b/simulator/docs/quickstart.md @@ -66,39 +66,13 @@ get started with the application. The simulator can run in two modes (Publisher and Consumer) and provides metrics for both configurations. To view the metrics: -1. Start the block node server first: +1. Start the block node server and simulator first: ```bash ./gradlew startDockerContainer ``` -2. Configure and run the simulator in Publisher mode: - - - In `app.properties`, set: - ```properties - blockStream.simulatorMode=PUBLISHER - prometheus.endpointEnabled=true - prometheus.endpointPortNumber=9998 - ``` - - Start the simulator: - ```bash - ./gradlew :simulator:run - ``` - -3. Configure and run the simulator in Consumer mode: - - - In `app.properties`, update: - ```properties - blockStream.simulatorMode=CONSUMER - prometheus.endpointEnabled=true - prometheus.endpointPortNumber=9997 - ``` - - Start another instance of the simulator: - ```bash - ./gradlew :simulator:run - ``` - -4. Access the metrics: +2. Access the metrics: - Open Grafana at http://localhost:3000 - Navigate to Dashboards - You'll find two dashboards: