python

Integrate AppSignal with AWS Fargate in Python Flask

Camilo Reyes

Camilo Reyes on

Integrate AppSignal with AWS Fargate in Python Flask

In this tutorial, we’ll show you how to integrate AppSignal with a Flask application running on AWS Fargate.

Fargate is a serverless container service that allows you to run Docker containers in the cloud. By integrating AppSignal with AWS Fargate, you can monitor the performance of your Flask application and get insights.

Set Up

The Flask application we'll use in this tutorial is a simple weather API that returns random weather data. We’ll build the cloud infrastructure using the AWS Cloud Development Kit (CDK) and deploy the Flask application to AWS Fargate. The app will run from a Docker image hosted on Amazon Elastic Container Registry (ECR).

Once the CDK stack is deployed, we’ll monitor the Flask application using AppSignal. The Open Telemetry instrumentation will have a custom span we can use to track the performance of the randomly generated weather data.

You can follow along with the code presented here or by cloning the GitHub repository.

PIP packages

The weather API will have the following dependencies:

  • appsignal: The AppSignal Python agent.
  • opentelemetry-instrumentation-flask: The OpenTelemetry instrumentation for Flask.
  • Flask: The Flask web framework.

These requirements can be installed via the requirements.txt file inside the docker image. To keep it simple, we will use the python:3.12-slim image as the base image for the Flask application. The docker container can run on any computer that has Docker installed, and it can be deployed to AWS Fargate.

But first, spin up the CDK project using the Python template. The infrastructure code will be the one to build the docker image inside an app folder.

AWS CDK

Be sure to have the AWS CDK installed on your computer. We will assume you have Python 3.6 or later installed.

Create a new project folder and initialize the CDK project using the Python template:

Shell
mkdir flask-fargate-api cd flask-fargate-api cdk init app --language python ./venv/Scripts/activate pip install -r requirements.txt cdk bootstrap cdk synth

The activate script will activate the virtual environment for your project. The cdk synth command will verify the CDK project is working correctly.

Open the app.py file in the flask-fargate-api folder and make sure your account details are correct.

Python
FlaskFargateApiStack( app, "flask-fargate-api-stack", env=cdk.Environment(account='1234567890', region='us-east-1') )

The stack ID flask-fargate-api-stack will be the name of the stack used by CloudFormation. You can change the name to something else if you like. But do not change the stack ID once the stack has been deployed because it will bomb.

Open the flask-fargate-api-stack.py file and add the following code to create the VPC, ECS cluster, and Fargate service:

Python
from aws_cdk import ( Stack, aws_ec2 as ec2, aws_ecs as ecs, aws_ecs_patterns as ecs_patterns, aws_logs as logs ) from constructs import Construct class FlaskFargateApiStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) vpc = ec2.Vpc( self, "vpc" ) cluster = ecs.Cluster( self, "cluster", vpc=vpc ) service = ecs_patterns.ApplicationLoadBalancedFargateService( self, "api", cluster=cluster, cpu=256, memory_limit_mib=512, desired_count=1, public_load_balancer=True, task_image_options={ "environment": { "ADDRESS": "0.0.0.0", "PORT": "80" }, "image": ecs.ContainerImage.from_asset( directory="app" ), "container_port": 80, "log_driver": ecs.AwsLogDriver( stream_prefix="api", log_retention=logs.RetentionDays.ONE_DAY ) } ) service.target_group.configure_health_check( path="/health" )

The task image has environment variables for the address and port. This will allow the loopback address to be used inside the container. The public_load_balancer will give us a public URL to access the Flask application.

The VPC allows the CDK to grant network access to the Fargate service. This allows access to the ECR repository and the ECS cluster. The app itself doesn’t exist yet, but the CDK will build the Docker image and push it to ECR. The health check is used to monitor the health of the Fargate service during deployment.

We are not able to deploy the stack yet, because it needs the Docker image to be built and pushed to ECR. Let's do that next.

Weather API

Create the missing app folder in the root of the project. Inside the app folder, create a new file called app.py and add the following code:

Python
import appsignal from appsignal import set_category from opentelemetry import trace # open telemetry instrumentation appsignal.start() tracer = trace.get_tracer(__name__) from flask import Flask, jsonify import random import os app = Flask(__name__) weather_data = [ {"city": "New York", "temperature": 77, "condition": "Cloudy"}, {"city": "Los Angeles", "temperature": 70, "condition": "Sunny"}, {"city": "Chicago", "temperature": 73, "condition": "Sunny"}, {"city": "Houston", "temperature": 81, "condition": "Cloudy"}, {"city": "Phoenix", "temperature": 92, "condition": "Sunny"}, ] @app.route('/weather', methods=['GET']) def get_weather(): # start a custom span with tracer.start_as_current_span("random_weather"): set_category("get_weather") return jsonify(random.choice(weather_data)) @app.route('/health', methods=['GET']) def health(): return jsonify({"status": "ok"}) if __name__ == '__main__': port = os.getenv('PORT', 5000) host = os.getenv('ADDRESS', 'localhost') app.run(debug=True, host=host, port=port)

