How to Serve a Flask App with Amazon Lightsail Containers

To get started, you'll need an AWS account and must install Docker, the AWS Command Line Interface (CLI) tool and the Lightsail Control (lightsailctl) plugin on your system. Follow the provided links if you don't have some of those.

Create the application

Complete the following steps on your local machine that is running Docker. These steps walk you through the process of creating the Flask application files.

Create a new project directory and switch to that directory.

$ mkdir lightsail-containers-flask && cd lightsail-containers-flask

Create a new file, app.py, and paste the following code into the file. Save the file.

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello_world():
    return "Hello, World!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

This minimal Flask application contains a single function hello_world that is triggered when the route “/” is requested. When run, this application binds to all IPs on the system (“0.0.0.0”) and listens on port 5000 (this is the default Flask port).

Create a new file, requirements.txt. Edit the file and add the following. Save the file.

flask===1.1.2

requirements.txt files are used to specifying what Python packages are required by the application. For this minimal Flask application there is only one required package, Flask.

Create a new file, Dockerfile. Edit the file and add the following. Save the file.

# Set base image (host OS)
FROM python:3.8-alpine

# By default, listen on port 5000
EXPOSE 5000/tcp

# Set the working directory in the container
WORKDIR /app

# Copy the dependencies file to the working directory
COPY requirements.txt .

# Install any dependencies
RUN pip install -r requirements.txt

# Copy the content of the local src directory to the working directory
COPY app.py .

# Specify the command to run on container start
CMD ["python", "./app.py"]

The Python alpine image ensures the resulting container is as compact and small as possible. The command to run when the container starts is the same as if run from the command line: python app.py

Your project directory should contain the following files:

$ tree
.
├── app.py
├── Dockerfile
└── requirements.txt

0 directories, 3 files

Build the container

Complete the following steps to build and test the container image locally.

Build the container using Docker. Execute the following command from the same directory as the Dockerfile:

$ docker build -t flask-container .

This command builds a container using the Dockerfile in the current directory and tags the container “flask-container”.

Once the container build is done, test the Flask application locally by running the container:

$ docker run -p 5000:5000 flask-container

The Flask app will run in the container and will be exposed to your local system on port 5000. Browse to http://localhost:5000 or use “curl” from the command line and you will see “Hello, World!”.

$ curl localhost:5000

Hello, World!

Create a container service

Complete the following steps to create the Lightsail container service using the AWS CLI, and then push your local container image to your new container service using the Lightsail control (lightsailctl) plugin.

  1. Create a Lightsail container service with the create-container-service command.
$ aws lightsail create-container-service --service-name flask-service \
--power small \
--scale 1

The power and scale parameters specify the capacity of the container service. For a minimal flask app, little capacity is required.

The output of the create-container-service command indicates the state of the new service is “PENDING”.

