Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add docker configuration for the simulator #416

Merged
merged 8 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ val copyDockerFolder: TaskProvider<Copy> =
into(dockerBuildRootDirectory)
}

// @todo(#343) - createProductionDotEnv is temporary and used by the suites,
// @todo(#343) - createDotEnv is temporary and used by the suites,
// once the suites no longer rely on the .env file from the build root we
// should remove this task
val createProductionDotEnv: TaskProvider<Exec> =
tasks.register<Exec>("createProductionDotEnv") {
val createDotEnv: TaskProvider<Exec> =
georgi-l95 marked this conversation as resolved.
Show resolved Hide resolved
ata-nas marked this conversation as resolved.
Show resolved Hide resolved
tasks.register<Exec>("createDotEnv") {
description = "Creates the default dotenv file for the Block Node Server"
group = "docker"

Expand Down
4 changes: 2 additions & 2 deletions server/docker/metrics/prometheus.yml
jsync-swirlds marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion server/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
68 changes: 68 additions & 0 deletions simulator/build.gradle.kts
ata-nas marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,71 @@ tasks.register<Copy>("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<Copy> =
tasks.register<Copy>("copyDockerFolder") {
description = "Copies the docker folder to the build root directory"
group = "docker"

from(dockerProjectRootDirectory)
into(dockerBuildRootDirectory)
}

// Docker related tasks
val copyDependenciesFolders: TaskProvider<Copy> =
tasks.register<Copy>("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<Exec> =
tasks.register<Exec>("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 createDotEnv: TaskProvider<Exec> =
tasks.register<Exec>("createDotEnv") {
description = "Creates .env file with needed environment variables for the simulator"
group = "docker"

dependsOn(createDockerImage, tasks.assemble)
workingDir(dockerBuildRootDirectory)
commandLine("sh", "-c", "./update-env.sh")
}

val startDockerContainer: TaskProvider<Exec> =
tasks.register<Exec>("startDockerContainer") {
description = "Creates and starts the docker image of the Block Stream Simulator"
group = "docker"

dependsOn(createDotEnv, tasks.assemble)
workingDir(dockerBuildRootDirectory)

commandLine("sh", "-c", "docker compose -p simulator up -d")
ata-nas marked this conversation as resolved.
Show resolved Hide resolved
}
ata-nas marked this conversation as resolved.
Show resolved Hide resolved

tasks.register<Exec>("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")
}
37 changes: 37 additions & 0 deletions simulator/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
41 changes: 41 additions & 0 deletions simulator/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions simulator/docker/update-env.sh
Original file line number Diff line number Diff line change
@@ -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

ata-nas marked this conversation as resolved.
Show resolved Hide resolved
# Output the values
echo ".env properties:"
cat .env
echo
9 changes: 9 additions & 0 deletions simulator/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
30 changes: 2 additions & 28 deletions simulator/docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions suites/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ tasks.register<Test>("runSuites") {
group = "suites"
modularity.inferModulePath = false

// @todo(#343) - :server:createProductionDotEnv should disappear
dependsOn(":server:createDockerImage", ":server:createProductionDotEnv")
// @todo(#343) - :server:createDotEnv should disappear
ata-nas marked this conversation as resolved.
Show resolved Hide resolved
dependsOn(":server:createDockerImage", ":server:createDotEnv")
ata-nas marked this conversation as resolved.
Show resolved Hide resolved

useJUnitPlatform()
testLogging { events("passed", "skipped", "failed") }
Expand Down
Loading