Hello World dApp
What's in it for me?
By following this tutorial, you'll be able to get more confident about:
- Preparing a Docker image for your app with the ultimate purpose of deploying it on Golem.
- Converting the VM image to Golem and uploading it to Golem's repository.
- Creating a descriptor reflecting your app using YAML syntax similar to that used by
- Deploying your app to Golem using
This step-by-step tutorial will be easier for you to follow if you previously had a chance to launch the
yagna deamon as a requestor and have any experience building portable web applications on Docker, but you should be able to complete it without any prior experience nevertheless.
To follow this tutorial in full, you need to have Docker installed on your machine. If you don't have it installed, please refer to instructions on Docker's website.
Choice of tools
The example that we're going to show you here uses a very simple Python HTTP server.
On the other hand, if you're more acquainted with any other language or platform that enables you to easily create a simple HTTP server and pack it into a Docker image, go for it.
Just as well - if the setup and construction of such a simple app is obvious to you, feel free to jump to
For the sake of completeness, we're including the steps that prepare our Python environment. Again, you're free to do it your way and skip to:
Create and activate the virtual environment
python3 -m venv ~/.envs/hello-dapps source ~/.envs/hello-dapps/bin/activate pip install -U pip poetry
On Windows, the above needs to be replaced with:
Initialize the project
mkdir -p hello_golem/server_app cd hello_golem/server_app/ poetry init --no-interaction --python="^3.9"
Again, on Windows:
Add the requirements
In our little example here, we'll use
Flask, a very robust and minimal Python back-end framework.
There, we're ready to start coding our app.
Hello world app
If you're lost in any moment, feel free to consult our source of the "Hello World" application available at: https://github.com/golemfactory/dapp-experiments/tree/main/05_hello_world
Similarly, instead of coding along, you may just check out the whole thing from the repository:
Fire up your favourite editor or IDE navigate to the
hello_golem/server_app directory that we have set up above.
If you have configured the app using poetry like we did above, you should already see the
In the directory, add
hello_golem.py and just paste the following few lines which are a slightly modified version of Flask's original, minimal example:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_golem(): return 'Hello from Golem!' app.run(host="0.0.0.0")
The above code achieves the following:
- import the
- define our Flask app
- set up the root route for the app
- launch the Flask server
You may wish to customize the "Hello..." message up there, so as to make your application (and, more importantly, its VM image) unique. Our repository is set up to reject repeated uploads of images with matching signatures so, if you encounter an issue while uploading your application later in this tutorial, just please use the hash that we'll provide you there.
For local testing, we could have gotten away with just
app.run(). That makes the server listen on the local host address (
127.0.0.1) by default. We need it to bind to all addresses so that it can later work correctly in Golem.
Let's test this app locally, before we start preparing it for Golem. Launch the app:
and then point your browser to http://127.0.0.1:5000.
You should see "Hello from Golem!" which proves that our minimal app is working correctly when launched completely stand-alone. Good!
Preparing the Docker image
We need to start with a Docker image since the only currently-supported way of creating a GVMI (Golem Virtual Machine Image) file is by providing a Docker image for conversion.
If you'd like to know more about the GVMI images and about the conversion process, please refer to:
Let's back-up a little and ensure that we're one directory above
To build a docker image, we'll need file called
Dockerfile with the following contents:
FROM python:3.9-slim RUN pip install -U pip poetry RUN mkdir /app COPY server_app/* /app/ WORKDIR /app RUN poetry install --no-root ENTRYPOINT poetry run python hello_golem.py
Let's now go through what happens there.
- Take a stock Python Docker image (the slim version, we won't need anything more here):
- Install the needed tools:
- Copy the app contents to the image:
- Install the app's requirements:
- Finally, set up the Docker's entrypoint:
Testing the Docker image
With the Dockerfile ready, we can test whether the app works inside the container:
Once again, after the image launches, you may connect to http://127.0.0.1:5000/ with your browser, and you should be able to see the "Hello..." message, which confirms that the app has been correctly packaged and is working as it should.
Converting the image to Golem
To be able to use our newly-created image on Golem, we need to convert it to the Golem's custom format and then make the image available to providers. The easiest way to achieve the latter is to upload the image to our image repository.
Convert the image to GVMI
Upload the image to the repository
Once the command completes, you should get a line containing the image hash, e.g.:
image already generated on 102777844: success. hash link 3032b6e97914eb5ee87d71188180d271f04eb9472b6da0d308943b2f
The hash there:
3032b6e97914eb5ee87d71188180d271f04eb9472b6da0d308943b2f is what we're interested in.
If the command fails because the image has already been uploaded, feel free to use the hash above and follow through with the tutorial.
Prepare the Golem dApp descriptor
Now that we have the image ready, uploaded into the Golem repo and its hash in hand, we can prepare the descriptor of the application that we're going to launch on Golem.
For a more complete information about the dApp descriptors, please consult the appropriate section of the "Creating Golem dApps" article. Here, we're just cover the bare minimum.
Here's what it looks like:
payloads: hello: runtime: "vm" params: image_hash: "3032b6e97914eb5ee87d71188180d271f04eb9472b6da0d308943b2f" nodes: hello: payload: "hello" init: - run: args: ["/bin/sh", "-c", "poetry run python hello_golem.py > /dev/null &"] http_proxy: ports: - "5000"
Let's add it as
hello_golem.yaml in the
There are two obligatory elements in it, the
The payload is the definition of what kind of activity you'd like the providers to run on your behalf.
In this case, it's just the reference to the VM image we just uploaded.
payloads: hello: runtime: "vm" params: image_hash: "3032b6e97914eb5ee87d71188180d271f04eb9472b6da0d308943b2f"
The node definition
node entry defines the parameters of the specific instances of services that we want launched on Golem.
nodes: hello: payload: "hello" init: - run: args: ["/bin/sh", "-c", "poetry run python hello_golem.py > /dev/null &"] http_proxy: ports: - "5000"
A couple of important details there.
Firstly, given the fact that Docker's
ENTRYPOINT is not yet supported by the
dapp-runner, our service definition must contain any and all commands that will start our service in the container.
Moreover, as the commands included in the
init must finish before the service can be treated as started, we need to put the service in the background. For this reason, we're launching our service using the shell and adding the ampersand (
&) to the end of the command.
One more caveat is that we need to redirect the output stream of the launched app so that it stays running after we exit the shell.
Lastly, we're adding the
http_proxy element because our service is an HTTP app which we wish to be able to talk to. There's currently no way for the service to be exposed directly on the provider's own address but we can use the local HTTP proxy functionality to expose a port on our own machine that will forward traffic to the app through the Golem Network.
The config file
There's one more piece of data that we'll need to run our application. It's the configuration of our Golem requestor that we need to supply for the
Unless you want to customize your set-up, it'll be easiest to just use the default that comes with the
dapp-runner, which you can get with:
curl https://raw.githubusercontent.com/golemfactory/dapp-runner/main/configs/default.yaml > golem_config.yaml
Running your app
Ensure your yagna daemon is started
First, let's make sure that you have your yagna daemon up and running and if not, execute this in another console session:
If you haven't set-up your yagna daemon before, please refer to our quick start guide.
Obtain the application key
and copy the value listed in the
If the above command doesn't give you any keys, just create your app key:
shell yagna app-key create requestor
and copy the value output by this command.
Export your application key to the environment
Run the app
Now you're ready to start the app on Golem.
Once the app launches, you should see some status messages describing various stages of the deployment. And finally, you should see:
The port may be different on your machine, since it's assigned automatically. Copy the address that you got there and paste that into your browser.
Assuming everything went well, you've just managed to create and deploy your own decentralized application on Golem.