How to connect two Docker containers running react and python - python

I have docker-compose.yml to bring up two docker containers.
1.) front-end - reactjs - running on port 3000
2.) back-end - python (flask) - running on port 8083
The front-end is calling the python server for a POST method through the url "http://127.0.0.1:8083/api using axios, but now since these are running at two containers, how can I connect the front-end to the python server through that url?
This is my docker-compose.yml
version: "3.2"
services:
frontend:
build: ./frontend
environment:
CHOKIDAR_USEPOLLING: "true"
volumes:
- /app/node_modules
- ./frontend:/app
ports:
- 80:3000
depends_on:
- backend
backend:
build: ./backends/jananath
volumes:
- ./backends/jananath:/usr/src/app
environment:
FLASK_APP: /usr/src/app/server.py
FLASK_DEBUG: 1
FLASK_RUN_EXTRA_FILES: "/usr/src/app/banuka.txt"
ports:
- 5000:8083
And this is the server.py python server
from flask import Flask, render_template, request, url_for, redirect
import os
from os import path, walk
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
PORT = 8083
#app.route('/api', methods=['POST', 'GET'])
def upload_file():
file = request.files['file']
filename = file.filename
print(filename)
filepath = os.path.abspath(filename)
print(filepath)
response_ = {}
response_['filename'] = str(filename)
response_['filepath'] = str(filepath)
return response_
if __name__ == '__main__':
app.run(host='0.0.0.0', port=PORT, extra_files=extra_files)
And this is the axios calling a POST method from front-end to this server.py
const onFormSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("file", file);
try {
const res = await axios.post("http://127.0.0.1:8083/api", formData, { // this url should change now?
headers: {
"Content-Type": "multipart/form-data",
"Access-Control-Allow-Credentials": "true",
"crossorigin": "true",
},
});
const {filename, filepath} = res.data;
setUploadedFile({filename, filepath});
} catch (error) {
console.log(error);
}
};
I think the problem here is the URL is now changed, but I don't know how to fix that. Can someone tell me how to fix this and what is the correct URL I should hit?
Thank you!

try backend:8083 in your react app, you will need to rebuild your react image.

Related

Possible to have multiple languages in a single application with routing?

You can use multiple services in Google App Engine and each service can be in its own language. This is usually done by having different url prefixes, so for example one url is:
myapp.com/js/*
myapp.com/python/*
However, I'm wondering if you can mix-and-match endpoints and just set them up with a dispatch file. Here is what I have so far to give an idea of what I'm trying to do:
default-multi/
app.yaml
dispatch.yaml
js/
js.yaml
package.json
server.js
py/
py.yaml
requirements.txt
main.py
And the files are:
js/js.yaml
runtime: nodejs14
service: js
js/package.json
{
"engines": {
"node": "14.x"
},
"dependencies": {
"express": "^4.17.1"
}
}
js/server.js
'use strict';
const express = require('express');
const app = express();
app.get('/js', (req, res) => {
res.status(200).send('Hello, world!').end();
});
app.listen(8080, () => {});
module.exports = app;
py/requirements.txt
Flask==2.1.3
py/py.yaml
runtime: python39
service: py
py/main.py
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/py')
def hello():
return jsonify(hello='world')
app.yaml
runtime: python39 # requires I add this ?
service: default
dispatch.yaml
dispatch:
- url: "*/py$"
service: py
- url: "*/js$"
service: js
And to dispatch:
$ gcloud app deploy app.yaml js/js.yaml py/py.yaml dispatch.yaml
Is there an actual way to accomplish what I'm trying to do above, or is it just not possible using GAE?
This is possible. Here is a working example I have now:
default_multi/
dispatch.yaml
dispatch:
- url: "*/js"
service: js
- url: "*/py"
service: default # 'py'
js/
js.yaml
runtime: nodejs14
service: js
package.json
{
"engines": {
"node": "14.x"
},
"dependencies": {
"express": "^4.17.1"
}
}
server.js
'use strict';
const express = require('express');
const app = express();
app.get('/js', (req, res) => {
res.status(200).send('Hello, world!').end();
});
app.listen(8080, () => {});
module.exports = app;
py/
py.yaml
# set this as 'default' yaml
runtime: python39
service: default
requirements.txt
Flask==2.1.3
main.py
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/py')
def hello():
return jsonify(hello='world')
And the command to run it:
$ gcloud app deploy py/py.yaml js/js.yaml dispatch.yaml
The main points here are that:
One server needs to be registered as the default service, even if the packages are split and equivalent in priority.
Only the dispatch.yaml goes at the top level. This acts as the service-router now.