{
    "containerService": {
        "containerServiceName": "flask-service",
        ...
        "state": "PENDING",

Use the get-container-services command to monitor the state of the container as it is being created.

$ aws lightsail get-container-services --service-name flask-service

Wait until the container service state changes to “ACTIVE” before continuing to the next step. Your container service should become active after a few minutes.

Push the application container to Lightsail with the push-container-image comand.

$ aws lightsail push-container-image --service-name flask-service \
--label flask-container\
--image flask-container

...

Refer to this image as ":flask-service.flask-container.X" in deployments.

Note: the X in :flask-service.flask-container.X will be a numeric value. If this is the first time you’ve pushed an image to your container service, this number will be 1. You will need this number in the next step.

Deploy the container

Complete the following steps to create deployment and public endpoint configuration JSON files, and then deploy your container image to your container service.

Create a new file, containers.json. Edit the file and add the following. Replace the X in :flask-service.flask-container.X with the numeric value from the previous step. Save the file.

{
    "flask": {
        "image": ":flask-service.flask-container.X",
        "ports": {
            "5000": "HTTP"
        }
    }
}

The containers.json file describes the settings of the containers that will be launched on the container service. In this instance, the containers.json file describes the flask container, the image it will use and the port it will expose.

Create a new file, public-endpoint.json. Edit the file and add the following. Save the file.

{
    "containerName": "flask",
    "containerPort": 5000
}

The public-endpoint.json file describes the settings of the public endpoint for the container service. In this instance, the public-endpoint.json file indicates the flask container will expose port 5000. Public endpoint settings are only required for services that require public access.

After creating containers.json and public-endpoint.json files, your project directory should look like this:

$ tree
.
├── app.py
├── containers.json
├── Dockerfile
├── public-endpoint.json
└── requirements.txt

0 directories, 5 files

Deploy the container to the container service with the AWS CLI using the create-container-service-deployment command.

$ aws lightsail create-container-service-deployment --service-name flask-service \
--containers file://containers.json \
--public-endpoint file://public-endpoint.json

The output of the create-container-servicedeployment command indicates that the state of the container service is now “DEPLOYING”.

{
    "containerServices": [{
        "containerServiceName": "flask-service",
        ...
        "state": "DEPLOYING",

Use the get-container-services command to monitor the state of the container until it changes to RUNNING before continuing to the next step.

$ aws lightsail get-container-services --service-name flask-service

The get-container-service command also returns the endpoint URL for container service.

{
    "containerServices": [{
        "containerServiceName": "flask-service",
        ...
        "state": "RUNNING",
        ...
        "url": "https://flask-service...

After the container service state changes to RUNNING, navigate to this URL in your browser to verify your container service is running properly. Your browser output should show “Hello, World!” as before.

Congratulations. You have successfully deployed a containerized Flask application using Amazon Lightsail containers.

Cleanup

Complete the following steps to the Lightsail container service that you created as part of this tutorial.

To cleanup and delete Lightsail resources, use the delete-container-service command.

$ aws lightsail delete-container-service --service-name flask-service

The delete-container-service removes the container service, any associated container deployments, and container images.

Additional Resources

The source code for this guide and this documentation is located in this GitHub repository


You Might Also Enjoy:
ALB API-Gateway AWS-Modern-App-Series AWS-Summit Alexa Analytics Andy-Jassy App-Mesh AppMesh AppSync Architecture Architrecture Athena Aurora AutoScale Backup Big-Data Blockchain CNCF Chaos Cloud-Computing Cognito Complexity Comprehend Compute Computing Config Containers Customer-Support DFS Data-Exchange Data-Lake DataSync Databases Deep-Learning DevOps Disaster-Recovery Distributed Diversity Docker DocumentDB DotNet Doug-Yeum DynamoDB EC2 ECS EFS EKS ELB EMR EUC ElastiCache Elastic-Beanstalk Elastic-Container-Service Elastic-File-System Elastic-Map-Reduce Elastic-Search Enterprise Envoy FSx FTP FTPS Fargate FedRAMP Flask Forecast GSaaS Graph GraphQL Graviton GroundTruth GuardDuty HIPAA Helm How-to Icons Infrastructure IoT K8s KMS Key-Management-Service Keynote Kinesis-Data-Streams KubeCon Kubernetes Lake-Formation Lambda Ledger-Database Lightsail Lustre MFA ML Machine-Learning Macie Marketing MemoryDB Message-Bus Messaging Microservices Migration MongoDB NATs NFS NLP Neptune Networking Nginx Nitro NoSQL OCR ObjectStorage OpenEnclave OpenTelemetry Outposts PCI POSIX PeriodicTable Personalize Peter-DeSantis Pinpoint PrivateLink PubSub Public-Sector Purpose-Built QLDB Queues QuickSight RDS Recommendations Redis Rekognition Relational-Database-Service Repository S3 SFTP SMB SNS SQS SaaS SageMaker Security Serverless Shield Simple-Notification-Service Simple-Queue-Service SnowBall SnowCone SnowMobile SpeechToText Startups Step-Functions Storage Storage-Gateway Streaming Swami-Sivasubramanian Teresa-Carlson Textract Time-Series Timestream Transcribe Transit-Gateway VPC VPS WAF Web-Application-Firewall Well-Architected-Framework Werner-Vogels Windows WorkLink YAML reInvent