The tracer object creates a custom span called random_weather. This span will track the performance of the random weather data. Keep in mind this could be an API call, a database query, or any other operation that needs to be monitored. The set_category function sets the category of the span to get_weather.

The appsignal.start() function must be called before the Flask application is imported. This will start the AppSignal agent and configure the OpenTelemetry instrumentation for Flask.

To activate this instrumentation, create an __appsignal.py__ file in the app folder and add the following code:

Python
from appsignal import Appsignal appsignal = Appsignal( active=True, name="flask-fargate-api", # Please do not commit this key to your source control management system. # Move this to your app's security credentials or environment variables. # https://docs.appsignal.com/python/configuration/options.html#option-push_api_key push_api_key="your-push-api-key" )

Next, create the requirements.txt file in the app folder and add the following dependencies:

text
appsignal opentelemetry-instrumentation-flask Flask

Create the Dockerfile in the app folder and add the following code:

Dockerfile
FROM python:3.12-slim WORKDIR /app COPY . /app RUN pip install --no-cache-dir -r requirements.txt CMD ["python", "app.py"]

This Dockerfile will create the Docker image for the Flask application to run on AWS Fargate. The command python app.py will run the Flask application when the container is started. You can test the Flask application locally or via the Docker container.

That’s it for the Flask application. The next step is to build the Docker image and push it to ECR via the CDK.

Deploy the CDK Stack

Drum roll, please! Fire up the CDK stack using the following command:

Shell
cdk deploy

If there is an issue with the Docker image, be sure to have Docker installed and running on your computer. Docker must also have access to ECR to push the image.

If it’s having trouble signing in to ECR, run the following command:

Shell
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 1234567890.dkr.ecr.us-east-1.amazonaws.com

Be sure to replace 1234567890 with your AWS account number. This will allow Docker to push the image to ECR.

The deployment should take no more than five minutes. If it is taking longer, kill it in CloudFormation and delete the stack. Troubleshoot the issue and try again. AWS charges for the Fargate service and ECR, so do not leave the stack running if it is not working.

At the end, the CDK will output the public URL for the Flask application. Look for the api URL in the output, which looks like this:

text
Outputs: flask-fargate-api-stack.api = http://api-1234567890.us-east-1.elb.amazonaws.com

Now grab the URL and test the Flask application via CURL or a web browser. The /weather endpoint should return random weather data. The /health endpoint should return a status of ok.

Hit the /weather endpoint a few times to generate some data. Next, we will monitor the Flask application using AppSignal.

AppSignal Monitoring of the Python Flask Application

Once you hit the endpoint enough times, go to the AppSignal dashboard under your account. The application should be listed under flask-fargate-api. The name matches the name configuration in the __appsignal__.py file. Click on the application to view the dashboard.

Under Performance, you should see Actions, Slow Events, and Graphs. Click on Actions and then the GET /health endpoint. Then, you can click on 'Slow Events' to see your custom span random_weather.

The random_weather span should show average duration, throughput, and overall performance impact. This is the custom span we created to monitor the performance of the random weather data.

AppSignal Dashboard

Note the span breakdown, which includes impact, meaning the endpoint spent all its time generating random weather data.

You may also track the performance of each call for the custom span.

AppSignal Custom Span

The breakdown of the span itself is also available. This shows a timeline of the HTTP request and the time spent generating the random weather data.

AppSignal Span Breakdown

And that's that!

Wrapping Up

In this tutorial, we showed you how to integrate AppSignal with a Flask application running on AWS Fargate. We built the cloud infrastructure using the AWS CDK and deployed the application. We then monitored the Flask application using AppSignal and created a custom span to track the performance of the random weather data.

Happy coding!

P.S. If you'd like to read Python posts as soon as they get off the press, subscribe to our Python Wizardry newsletter and never miss a single post!

Camilo Reyes

Camilo Reyes

Our guest author Camilo is a Software Engineer from Houston, Texas. He’s passionate about JavaScript and clean code that runs without drama. When not coding, he loves to cook and work on random home projects.

All articles by Camilo Reyes

Become our next author!

Find out more

AppSignal monitors your apps

AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!

Discover AppSignal
AppSignal monitors your apps