how to debug ajax error with python and vue js?

working on a python flask app with a vue js front end. tested it my local mac book but when i try the same thing on a linux development machine, i get a ajax error. here is the set up ( directory structure below).
backend is flask app that i run with python app.py , then in the front end vue js, i have added a route and calling the backend api endpoint. not sure if there is anything different we have to do in RHEL linux.
myApp
server
app.py
requirements.txt
Client
node_modules
public
src
components
...
package.json
installed vue-cli , npm install -g #vue/cli
Vue create myapp
npm run serve
from flask import Flask
from flask_cors import CORS
# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})
app = Flask(__name__)
#app.route('/helo')
def index():
return "Hello from flask app"
if __name__ == "__main__":
app.run()
User.vue
<template>
<div>
<div class="hello">
...
</template>
<script>
import axios from "axios";
export default {
name: "Users",
data() {
return {
message: '',
},
};
},
methods: {
getUsers() {
const path = 'http://localhost:5000/hello';
axios.get(path)
.then((res) => {
this.message = msg;
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
}
},
created() {
this.getUsers();
}
}
</script>

Slow Socket IO response when using Docker

I have a Web App built in Flask where tweets are captured (using Tweepy library) and displayed on the front-end. I used Socket IO to display the tweets live on the front-end.
My code works fine when I run this locally. The tweets appear instantly.
However, when i Dockerized the web app, the front-end doesn't update immediately. It takes some time to show the changes (sometimes I think tweets are lost due to the slowness)
Below are code extracts from my website:
fortsocket.js
$(document).ready(function () {
/************************************/
/*********** My Functions ***********/
/************************************/
function stream_active_setup() {
$("#favicon").attr("href", "/static/icons/fortnite-active.png");
$("#stream-status-ic").attr("src", "/static/icons/stream-active.png");
$("#stream-status-text").text("Live stream active");
}
function stream_inactive_setup() {
$("#favicon").attr("href", "/static/icons/fortnite-inactive.png");
$("#stream-status-ic").attr("src", "/static/icons/stream-inactive.png");
$("#stream-status-text").text("Live stream inactive");
}
/*********************************/
/*********** My Events ***********/
/*********************************/
// Socket connection to server
// Prometheus
//var socket = io.connect('http://104.131.173.145:8083');
// Local
var socket = io.connect(window.location.protocol + '//' + document.domain + ':' + location.port);
// Heroku
//var socket = io.connect('https://fortweet.herokuapp.com/');
// Send a hello to know
// if a stream is already active
socket.on('connect', () => {
socket.emit('hello-stream', 'hello-stream');
});
// Listene for reply from hello
socket.on('hello-reply', function (bool) {
if (bool == true) {
stream_active_setup()
} else {
stream_inactive_setup()
}
});
// Listens for tweets
socket.on('stream-results', function (results) {
// Insert tweets in divs
$('#live-tweet-container').prepend(`
<div class="row justify-content-md-center mt-3">
<div class="col-md-2">
<img width="56px" height="56px" src="${results.profile_pic !== "" ? results.profile_pic : "/static/icons/profile-pic.png"}" class="mx-auto d-block rounded" alt="">
</div>
<div class="col-md-8 my-auto">
<div><b>${results.author}</b></div>
<div>${results.message}</div>
</div>
</div>
`);
});
// Listener for when a stream of tweets starts
socket.on('stream-started', function (bool) {
if (bool == true) {
stream_active_setup()
}
});
// Listener for when a stream of tweets ends
socket.on('stream-ended', function (bool) {
if (bool == true) {
stream_inactive_setup()
}
});
});
init.py
# Create the app
app = create_app()
# JWT Configurations
jwt = JWTManager(app)
# Socket IO
socketio = SocketIO(app, cors_allowed_origins="*")
# CORS
CORS(app)
app.config["CORS_HEADERS"] = "Content-Type"
# Creates default admins and insert in db
create_default_admin()
# Main error handlers
#app.errorhandler(404) # Handling HTTP 404 NOT FOUND
def page_not_found(e):
return Err.ERROR_NOT_FOUND
# Listen for hello emit data
# from client
#socketio.on("hello-stream")
def is_stream_active(hello_stream):
emit("hello-reply", streamer.StreamerInit.is_stream_active(), broadcast=True)
streamer.py
import time
import tweepy
import threading as Coroutine
import app.messages.constants as Const
import app.setup.settings as settings_mod
import app.models.tweet as tweet_mod
import app.services.logger as logger
import app
class FStreamListener(tweepy.StreamListener):
def __init__(self):
self.start_time = time.time()
self.limit = settings_mod.TwitterSettings.get_instance().stream_time
logger.get_logger().debug("Live capture has started")
# Notify client that a live capture will start
app.socketio.emit(
"stream-started", True, broadcast=True,
)
super(FStreamListener, self).__init__()
def on_status(self, status):
if (time.time() - self.start_time) < self.limit:
# Create tweet object
forttweet = tweet_mod.TweetModel(
status.source,
status.user.name,
status.user.profile_background_image_url_https,
status.text,
status.created_at,
status.user.location,
)
# Emit to socket
app.socketio.emit(
"stream-results",
{
"profile_pic": forttweet.profile_pic,
"author": forttweet.author,
"message": forttweet.message,
},
broadcast=True,
)
# Add to database
forttweet.insert()
return True
else:
logger.get_logger().debug("Live capture has ended")
# Notify client that a live capture has ended
app.socketio.emit(
"stream-ended", True, broadcast=True,
)
# Stop the loop of streaming
return False
def on_error(self, status):
logger.get_logger().debug(f"An error occurred while fetching tweets: {status}")
raise Exception(f"An error occurred while fetching tweets: {status}")
class StreamerInit:
# [Private] Twitter configurations
def __twitterInstantiation(self):
# Get settings instance
settings = settings_mod.TwitterSettings.get_instance()
# Auths
auth = tweepy.OAuthHandler(settings.consumer_key, settings.consumer_secret,)
auth.set_access_token(
settings.access_token, settings.access_token_secret,
)
# Get API
api = tweepy.API(auth)
# Live Tweets Streaming
myStreamListener = FStreamListener()
myStream = tweepy.Stream(auth=api.auth, listener=myStreamListener)
myStream.filter(track=settings.filters)
def start(self):
for coro in Coroutine.enumerate():
if coro.name == Const.FLAG_TWEETS_LIVE_CAPTURE:
return False
stream = Coroutine.Thread(target=self.__twitterInstantiation)
stream.setName(Const.FLAG_TWEETS_LIVE_CAPTURE)
stream.start()
return True
#staticmethod
def is_stream_active():
for coro in Coroutine.enumerate():
if coro.name == Const.FLAG_TWEETS_LIVE_CAPTURE:
return True
return False
The streamer.py is called on a button click
Dockerfile
# Using python 3.7 in Alpine
FROM python:3.6.5-stretch
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
RUN apt-get update -y && apt-get upgrade -y && pip install -r requirements.txt
# Run the command
ENTRYPOINT ["uwsgi", "app.ini"]
#ENTRYPOINT ["./entry.sh"]
docker-compose.yml
version: "3.8"
services:
fortweet:
container_name: fortweet
image: mervin16/fortweet:dev
build: ./
env_file:
- secret.env
networks:
plutusnet:
ipv4_address: 172.16.0.10
expose:
- 8083
restart: always
nginx_fortweet:
image: nginx
container_name: nginx_fortweet
ports:
- "8083:80"
networks:
plutusnet:
ipv4_address: 172.16.0.100
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- fortweet
restart: always
networks:
plutusnet:
name: plutus_network
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.0.0/24
gateway: 172.16.0.1
app.ini
[uwsgi]
module = run:app
master = true
processes = 5
# Local & Prometheus
http-socket = 0.0.0.0:8083
http-websockets = true
chmod-socket = 660
vacuum = true
die-on-term = true
For a full, updated code, you can find it here under the branch dev/mervin
Any help is appreciated.
in order to see if ipv6 is responsible i would suggest you shutdown everything
open /etc/sysctl.conf and add the following lines to disable ipv6
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
run sudo sysctl -p so changes can take effect
start nginx and the docker again
if you dont see any difference then you can just change the settings to 0 and rerun sysctl -p and let me know
Unfortunately I can't reproduce the issue without the configuration, so I can't verify my answer.
I was able to find a similar issue on a JP's blog: Performance problems with Flask and Docker
In short, it might be that having both IPv6 and IPv4 configs on the container are causing the issue.
In order to verify the issue:
Run the docker
Go inside the running container and change the hosts file so that it won't map IPv6 to localhost
Run application again inside of container
If the app runs smoothly then you've identified your issue.
The solution would be to tweak the uwsgi parameters.
What the author did in the blog post:
CMD uwsgi -s /tmp/uwsgi.sock -w project:app --chown-socket=www-data:www-data --enable-threads & nginx -g 'daemon off;'

POST request from react native does not reach my flask server

I'm trying to send some data from my frontend (react native) to a flask application running on a remote computer. Something isn't working and I'm not sure where the problem lies.
The flask app is listening on port 5000 on the remote server. I've tried simply sending a post request to the IP address of the server (with the port), but this doesn't work.
On my frontend I have this code:
fetch('http://18.222.109.76:5000/add_New_Entry', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
}).then((response) => /*do something with response*/
));
On my backend I have this code as part of the flask app:
app = Flask(__name__)
app.debug = True
app.config['CORS_HEADERS'] = 'Content-Type'
CORS(app)
#app.route("/")
def hello():
return ""
#app.route('/add_New_Entry', methods=['GET', 'POST'])
#cross_origin(origin='*',headers=['Content- Type','Authorization'])
def add_New_Form():
print('bla')
return ""
if __name__ == '__main__':
app.run(debug=True)
So, I expect that if I run the piece of code from the frontend, the server will print "bla", but it doesn't, and no sign of failure appears on the frontend as well (maybe it's because I failed to catch the exception?)
So I finally figured it out. Apparently it was because I was using a remote Amazon server, and I had to open its ports on the amazon interface.
After I did, this worked flawlessly.

