A simple distributed application running across multiple Docker containers.
Download Docker Desktop for Mac or Windows. Docker Compose will be automatically installed. On Linux, make sure you have the latest version of Compose.
This solution uses Python, Node.js, .NET, with Redis for messaging and Postgres for storage.
Run in this directory to build and run the app:
docker compose up
The vote
app will be running at http://localhost:5000, and the results
will be at http://localhost:5001.
Alternately, if you want to run it on a Docker Swarm, first make sure you have a swarm. If you don't, run:
docker swarm init
Once you have your swarm, in this directory run:
docker stack deploy --compose-file docker-stack.yml vote
- A front-end web app in Python which lets you vote between two options
- A Redis which collects new votes
- A .NET worker which consumes votes and stores them in…
- A Postgres database backed by a Docker volume
- A Node.js web app which shows the results of the voting in real time
Note: At any point during the below steps, feel free to look at the instrumented-version
branch of this repo here for reference.
Account Setup
- You'll need a New Relic account. The good news is that you can create a free account here (no credit card required).
Python Agent Installation
- Once you've created an account, you can begin installing the agent by first clicking the
Add Data
tab on the left hand navigation pane, as shown below. - Search for the Python agent in the
Search for any technology
search bar and click the Python agent under theApplication monitoring
section as shown below. - Next, give your application a name
- Install the New Relic agent into the voting app Docker container by following the below steps
- Add the
newrelic
Python module as a dependency in the/vote/requirements.txt
file - Copy the
newrelic.ini
file as shown below into the/vote
directory of the project folder. - Add the
NEW_RELIC_CONFIG_FILE
as an environment variable in thedocker-compose.yml
file to point to thenewrelic.ini
file. - Add the
newrelic-admin run-program
commands in front of the existingpython app.py
command for the vote Docker service. - Your
vote
service in yourdocker-compose.yml
file should look like the code here:
- Add the
- Next, connect your infrastructure by running the given Docker command as shown below.
- Run your application with
docker compose up
in the project directory - Finally, test the connection to the Python agent and your infrastructure. You should see results similar to the screenshot below. It is ok for the
On-host logs
connection to fail.
Troubleshooting Python Agent Installation
- If the connection to the Python agent fails in the last step.
- First tear down your Docker containers with
docker compose down
- Try running the following command to forcefully rebuild your images:
docker compose build --no-cache
- Then try running
docker compose up
again to start your containers
- First tear down your Docker containers with
- If the connection to the Infrastructure agent fails in the last step.
.NET Agent Installation
-
You can begin installing the .NET agent by first clicking the Add Data tab on the left hand navigation pane, as shown below.
-
Search for the .NET agent in the Search for any technology search bar and click the .NET agent under the Application monitoring section as shown below.
-
We will be following the steps linked here to install and enable the .NET agent inside our .NET Docker container.
- Replace the code in your
/worker/Dockerfile
file for your .NET worker to be as shown here. - Make sure to replace
YOUR_LICENSE_KEY
andYOUR_APP_NAME
with your New Relic license key and .NET application name respectively inside theENV
command at the bottom of the Dockerfile. If you would like to know where to find your license key, you can follow instructions here.
- Replace the code in your
.NET Worker Custom Instrumentation
- If you have installed the .NET agent inside the .NET worker Dockerfile, we can begin adding custom instrumentation to monitor the .NET worker's transactions.
- Let's first make sure we install the
NewRelic.Agent.Api
package in our project's PackageReference. - Replace your /worker/Worker.csproj file with the code here so we can install the
NewRelic.Agent.Api
package.
- Let's first make sure we install the
- Let's begin with a simple task of tracking the
UpdateVote
transaction inside the/worker/Program.cs
file for the .NET worker.- Place the following line at the top of your
Program.cs
file:using NewRelic.Api.Agent;
as shown here. - Place a
[Transaction]
decorator directly above theUpdateVote
function as shown here. - The above steps will import the
NewRelic.Api.Agent
package into our worker's code and will create a custom transaction that can be tracked in New Relic whenever theUpdateVote
function is called.
- Place the following line at the top of your
- Try interacting with the app so the worker can process some votes and so we can begin seeing data in our New Relic account!
- As of now, we've only added custom instrumentation for tracking the
UpdateVote
transaction. Let's try adding custom instrumentation for tracking our query to the Redis server!- To do this, we'll need to extract our call to the Redis server into its own function rather than being called directly in the
Main
function. - Try poking around in the main function in
/worker/Program.cs
to see if you can find the call being made to Redis. Then, try extracting this call into its own function and decorating it with a[Transaction]
. You should have a final result that looks like this. - Let's restart our application and interact with the vote counter to make some calls to the Redis server. You should begin to see data in your New Relic account as shown below.
- This is really cool as we're now adding custom instrumentation to track a couple of important transactions that are being made in our .NET worker! Feel free to add more custom instrumentation as you'd like, and you can also reference documentation here for doing so.
- To do this, we'll need to extract our call to the Redis server into its own function rather than being called directly in the
NodeJS Agent Installation
- Once you've created an account, you can begin installing the agent by first clicking the
Add Data
tab on the left hand navigation pane, as shown below. - For Instrumentation Method, select
Docker
. - Give your application a name and click Save.
- Look for the
package.json
file in theresult
folder and add"newrelic": "latest"
as part of the dependencies. - In the
server.js
file, add this line to the top:var newrelic = require('newrelic');
- Change Directory in your Terminal to the results directory and run the following command
npm install newrelic --save
- Once install is complete, navigate back to the root directory of the application
- Setting up your ENV variables
- For the Dockerfile in the
result
folder, we will need to add this ENV variableENV NEW_RELIC_NO_CONFIG_FILE=true
- Optionally, you can also add other ENV variables like
ENV NEW_RELIC_DISTRIBUTED_TRACING_ENABLED=true \
andNEW_RELIC_LOG=stdout
. Please refer to here. - Since we do not have a newrelic.js file, we will need to setup the ENV variables for our license key and app name. In the same dockerfile, add
ENV NEW_RELIC_APP_NAME=["Insert results services name"]
andENV NEW_RELIC_LICENSE_KEY=["Insert Ingest License Key"]
. Make sure to use a unique application name that doesn't exist in New Relic One.
- For the Dockerfile in the
- In your terminal, run this following command to build your Docker containers:
docker compose build --no-cache
- Afterwards, we can run the Docker images by executing
docker compose up
- Afterwards, we can run the Docker images by executing
- Continue to the next step in New Relic One to test for a successful connection.
Instructions
-
We will need to send some custom events in order to create a custom dashboard
- In
vote/app.py
add these 2 lines at the top
import newrelic.agent newrelic.agent.initialize('/app/newrelic.ini')
- After line 39, we will add this block of code to customize an event and to send it to New Relic
cats = 0 dogs = 0 params = None if vote == 'a': params = {'cats': 1} if vote == 'b': params = {'dogs': 1} newrelic.agent.record_custom_event('votes', params,application=newrelic.agent.application())
- Run your app and the custom events data should flow into New Relic One
- In
-
In your New Relic One dashboard on the left, click on
Dashboards
, then on the top right, click onCreate a dashboard
-
Select
Create a new dashboard
and on the next page, enter a name before proceeding. -
Click on any panel to
Add a new chart
and in the pop-up on the right, selectAdd a chart
-
Enter the follow query
SELECT count(*) FROM votes FACET appName TIMESERIES SINCE 5 hours ago
and hit theRun
button. You should be able to see a chart of the results being sent from the application. You can also customize how the chart looks, for example, we can change the "Chart Type" -
Changing the "Chart Type" to Stacked Bar will look like this:
Steps
The folder k8s-specifications contains the YAML specifications of the Voting App's services.
Run the following command to create the deployments and services. Note it will create these resources in your current namespace (default
if you haven't changed it.)
kubectl create -f k8s-specifications/
The vote
web app is then available on port 31000 on each host of the cluster, the result
web app is available on port 31001.
To remove them, run:
kubectl delete -f k8s-specifications/
The voting application only accepts one vote per client browser. It does not register additional votes if a vote has already been submitted from a client.
This isn't an example of a properly architected perfectly designed distributed app... it's just a simple example of the various types of pieces and languages you might see (queues, persistent data, etc), and how to deal with them in Docker at a basic level.