Python3 Flask: Interacts with Docker Containers
Final Friday, I used to be speaking with my co-worker at my work. Nearly work, you already know. He informed me he needed to implement a server for serving his options. Though I did not perceive what he was going to do precisely, it sounded actually fascinating and I needed to attempt. Since I acquired numerous work that make many pages, I had written a bunch of HTML issues with React. It wasn’t technically fascinating in the intervening time(I really like React however the work was nearly the identical in any respect). I acquired bored with that. Whereas I used to be in there, the coworker mentioned me what he was doing.
He needed to do
- Make an API server that will get a picture file
- Execute a docker container and go the picture file to the container and the container will create the textual content file that’s generated from the picture file
- Execute one other docker container and go the textual content
- The API Server is aware of that the container has performed with its work and notify to a different server(The backend that servers the information to customers).
It sounds fascinating, ha?, I made a decision to implement the system on the weekend. I assumed it was going to be enjoyable. However it’s been actually a very long time since I coded with python. So, I needed to be taught numerous stuff. Throughout the weekends, I could not be taught all of the issues, so, I might use the minimal abilities for implementing the system. In case you’re a python developer or working with the docker, it is perhaps not in your thoughts at some factors.
Anyhow, Let’s get began!
Prerequisite
Pipenv is a software that goals to convey one of the best of all packaging worlds (bundler, composer, npm, cargo, yarn, and so on.) to the Python world. Home windows is a first-class citizen, in our world.
After I first use python, it was about 5 years in the past, I used conda or venv for managing packages. Whereas I used to be looking for package deal administration, I discovered this. It looks as ifnpm
, I am undecided that is one of the best answer, however in my view, it have to be price it to attempt.
Docker is a platform designed to assist builders construct, share, and run trendy purposes. We deal with the tedious setup, so you’ll be able to deal with the code.
As I launched at first, that is the primary subject on this submit
Flask is an online software framework written in Python. It was developed by Armin Ronacher, who led a group of worldwide Python fans referred to as Poocco.
To implement a easy API internet server, I usedFlask
. there have been different libraries like Quick API. For lowering my hours, I went with Flask.
That is the method that I’ll implement.
-
The API server receives a file from the consumer
-
Container A processes A file then saves it to the B File
-
Container B processes the B File then saves it to the C File
-
Customers can see the consequence by way of API
Python Apps and Docker Photos
I made two photos and uploaded to my them repository in docker-hub.
A tokenizer and word-counting app.
[Tokenizer]
import sys, json, os, requests
from textblob import TextBlob
def extract_nouns(textual content):
blob = TextBlob(textual content)
filtered_tags = checklist(filter(lambda tag: tag[1] == "NN", blob.tags))
nouns = checklist(map(lambda tag: tag[0], filtered_tags))
return nouns
def read_file(path):
with open(path) as f:
contents = f.learn()
return contents
def save_data(path, information):
with open(path, "w") as f:
json.dump(information, f)
def get_filename_from_path(path):
return os.path.splitext(os.path.basename(path))[0]
def notify_done(url, file_name):
requests.get(f"{url}/docker/tokenizer_done?file_name={file_name}")
if __name__ == "__main__":
if len(sys.argv) < 4:
print("You have to go file path as an argument")
print("python3 major.py [file path to read] [dir to save] [notification api]")
print("Instance) python3 major.py ./take a look at.txt ./ http://host.docker.inner:20000")
sys.exit()
api_url = sys.argv[3]
file_path = sys.argv[1]
file_name = get_filename_from_path(file_path)
target_path = os.path.be part of(sys.argv[2], file_name + ".json")
textual content = read_file(file_path)
nouns = extract_nouns(textual content)
save_data(target_path, {"nouns": nouns})
notify_done(api_url, file_name)
print("Executed")
[word-counting]
import sys, json, os, requests
def count_word(nouns_list):
count_dict = dict()
for noun in nouns_list:
if noun in count_dict:
count_dict[noun] += 1
else:
count_dict[noun] = 1
return count_dict
def load_data(path):
with open(path) as f:
json_data = json.load(f)
return json_data
def save_data(path, information):
with open(path, "w") as f:
json.dump(information, f)
def get_filename_from_path(path):
return os.path.splitext(os.path.basename(path))[0]
def notify_done(url, file_name):
requests.get(f"{url}/docker/word_count_done?file_name={file_name}")
if __name__ == "__main__":
if len(sys.argv) < 4:
print("You have to go file path as an argument")
print("python3 major.py [file path to read] [dir to save] [notification api]")
print("Instance) python3 major.py ./take a look at.txt ./ http://host.docker.inner:20000")
sys.exit()
api_url = sys.argv[3]
file_path = sys.argv[1]
file_name = get_filename_from_path(file_path)
target_path = os.path.be part of(sys.argv[2], file_name + ".json")
json_data = load_data(file_path)
count_dict = count_word(json_data["nouns"])
save_data(target_path, {"consequence": count_dict})
notify_done(api_url, file_name)
print("Executed")
For operating the apps from the API server, I constructed each python recordsdata with beneath Dockerfiles.
[Tokenizer]
FROM python:3.9
WORKDIR /app
COPY . .
RUN pip set up pipenv
RUN pipenv set up
RUN pipenv run python3 -m textblob.download_corpora
ENTRYPOINT ["pipenv", "run", "python3", "./main.py"]
[word-counting]
FROM python:3.9
WORKDIR /app
COPY . .
RUN pip set up pipenv
RUN pipenv set up
ENTRYPOINT ["pipenv", "run", "python3", "./main.py"]
API Server
That is the primary code and it is type of easy.
from flask import Flask
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
import routes
Routes
[routes/docker.py]
import os
from flask import jsonify, request
from server import app
from lib import docker, json
consequence = []
@app.route('/docker/tokenizer_done')
def get_tokenizer_done():
file_name = request.args.get("file_name")
docker.run_word_count_container(file_name)
return "run a word_count container"
@app.route('/docker/word_count_done')
def get_word_count_done():
file_name = request.args.get("file_name")
json_data = json.load_data(
os.path.be part of(os.getenv("SHARED_VOLUME_PATH"),
"word_count_output",
f"{file_name}.json"
))
consequence.append(json_data)
return "all works performed"
@app.route('/docker/consequence')
def get_result():
file_name = request.args.get("file_name")
return jsonify({
"consequence": consequence
})
[routes/upload.py]
import os
from flask import jsonify, request
from werkzeug.utils import secure_filename
from server import app
from lib import docker
@app.route("/add", strategies=["POST"])
def upload_file():
f = request.recordsdata["file"]
file_name = secure_filename(f.filename)
f.save(os.path.be part of(os.getenv("SHARED_VOLUME_PATH"), "enter", file_name))
docker.run_tokenizer_container(file_name)
return "succeed to add"
[routes/__init__.py]
from routes import docker, add
[lib/docker.py]
import os
API_URL = os.getenv("API_URL")
VOLUME_ROOT_PATH = os.getenv("SHARED_VOLUME_PATH")
RUN_TOKENIZER_CONTAINER = 'docker run -it --add-host=host.docker.inner:host-gateway -v "' + VOLUME_ROOT_PATH + ':/shared_volume" hskcoder/tokenizer:0.2 /shared_volume/enter/{FILE_NAME_WITH_EXTENSION} /shared_volume/tokenizer_output ' + API_URL
RUN_WORD_COUNT_CONTAINER = 'docker run -it --add-host=host.docker.inner:host-gateway -v "' + VOLUME_ROOT_PATH + ':/shared_volume" hskcoder/word_count:0.2 /shared_volume/tokenizer_output/{FILE_NAME_WITHOUT_EXTENSION}.json /shared_volume/word_count_output ' + API_URL
def run_tokenizer_container(file_name):
print(RUN_TOKENIZER_CONTAINER.format(
FILE_NAME_WITH_EXTENSION = file_name
))
os.popen(RUN_TOKENIZER_CONTAINER.format(
FILE_NAME_WITH_EXTENSION = file_name
))
def run_word_count_container(file_name):
os.popen(RUN_WORD_COUNT_CONTAINER.format(
FILE_NAME_WITHOUT_EXTENSION = file_name
))
[iib/json.py]
import json
def load_data(path):
with open(path) as f:
json_data = json.load(f)
return json_data
This app learn surroundings variables from .env
file, so it is advisable to arrange like this.
The beneath variables simply match my system.
API_URL=http://host.docker.inner:20000
ROOT_PATH=C:UsershskcoOneDrive바탕 화면stuffdockerapi
SHARED_VOLUME_PATH=C:UsershskcoOneDrive바탕 화면stuffdockerapishared_volume
You’ll be able to run the server with this script
python3 -m pipenv run flask run -h 0.0.0.0 --port 20000
Earlier than operating this command, it is advisable to set an surroundings variable FLASK_APP
.
Since I used to be growing in Home windows, I ran this command in api
dir.
$env:FLASK_APP = './server.py'
In case you enter http://127.0.0.1/docker/consequence
it’s essential to see this web page.
Let’s ship a file to the API server and see the consequence.
Conclusion
It was actually enjoyable. I’ve discovered numerous issues.
No matter your place, I feel It might be actually good to attempt something you are all in favour of.
This instance is basically fundamental, I imply.
It ought to’ve thought-about like
- Authorization
- Communication between containers (On this instance, the API server exposes all routes to the general public)
- Administration containers (Containers which have performed have to be deleted)
- Deployment the API server
With out these, there have to be many issues that it is advisable to contemplate. (I respect for backend builders) I used to be simply specializing in implementing the system, Truthfully, I did not care a lot about others. If I did, I could not write this text. I’ll be again to work tomorrow.
Anyhow, it was enjoyable, it is true 🙂 I hope it’s going to be useful for somebody.