Angular frontend, for Flask api, all inside docker

I have a problem witch Angular and Flask inside Docker.
Angular linking to Flask app inside docker, but when I want to make http requests to API from Angular returns error.
Error image
My Angular service for make requests.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders,Response } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import {User} from './user';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable({providedIn: 'root'})
export class LoginService {
private loginUrl = "http://waiter_flask_1:5000/api/account/login";
constructor(
private http:HttpClient
) { }
loginUSer(): Observable<any> {
return this.http.post(this.loginUrl,{"username":"test","password":"test"},httpOptions).pipe(
map((response:Response)=>response)
);
}
}
My docker-compose.yml
version: '3.3'
services:
flask:
image: flask
ports:
- "5000:5000"
volumes:
- ./run.py:/app/run.py
- ./api:/app/api
links:
- database:waiter_database_1
angular:
image: angular
ports:
- "4200:4200"
volumes:
- ./docker-angular:/usr/src/app
links:
- flask:waiter_flask_1
How can I resolve this problem?
When you make the request from the Angular app, your browser is making the request, not the angular container. Therefore your host machine that you are running your browser from will try to resolve the http://waiter_flask_1:5000 host not the angular container, and since your host cannot resolve the name waiter_flask_1, the request will fail.
What you need to do is replace the url your angular app is using to make the HTTP request with a url that your host is able to resolve e.g:
http://host.ip.address:5000/api/account/login
where host.ip.address is the ip address for the host running the flask container. If, for example, you are running the flask container on the same host that you are accessing your browser, then your url can point to localhost, eg:
http://127.0.0.1:5000/api/account/login

Categories