-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add package development instructions (#437)
- Loading branch information
1 parent
0acdcf3
commit 37a77f5
Showing
4 changed files
with
349 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
# Multi-Config Package Development | ||
|
||
This guide will walk you through the steps to develop a multi-config Dappnode package, allowing you to create multiple package configurations from a single source. We'll use the Lodestar Generic package as a reference, which builds multiple variants for different networks like Mainnet, Holesky, and Gnosis. | ||
|
||
## Step 1: Initialize the Package | ||
|
||
Start by running the following command to initialize your multi-variant Dappnode package: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest init --use-variants | ||
``` | ||
|
||
This will create the following directory structure: | ||
|
||
``` | ||
. | ||
├── avatar-default.png | ||
├── dappnode_package.json | ||
├── docker-compose.yml | ||
├── Dockerfile | ||
└── package_variants | ||
├── mainnet | ||
│ ├── dappnode_package.json | ||
│ └── docker-compose.yml | ||
└── testnet | ||
├── dappnode_package.json | ||
└── docker-compose.yml | ||
``` | ||
|
||
## Step 2: Customize your package | ||
|
||
### Create a directory for each variant | ||
|
||
Each variant of your package will have its own configuration files under `package_variants`. For example, if you have `mainnet` and `testnet` variants, you will find the following: | ||
|
||
``` | ||
package_variants/ | ||
├── mainnet/ | ||
│ ├── dappnode_package.json | ||
│ └── docker-compose.yml | ||
└── testnet/ | ||
├── dappnode_package.json | ||
└── docker-compose.yml | ||
``` | ||
|
||
The contents within each variant directory include the fields that differ from one variant to another. When building a specific variant, such as `testnet`, the data from these variant-specific files is merged with the root-level `dappnode_package.json` and `docker-compose.yml`. This ensures that only the necessary variant-specific changes are applied, while the common configuration remains consistent across all variants. | ||
|
||
You can add more variants as needed by creating additional directories and files following this structure. | ||
|
||
### Customize the Avatar | ||
|
||
Replace the default avatar (`avatar-default.png`) with a square `.png` image that represents your package (recommended dimensions: width between 200px and 300px). This image will appear in the Dappnode UI, so it's important to choose one that aligns with your package's branding. The avatar is common for each of the variants. | ||
|
||
### Key Changes in `docker-compose.yml` and `dappnode_package.json` | ||
|
||
In the root-level `docker-compose.yml` and `dappnode_package.json`, specify the general configuration that applies across all variants. | ||
|
||
Each variant in `package_variants` will have its own `docker-compose.yml` and `dappnode_package.json`, tailored to the network or environment it is intended for. | ||
|
||
For example, `package_variants/mainnet/docker-compose.yml` could define services using `NETWORK=mainnet`, while `package_variants/testnet/docker-compose.yml` would use `NETWORK=testnet`. | ||
|
||
Example of a variant-specific `dappnode_package.json`: | ||
|
||
```json | ||
{ | ||
"name": "test-mainnet.public.dappnode.eth", | ||
"version": "0.1.0", | ||
"type": "service" | ||
} | ||
``` | ||
|
||
And the corresponding `docker-compose.yml`: | ||
|
||
```json | ||
version: "3.5" | ||
services: | ||
test: | ||
build: | ||
args: | ||
NETWORK: mainnet | ||
|
||
``` | ||
|
||
### Simplified Dockerfile | ||
|
||
Here’s an example of the `Dockerfile` used for the Lodestar Generic package. This `Dockerfile` is responsible for configuring the Lodestar Ethereum client and handling multiple variants. | ||
|
||
```Dockerfile | ||
ARG UPSTREAM_VERSION | ||
|
||
FROM chainsafe/lodestar:${UPSTREAM_VERSION} | ||
|
||
ARG NETWORK | ||
ARG STAKER_SCRIPTS_VERSION | ||
|
||
# Additional envs | ||
|
||
ENV STAKER_SCRIPTS_URL=https://github.com/dappnode/staker-package-scripts/releases/download/${STAKER_SCRIPTS_VERSION} | ||
|
||
COPY entrypoint.sh /usr/local/bin/entrypoint.sh | ||
|
||
# These scripts provide useful tools for the entrypoint | ||
ADD ${STAKER_SCRIPTS_URL}/consensus_tools.sh /etc/profile.d/ | ||
RUN chmod +rx /etc/profile.d/consensus_tools.sh | ||
|
||
# Additional commands or package installation | ||
|
||
# This environment variable sets the variant (e.g., mainnet, testnet) | ||
ENV NETWORK=${NETWORK} | ||
|
||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] | ||
``` | ||
|
||
### Simplified entrypoint | ||
|
||
The `entrypoint.sh` script for the Lodestar client manages different network setups (e.g., Holesky, Gnosis, Mainnet) and configures runtime flags accordingly. Here’s a simplified version: | ||
|
||
```bash | ||
#!/bin/sh | ||
|
||
SUPPORTED_NETWORKS="gnosis holesky mainnet" | ||
MEVBOOST_FLAG_KEY="--builder" | ||
CLIENT="lodestar" | ||
|
||
# Load the tools scripts | ||
. /etc/profile | ||
|
||
# Get the necessary environment variables for the beacon node | ||
ENGINE_URL="http://execution.${NETWORK}.staker.dappnode:8551" | ||
VALID_FEE_RECIPIENT=$(get_valid_fee_recipient "${FEE_RECIPIENT}") | ||
MEVBOOST_FLAG=$(get_mevboost_flag "${NETWORK}" "${MEVBOOST_FLAG_KEY}") | ||
|
||
JWT_SECRET=$(get_jwt_secret_by_network "${NETWORK}") | ||
echo "${JWT_SECRET}" >"${JWT_FILE_PATH}" | ||
|
||
# Start the beacon node with the appropriate flags | ||
echo "[INFO - entrypoint] Running beacon node" | ||
|
||
FLAGS="beacon \ | ||
--network=${NETWORK} \ | ||
--suggestedFeeRecipient=${VALID_FEE_RECIPIENT} \ | ||
--jwt-secret=${JWT_FILE_PATH} \ | ||
--execution.urls=${ENGINE_URL} \ | ||
# ... Additional flags here | ||
--logFileDailyRotate=5 $MEVBOOST_FLAG $EXTRA_OPTS" | ||
|
||
# Run the Lodestar client with the specified flags | ||
exec ${CLIENT_BIN} $FLAGS | ||
``` | ||
|
||
### Prometheus and Grafana | ||
|
||
In multi-variant packages, you can use a common Grafana dashboard located at the root level, while each variant can have its own Prometheus targets. These are stored in variant-specific directories like `package_variants/gnosis/prometheus-targets.json`. | ||
|
||
By following this guide, you’ll be able to create multi-variant packages that support different networks or configurations within a single source code base. | ||
|
||
## Step 3: Build the packages | ||
|
||
Once your variants are configured, build any of them using the following command: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest build --variants=<comma-separated-list-of-variants> | ||
``` | ||
|
||
If you want to build all variants at the same time, you can use: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest build --all-variants | ||
``` | ||
|
||
These commands will package your services, making them ready for installation on Dappnode machines. | ||
|
||
## Step 4: Publish the Packages | ||
|
||
Once you have built your variants, you can choose to publish them. While publishing is optional if you only want to use the package locally, it is required if you want your package to be available in the public Dappstore for other users to discover and install. | ||
|
||
The publish command allows you to specify which variants you want to publish, using the same `--variants` flag as the build command. You can publish one or more variants as follows: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest publish --type=<patch/minor/major> --variants=<comma-separated-list-of-variants> --eth-provider=<your ETH RPC> --content-provider=<your IPFS API> --developer-address=<the address to sign> | ||
``` | ||
|
||
If you want to generate all variants publish links at once, you can use the following command: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest publish --type=patch --all-variants --eth-provider=https://your-eth-node --content-provider=https://your-ipfs-api --developer-address=0xYourAddress | ||
``` | ||
|
||
After running the publish command, you will receive a link to sign the transaction to complete the publishing process. | ||
|
||
### Automating Publication with GitHub Actions | ||
|
||
If your package source code is hosted on GitHub, you can automate the publishing process by setting up GitHub Actions. Use the workflows [here](/docs/dev/github-actions.md) to integrate publishing workflows, ensuring your package builds and publishes automatically. | ||
|
||
By following these steps, you'll be able to develop, build, and publish multi-variant packages on Dappnode, making it easier to support multiple configurations from a single codebase. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Package Development | ||
|
||
Welcome to the **Package Development** section! This guide will help you create your own Dappnode packages. In Dappnode, packages are applications that you can download and install on your Dappnode machine, allowing you to enhance its functionality. | ||
|
||
### Types of Package Repositories | ||
|
||
There are two main types of package repositories: | ||
|
||
- **Standard Package Repository**: Used to generate a single package, tailored for a specific configuration. | ||
- **Multi-Configuration (Generic) Package Repository**: Used to generate multiple packages with varying configurations, such as different networks or client setups. For example, a multi-configuration repository could be used to build packages for both **Holesky Nethermind** and **Mainnet Nethermind**, which differ in their configurations. | ||
|
||
### Developing Packages | ||
|
||
- **Single-Configuration Package**: If you want to develop a package with a single configuration, like [Rotki](https://github.com/dappnode/DAppNodePackage-rotki), follow the instructions [here](/docs/dev/package-development/single-configuration.md). | ||
- **Multi-Configuration Package**: For packages with multiple configurations, like [Lodestar](https://github.com/dappnode/DAppNodePackage-lodestar-generic), refer to [this guide](/docs/dev/package-development/multi-configuration.md). | ||
|
||
By following these guides, you'll be able to create and contribute your own packages to the Dappnode ecosystem. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# Single-Variant Package Development | ||
|
||
This guide will walk you through the steps to develop a single-variant Dappnode package using a simple example. We'll start with initializing a basic package and progress to a more complex setup, using the Holesky Geth package as a reference. | ||
|
||
## Step 1: Initialize the Package | ||
|
||
Start by running the following command to initialize your Dappnode package: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest init | ||
``` | ||
|
||
This will create the following directory structure: | ||
|
||
``` | ||
. | ||
├── avatar-default.png | ||
├── dappnode_package.json | ||
├── docker-compose.yml | ||
└── Dockerfile | ||
``` | ||
|
||
## Step 2: Customize your Package | ||
|
||
### Create a Directory for Container Files | ||
|
||
For more complex packages, such as the Holesky Geth package, it is recommended to create a directory (e.g., `geth`) that will contain everything that needs to go inside each Docker container corresponding to a service in the compose file. This includes the `Dockerfile`, an `entrypoint.sh` script, and any security or configuration files. Example: | ||
|
||
``` | ||
geth/ | ||
├── Dockerfile | ||
├── entrypoint.sh | ||
└── security/ | ||
└── jwtsecret.hex | ||
``` | ||
|
||
### Customize the avatar | ||
|
||
Replace the default avatar (`avatar-default.png`) with a square `.png` image that represents your package (recommended dimensions: width between 200px and 300px). This image will appear in the Dappnode UI, so it's important to choose one that aligns with your package's branding. | ||
|
||
### Key Changes in `docker-compose.yml` and `dappnode_package.json` | ||
|
||
In the `docker-compose.yml`, modify the services section to: | ||
|
||
- Reference the newly created directory (`geth` in this example) where the `Dockerfile` and other container files are stored. | ||
- Set up environment variables, ports, and volumes relevant to your service. | ||
|
||
In the `dappnode_package.json`, update fields such as: | ||
|
||
- `name`, `version`, `description`, and `author` to reflect your package. | ||
- Add relevant `categories`, `architectures`, and exposed services (e.g., API endpoints). | ||
|
||
### Simplified Dockerfile | ||
|
||
Here’s a simplified version of the Dockerfile inside the `geth` directory: | ||
|
||
```Dockerfile | ||
ARG UPSTREAM_VERSION | ||
|
||
FROM ethereum/client-go:${UPSTREAM_VERSION} | ||
|
||
COPY /security /security | ||
COPY entrypoint.sh /usr/local/bin/entrypoint.sh | ||
|
||
# Additional commands or package installation | ||
|
||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] | ||
``` | ||
|
||
### Simplified entrypoint.sh | ||
|
||
The `entrypoint.sh` script is responsible for setting up the environment and running the application. Here’s a simplified version: | ||
|
||
```bash | ||
#!/bin/sh | ||
|
||
# Additional logic related to JWT token | ||
|
||
# Start the Geth process (add any flags you consider relevant) | ||
exec geth --authrpc.jwtsecret ${JWT_PATH} ${EXTRA_FLAGS} | ||
``` | ||
|
||
## Step 3: Build the package | ||
|
||
Once all the necessary customizations are made, you can build your package by running the following command while connected to your Dappnode box: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest build | ||
``` | ||
|
||
This will package your service, making it ready for installation on a Dappnode machine. Once you get the package hash, you just have to paste it into the Dappstore search bar to download it. | ||
|
||
## Step 4: Publish the package | ||
|
||
Publishing the package is optional; you can install and use the package locally after building it. However, if you want the package to be available in the public Dappstore for other users to discover and install, publishing is required. To publish the package, start by running the following command: | ||
|
||
```bash | ||
npx @dappnode/dappnodesdk@latest publish --type=<patch/minor/major> --eth-provider=<your ETH RPC> --content-provider=<your IPFS API> --developer-address=<the address to sign> | ||
``` | ||
|
||
This command will return a link where you can perform the transaction to publish the package. | ||
|
||
### Naming conventions for packages | ||
|
||
All package names must follow this convention: | ||
|
||
``` | ||
<name>.<public/dnp>.dappnode.eth | ||
``` | ||
|
||
- DNP: This suffix is reserved for official Dappnode packages and must be approved by the Dappnode Association. | ||
- Public: This suffix is for community-contributed packages that can be published by anyone. | ||
|
||
### Automating Publication with GitHub Actions | ||
|
||
If the package source code is hosted on GitHub, you can automate the publishing process by setting up GitHub Actions. Use the workflows [here](/docs/dev/github-actions.md) to integrate publishing workflows. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters