Running non-web app container on Azure Web Apps for Containers - python

I'm trying to launch a constantly running container in Azure that reads from a queue and processes the messages with some application code. To do so, I want to use Azure Web App for Containers. Although I know this is not the most obvious choice since my container doesn't run a web app, I would like to know if this could be made to be workable.
I mocked the setup of a by a very simple Python script:
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
count = 0
while True:
time.sleep(30)
count += 30
logging.info(f'Busy counting: {count}')
which I make callable in a Docker image with the following content:
FROM python:3.8-slim-buster
COPY main.py /app/main.py
WORKDIR /app
EXPOSE 80
CMD ["python", "./main.py"]
I set this image as the image to use in the Web App Service, after which the container is launched. I get the logging up until 230 seconds, after which the container is stopped with the following log message:
2022-06-16T14:46:34.582Z ERROR - Container testapp_123 for site testapp did not start within expected time limit. Elapsed time = 230.9588354 sec
and:
Container testapp_123 didn't respond to HTTP pings on port: 80, failing site start. See container logs for debugging.
Now this obviously has to do with the fact that I have no web server listening on port 80. Is there any way to circumvent this pinging from even happening or running my app without a web server running, or would this be basically impossible to achieve?

Related

How do we run multiple services of a single FastAPI application from single script/command

I am building APIs for a Microservice application using FastAPI.
I built 2 microservices: ServiceA at localhost:8000 and ServiceB at localhost:8001. They are communicating with each other via RedisStreams. Here is how the directory structure looks like:
Project_Directory/
| - ServiceA
| - run.py : I import `app` from `src` here which imports the initialized variable in `__init__.py`
| - src
| - __init__.py: FastAPI application is created and initialized here. `app = FastAPI()` would be in this file
| - routes.py: All routes in this file
| - models.py: All models in this file
| - consumer.py: This file reads and writes to RedisStream
| - ServiceB
...(similar directory structure)
When I start the application, I start using the following:
uvicorn run:app --port 8000 --reload
uvicorn run:app --port 8001 --reload
I need to start the consumer separately (run consumer.py) to read/write values in each of the services.
Is there a way to integrate this in the FastAPI? I imported consumer into __init__ and tried the following:
invoked a direct method call to the Redis consumer method
consumer.run_consumer_stream()
used the on_event("startup") to call the same consumer method
#app.on_event("startup")
async def startup_event():
consumer.run_consumer_stream()
In both cases my service would take a long time to respond to API request and would fail with connect ETIMEDOUT 127.0.0.1:8000.
I want to integrate the starting of the Redis-Streams consumer to the main code, so that every time I start the service with uvicorn I don't need to run the consumer separately. One command should take care of starting all parts of a service. I am not sure I am looking in the right direction and hence, I'm not getting anything. Can someone help me with this?

Localhost Flask app crashes after 413 error

Okay so I've realized that something weird is happening when I try to upload more than I specified in my config.py which is:
class Config:
#other configurations
MAX_CONTENT_LENGTH = 10 * 1024 * 1024
When I try to upload more than 10 MB, instead of giving me a 413 Error, application just refuses to connect. My error handler:
#errors.app_errorhandler(413)
def error_413(error):
return render_template('errors/413.html'), 413
My run.py:
from flaskblog import create_app
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
I can see on terminal that I've gotten this error:
"POST /foo/bar HTTP/1.1" 413 -
Although my app seems to be running on the terminal, I can't access it whatsoever. It's just dead on the browser:
ERR_CONNECTION_REFUSED
I tried running it on uWSGI, Werkzeug, other browsers, no luck.
Any idea what's happening?
EDIT: I can access after I restart my computer. But I'm still curious why about this happens.
Also I use Cloud SQL with external IP for more information.
I had a similar error when using the MAX_CONTENT_LENGTH configuration.Did you register the blueprint errors if yes,Please try removing app_ from #errors.app_errorhandler.Like below:
#errors.errorhandler(413)
def error_413(error):
return render_template('errors/413.html'), 413
If this didn't work try removing the MAX_CONTENT_LENGTH line or if you are trying to connect from another device, run your app with the following command flask run --host=0.0.0.0 and then access it on the other device using your router's ip address which usually looks like 192.168.xxx.xxx and the port which your app is running on like 192.168.xxx.xxx:<port_of_your_app>.If this doesn't work it might be an issue with your firewall refusing incoming connections in the port that your app is running on in which case you can run the following command on your terminal sudo ufw allow <YOUR_PORT>.
Okay next time I should read documentations more carefully:
Connection Reset Issue When using the local development server, you
may get a connection reset error instead of a 413 response. You will
get the correct status response when running the app with a production
WSGI server.
from Flask - File uploads.

Docker - Can't get user webcam: getUserMedia() no longer works on insecure origins

WHAT WORKS
I created a simple Web Application in Flask that takes care of operating a simple return render_template("index.html") when the root node is accessed by a Web Browser.
# app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def show_index():
return render_template("index.html")
if __name__ == "__main__":
app.run(port=80)
The index.html is a simple page that uses tracking.js in order to get the user webcam and track his/her face in the live video stream.
Opening cmd and typing python app.py results in Running on http://127.0.0.1:80/
Accessing the above mentioned URL results in the correct display of the page, that asks me for permission to use the camera, opens it and correctly tracks my face in the live video feed. So it's all working fine till here.
WHAT DOES NOT WORKS
The problem I'm experiencing arises when I dockerize my application using Docker. docker-machine ip is 192.168.99.100
Opening cmd and typing: docker run -p 4000:80 my_face_track_app results in: Running on http://0.0.0.0:80/
Accessing 192.168.99.100:4000 results in the correct display of index.html but I am not asked anymore for permission on the camera and inspecting the JS console I read the following exception:
getUserMedia() no longer works on insecure origins
Here the full error log:
I know the error is telling me I'm not serving the page in HTTPS.
Has anyone else encountered this problem?
What would be the proper solution to the issue or a possible walkaround?
Any help will be highly appreciated, thank you a lot in advance
WHAT I HAVE TRIED TO DO IN ORDER TO SOLVE THE PROBLEM
Since an HTTPS serving of the page is needed in order for JS to execute the function getUserMedia() I tought about serving my Flask application with an SSL certificate by modifying app.py like this:
# app.py
from flask import Flask, render_template
import OpenSSL
app = Flask(__name__)
#app.route("/")
def show_index():
return render_template("index.html")
if __name__ == "__main__":
app.run(port=80, ssl_context="adhoc")
I then dockerized the app building a new image. Typing:
docker run -p 443:80 facetrackapphttps
Results in
Running on https://127.0.0.1:80
So yeah, here HTTPS is ON: the problem is that the port 80 of the HTTPS Flask App is mapped to the port 443 of the docker-machine ip 192.168.99.100.
Trying to access 192.168.99.100:443 does not work and nothing is shown.
Does anybody have an idea about how to do this?
If your application is bound to 127.0.0.1 inside the container, you're not going to be able to access it from your host. According to the flask docs, flask will bind to 127.0.0.1 by default.
You'll need to modify your service so that it binds to 0.0.0.0 inside the container:
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, ssl_context="adhoc")

How to run other program with the web server running in VPS with SSH connection?

I log on my VPS with SSH method and set up a test web page with web.py
After I run the server with below command, the VPS come into the server state and I can't do other things to the VPS, e.g. open a browser to check if the server works...
Anyone know how can I do other thing with the server running? In the local computer, it seems no problem obviously.
My terminal operation screen shot
my main.py code is as follows:
# filename: main.py
import web
urls = (
'/wx', 'Handle',
)
class Handle(object):
def GET(self):
return "hello, this is a test"
if __name__ == '__main__':
app = web.application(urls, globals())
app.run()
Script is working properly. The app.run() call puts the program in an infinite loop waiting for clients to connect with it.
As #Andersson suggests, you could execute the script, putting it in the background. Or, open another SSH session and use one window for your script & another for whatever else you want to do on your server.
For production systems, you should run web.py under nginx or apache.
See http://webpy.org/cookbook/, scroll down to "Deployments", for guidance on running under Apache and Nginx.

arduino yun uhttpd flask setup

I'm trying to set up python and flask on the arduino yun. I've managed to run python files via the /etc/config/uhttpd configuration file:
...
list interpreter ".py=/usr/bin/python"
...
The default path for the website's root is: /www in which I've placed a soft link (apps) to the sd card. So now I can run python programs: http://[ip arduino]/apps/helloworld.py
And when I make my first helloflask.py program and run that via python helloflask.py I can see the result at: http://[ip arduino]:5000
But now I want to configure the uhttpd mini webserver (which is capable to exchange information via CGI) to use the flask setup. The URI: http://flask.pocoo.org/docs/deploying/cgi/#server-setup shows some instructions... but I just don't get it. I've made a directory ../apps/uno in which I've placed a __init__.py file with the following content:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "He Flask!"
In the apps dir I've put a file: cgi.py with this content:
from wsgiref.handlers import CGIHandler
from uno import app
CGIHandler().run(app)
Now I when I browse: http://[ip arduino]/cgi.py get a server error occured, contact the administrator (I think this is the CGI interface from uhttpd).
I just don't grasp the CGI configuration for Flask/uhttpd
I looked into this too and got a little further, I was able to setup a simple hello world but once I tried to do something non-trivial I ran into a big issue that uhttpd doesn't support URL rewriting/aliasing. This means your flask app can only be served at the URL of its .py file instead of at a root like http:// (arduino IP) /flaskapp/. None of the routes inside the app will be visible and makes the whole thing unusable.
However, instead of trying to force flask into uhttpd I had great success running the built in server that flask provides. Take a look at this guide I wrote up that uses flask to serve data from a Yun: https://learn.adafruit.com/smart-measuring-cup/overview
The thing to do is add a call to app.run when the script is run, for example make your flask app look like:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello Flask!"
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, threaded=True)
Then log in to the Yun and run the script using python. Flask's built in server should start serving the app on http:// (arduino IP) :5000/. Make sure to include the host='0.0.0.0' as it's required to listen on the Yun's external network interface. You probably also want debug=True so there are better error messages (and live reloading of the server when the code changes), and I found threaded=True helps because the default server only handles one connection at a time. The Yun is a relatively slow processor so don't expect to service a lot of concurrent requests, however it's quite capable for providing a simple REST API or web application for a few users.
If you want this server to always run on bootup, edit the /etc/rc.local file to include a call to python and your script.

Categories