Primera prueba de código de microservicios
Some checks failed
build / build (push) Failing after 0s
test / echo (push) Has been cancelled

This commit is contained in:
2025-12-12 12:59:20 +01:00
commit 85d023acec
7 changed files with 251 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
name: build
on:
push:
branches:
- main
jobs:
build:
runs-on: [k8s, kaniko]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Login a Nexus
env:
NEXUS_USER: ${{ secrets.NEXUS_USER }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
run: |
echo "$NEXUS_PASSWORD" | docker login nexus.rancherk3.duckdns.org -u "$NEXUS_USER" --password-stdin
- name: Build & Push image with Kaniko
image: gcr.io/kaniko-project/executor:latest
command:
- /kaniko/executor
args:
- --context=.
- --dockerfile=./Dockerfile
- --destination=nexus.rancherk3.duckdns.org/tfm/microserviciospython:latest

View File

@@ -0,0 +1,8 @@
name: test
on: [push]
jobs:
echo:
runs-on: self-hosted
steps:
- run: echo "Gitea Actions funcionando!"

72
Dockerfile Normal file
View File

@@ -0,0 +1,72 @@
# =========================
# Etapa de Build
# =========================
FROM python:3.12-slim AS build
# Instalar dependencias de build mínimas
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
python3-venv \
pip \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Crear un entorno virtual Python para build
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Actualizar pip y herramientas de build
RUN pip install --upgrade pip setuptools wheel build pipenv
# Copiar código y preparar build
ADD src /app
WORKDIR /app
# Instalar dependencias y construir la rueda
RUN pipenv install --deploy --system || true
RUN python -m build -w
# =========================
# Etapa de Runtime
# =========================
FROM python:3.12-slim
ARG BUILD_DATE
LABEL org.label-schema.maintainer="Diego Fernández Carvajal (diego.fdezcarvajal@emtmadrid.es)" \
org.label-schema.build-dockerfile="11/12/2025" \
org.label-schema.build=$BUILD_DATE
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Europe/Madrid
ENV PYTHONUNBUFFERED=1
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /app
# Instalar dependencias mínimas de runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
python3-venv \
supervisor \
tzdata \
locales \
&& ln -fs /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& echo "es_ES.UTF-8 UTF-8" > /etc/locale.gen \
&& echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \
&& locale-gen \
&& apt-get clean && apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Copiar supervisord
COPY /man/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Copiar ruedas desde build
COPY --from=build /app/dist/*.whl /app/
# Crear entorno virtual para runtime
RUN python -m venv /opt/venv
# Instalar ruedas en el entorno virtual
RUN pip install --upgrade pip setuptools wheel
RUN pip install /app/*.whl -t /app
CMD ["/usr/bin/supervisord","-c","/etc/supervisor/conf.d/supervisord.conf"]

23
man/supervisord.conf Normal file
View File

@@ -0,0 +1,23 @@
[supervisord]
logfile=/tmp/supervisord.log ; supervisord log file
logfile_maxbytes=10MB ; maximum size of logfile before rotation
logfile_backups=2 ; number of backed up logfiles
loglevel=error ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
nodaemon=true ; run supervisord as a daemon
minfds=1024 ; number of startup file descriptors
minprocs=200 ; number of process descriptors
user=root ; default user
[unix_http_server]
file = /tmp/supervisor.sock ; supervisor unix http server sock file
[program:microservicios]
command=python3 flask.py
directory=/app
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/2
stderr_logfile_maxbytes=0
autostart=true
autorestart=true

0
src/__init__.py Normal file
View File

85
src/flask.py Normal file
View File

@@ -0,0 +1,85 @@
from flask import Flask, jsonify, request
import os
import psycopg2
import pandas as pd
import xgboost as xgb
import joblib
app = Flask(__name__)
# Configuración de la base de datos
DB_CONFIG = {
'dbname': os.getenv('DB_NAME', 'postgres'),
'user': os.getenv('DB_USER', 'postgres'),
'password': os.getenv('DB_PASSWORD', 'tfmuocdfcarvajal'),
'host': os.getenv('DB_HOST', '10.10.5.32'),
'port': os.getenv('DB_PORT', '5432')
}
# Ruta para entrenar o cargar el modelo
MODEL_PATH = 'modelo_xgb.joblib'
def get_db_connection():
conn = psycopg2.connect(**DB_CONFIG)
return conn
def fetch_data():
conn = get_db_connection()
query = """
SELECT h3, hour, dow, total_events, total_nulos, nulo_rate
FROM demanda_h3_hour
"""
df = pd.read_sql(query, conn)
conn.close()
return df
def train_model(df):
# Variables predictoras
X = df[['hour', 'dow', 'total_events']]
# Variable objetivo: nulo_rate > 0 -> 1, else 0
y = (df['nulo_rate'] > 0).astype(int)
model = xgb.XGBClassifier(
max_depth=4, n_estimators=100, learning_rate=0.1, use_label_encoder=False, eval_metric='logloss'
)
model.fit(X, y)
joblib.dump(model, MODEL_PATH)
return model
def load_model():
try:
model = joblib.load(MODEL_PATH)
return model
except:
df = fetch_data()
return train_model(df)
model = load_model()
@app.route('/predict', methods=['GET'])
def predict():
# Parámetros de la consulta
hour = int(request.args.get('hour'))
dow = int(request.args.get('dow'))
total_events = int(request.args.get('total_events', 1)) # valor por defecto si no se pasa
X_pred = pd.DataFrame([[hour, dow, total_events]], columns=['hour', 'dow', 'total_events'])
prob = model.predict_proba(X_pred)[0][1] # Probabilidad de nulo
return jsonify({
'hour': hour,
'dow': dow,
'total_events': total_events,
'predicted_nulo_prob': float(prob)
})
@app.route('/demand', methods=['GET'])
def demand():
df = fetch_data()
X_pred = df[['hour', 'dow', 'total_events']]
df['predicted_nulo_prob'] = model.predict_proba(X_pred)[:,1].astype(float)
# Convertimos a JSON
result = df.to_dict(orient='records')
return jsonify(result)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

33
src/pyproject.toml Normal file
View File

@@ -0,0 +1,33 @@
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "microservicios"
version = "1.0.1"
requires-python = ">= 3.8"
description = "Microservicios para Estimaciones"
license={text = "EULA"}
authors = [
{name = "Diego Fernández", email = "carvajal.diego@gmail.com"}
]
dependencies = [
'flask',
'psycopg2-binary',
'pandas',
'xgboost',
'scikit-learn',
'joblib'
]
[tool.setuptools]
include-package-data = true
py-modules = ["flask"]
[tool.setuptools.packages]
find = {}
[project.urls]
Documentation='https://https://gitea.tfmuocdfcarvajal.duckdns.org/TFM/microservicios_python'