Tutorial: Compilación e implementación de una aplicación web de Python con Azure Container Apps y PostgreSQL
Este artículo forma parte de una serie de tutoriales sobre cómo incluir e implementar una aplicación web de Python en Azure Container Apps. Container Apps permite implementar aplicaciones contenerizadoras sin necesidad de administrar una infraestructura compleja.
En este tutorial, tú:
- Contenerizar un ejemplo de aplicación web de Python (Django o Flask) mediante la creación de una imagen de contenedor en la nube.
- Implemente la imagen de contenedor en Azure Container Apps.
- Defina variables de entorno que permitan que la aplicación contenedora se conecte a una instancia de Azure Database for PostgreSQL: servidor flexible, donde la aplicación de ejemplo almacena los datos.
En el diagrama siguiente se resaltan las tareas de este tutorial: compilar e implementar una imagen de contenedor.
Prerrequisitos
Si no tiene una suscripción de Azure, cree una cuenta gratuita antes de comenzar.
Puede ejecutar comandos de la CLI de Azure en Azure Cloud Shell o en una estación de trabajo con la CLI de Azure instalada.
Si se ejecuta localmente, siga estos pasos para iniciar sesión e instalar los módulos necesarios para este tutorial:
Inicie sesión en Azure y autentíquese, si es necesario:
az login
Asegúrese de que ejecuta la versión más reciente de la CLI de Azure:
az upgrade
Instale o actualice las extensiones de la CLI de Azure containerapp y rdbms-connect mediante el comando az extension add:
az extension add --name containerapp --upgrade az extension add --name rdbms-connect --upgrade
Nota:
Para enumerar las extensiones instaladas en el sistema, puede usar el comando az extension list. Por ejemplo:
az extension list --query [].name --output tsv
Obtención de la aplicación de ejemplo
Hacer un fork y clonar el código de ejemplo en el entorno de desarrollo:
Vaya al repositorio GitHub de la aplicación de ejemplo (Django o Flask) y seleccione Bifurcar.
Sigue los pasos para hacer un fork del repositorio en tu cuenta de GitHub. También puede descargar el repositorio de código directamente en su máquina local sin necesidad de bifurcarlo ni usar una cuenta de GitHub. Pero si usa el método de descarga, no podrá configurar la integración continua y la entrega continua (CI/CD) en el siguiente tutorial de esta serie.
Use el comando git clone para clonar el repositorio bifurcado en la carpeta python-container:
# Django git clone https://github.com/$USERNAME/msdocs-python-django-azure-container-apps.git python-container # Flask # git clone https://github.com/$USERNAME/msdocs-python-flask-azure-container-apps.git python-container
Cambie el directorio:
cd python-container
Construir una imagen de contenedor a partir del código de la aplicación web
Después de seguir estos pasos, tendrá una instancia de Azure Container Registry que contiene una imagen de contenedor de Docker compilada a partir del código de ejemplo.
Cree un grupo de recursos con el comando az group create:
az group create \ --name pythoncontainer-rg \ --location <location>
Sustituya <location> por uno de los valores de
Name
de ubicación de Azure de la salida del comandoaz account list-locations -o table
.Cree un registro de contenedor mediante el comando az acr create:
az acr create \ --resource-group pythoncontainer-rg \ --name <registry-name> \ --sku Basic \ --admin-enabled
El nombre que use para <nombre del Registro> debe ser único en Azure y debe contener de 5 a 50 caracteres alfanuméricos.
Inicie sesión en el Registro con el comando az acr login
: az acr login --name <registry-name>
El comando añade "azurecr.io" al nombre para crear el nombre de registro completo. Si el inicio de sesión se realiza correctamente, aparece el mensaje "Inicio de sesión correcto". Si está accediendo al registro desde una suscripción diferente de aquella en la que se creó el registro, use el conmutador
--suffix
.Si se produce un error en el inicio de sesión, asegúrese de que el demonio de Docker se está ejecutando en su sistema.
Compile la imagen mediante el comando az acr build:
az acr build \ --registry <registry-name> \ --resource-group pythoncontainer-rg \ --image pythoncontainer:latest .
Estas consideraciones se aplican:
El punto (
.
) al final del comando indica la ubicación del código fuente que se va a compilar. Si no ejecuta este comando en el directorio raíz de la aplicación de ejemplo, especifique la ruta de acceso al código.Si ejecuta el comando en Azure Cloud Shell, use
git clone
para extraer primero el repositorio en el entorno de Cloud Shell. A continuación, cambie el directorio a la raíz del proyecto para que el punto (.
) se interprete correctamente.Si omite la opción
-t
(igual que--image
), el comando pone en cola una compilación de contexto local sin enviarla al registro. Compilar sin enviar puede ser útil para comprobar que la imagen se compila.
Confirme que la imagen de contenedor se creó mediante el comando az acr repository list:
az acr repository list --name <registry-name>
Nota:
Los pasos de esta sección crean un registro de contenedor en el nivel de servicio Básico. Este nivel está optimizado para costos, con un conjunto de características y un rendimiento dirigidos a escenarios de desarrollador, y es adecuado para los requisitos de este tutorial. En escenarios de producción, lo más probable es que use el nivel de servicio Estándar o Premium. Estos niveles proporcionan niveles mejorados de almacenamiento y rendimiento.
Para obtener más información, consulte Niveles de servicio de Azure Container Registry. Para obtener información sobre los precios, consulte los Precios de Azure Container Registry.
Crear una instancia de servidor flexible de PostgreSQL.
La aplicación de ejemplo (Django o Flask) almacena los datos de revisión del restaurante en una base de datos PostgreSQL. En estos pasos, se crea el servidor que contendrá la base de datos.
Use el comando az postgres flexible-server create para crear el servidor PostgreSQL en Azure. No es raro que este comando se ejecute durante unos minutos antes de que finalice.
az postgres flexible-server create \ --resource-group pythoncontainer-rg \ --name <postgres-server-name> \ --location <location> \ --admin-user demoadmin \ --admin-password <admin-password> \ --active-directory-auth Enabled \ --tier burstable \ --sku-name standard_b1ms \ --public-access 0.0.0.0
Use estos valores:
pythoncontainer-rg
: el nombre del grupo de recursos que usa este tutorial. Si ha usado un nombre diferente, cambie este valor.<postgres-server-name>: el nombre del servidor de base de datos postgreSQL. Este nombre debe ser único en todas las instancias de Azure. El punto de conexión del servidor es
https://<postgres-server-name>.postgres.database.azure.com
. Los caracteres permitidos son deA
aZ
,0
a9
y el guion (-
).<ubicación>: Use la misma ubicación que utilizaste para la aplicación web. <location> es uno de los valores de
Name
de ubicación de Azure de la salida del comandoaz account list-locations -o table
.<>admin-username: el nombre de usuario de la cuenta de administrador. No puede ser
azure_superuser
,admin
,administrator
,root
,guest
opublic
. Usademoadmin
para este tutorial.<contraseña del usuario administrador>: la contraseña del usuario administrador. Debe contener entre 8 y 128 caracteres de tres de las siguientes categorías: Letras del alfabeto inglés mayúsculas y minúsculas, números y caracteres no alfanuméricos.
Importante
Al crear nombres de usuario o contraseñas, no usar el carácter de signo de dólar ($). Más adelante, al crear variables de entorno con estos valores, ese carácter tiene un significado especial dentro del contenedor de Linux que se usa para ejecutar aplicaciones de Python.
--active-directory-auth
: este valor especifica si la autenticación de Microsoft Entra está habilitada en el servidor PostgreSQL. Establézcalo enEnabled
.--sku-name
: El nombre del plan de tarifa y la configuración del proceso, por ejemplo,Standard_B1ms
. Para más información, consulte los precios de Azure Database for PostgreSQL. Para enumerar los niveles disponibles, useaz postgres flexible-server list-skus --location <location>
.--public-access
: utiliza0.0.0.0
. Permite el acceso público al servidor desde cualquier servicio de Azure, como Container Apps.
Nota:
Si tiene previsto trabajar con el servidor PostgreSQL desde la estación de trabajo local mediante herramientas, debe agregar una regla de firewall para la dirección IP de la estación de trabajo mediante el comando az postgres flexible-server firewall-rule create.
Utilice el comando az ad signed-in-user show para obtener el ID de objeto de su cuenta de usuario. Use este identificador en el siguiente comando.
az ad signed-in-user show --query id --output tsv
Use el comando az postgres flexible-server ad-admin create para agregar su cuenta de usuario como administrador de Microsoft Entra en el servidor PostgreSQL.
az postgres flexible-server ad-admin create \ --resource-group pythoncontainer-rg \ --server-name <postgres-server-name> \ --display-name <your-email-address> \ --object-id <your-account-object-id>
Para el identificador de objeto de tu cuenta, usa el valor que obtuviste en el paso anterior.
Nota:
Los pasos en esta sección le permiten crear un servidor PostgreSQL con un único vCore y memoria limitada en el nivel de precios ampliable. El nivel Elástico es una opción de menor costo para las cargas de trabajo que no necesitan utilizar la CPU al completo de forma continua, y es adecuada para los requisitos de este tutorial. En el caso de las cargas de trabajo de producción, puede actualizar al nivel de precios de uso general u optimizado para memoria. Estos niveles proporcionan un mayor rendimiento, pero aumentan los costos.
Para obtener más información, consulte Opciones de proceso en Azure Database for PostgreSQL - Servidor flexible. Para obtener más información sobre los precios, consulte Precios de Azure Database for PostgreSQL.
Crear una base de datos en el servidor
En este punto, tiene un servidor PostgreSQL. En esta sección, se crea una base de datos en el servidor.
Use el comando az postgres flexible-server db create para crear una base de datos denominada restaurants_reviews:
az postgres flexible-server db create \
--resource-group pythoncontainer-rg \
--server-name <postgres-server-name> \
--database-name restaurants_reviews
Use estos valores:
pythoncontainer-rg
: el nombre del grupo de recursos que usa este tutorial. Si ha usado un nombre diferente, cambie este valor.<postgres-server-name>
: el nombre del servidor postgreSQL.
También podría usar el comando az postgres flexible-server connect para conectarse a la base de datos y luego trabajar con comandos psql. Al trabajar con psql, a menudo es más fácil usar Azure Cloud Shell, ya que el shell incluye todas las dependencias automáticamente.
También puede conectarse al servidor flexible de Azure Database for PostgreSQL y crear una base de datos mediante psql o un IDE que admita PostgreSQL, como Azure Data Studio. Para conocer los pasos con psql, consulte Configuración de la identidad administrada en la base de datos postgreSQL más adelante en este artículo.
Creación de una identidad administrada asignada por el usuario
Cree una identidad administrada asignada por el usuario para usarla como identidad para la aplicación contenedora cuando se ejecute en Azure.
Nota:
Para crear una identidad administrada asignada por el usuario, la cuenta requiere la asignación del rol Colaborador de identidades administradas.
Utiliza el comando az identity create para crear una identidad gestionada asignada al usuario.
az identity create --name my-ua-managed-id --resource-group pythoncontainer-rg
Configuración de la identidad administrada en la base de datos postgreSQL
Configure la identidad administrada como rol en el servidor PostgreSQL y conceda los permisos necesarios para la base de datos de restaurants_reviews. Ya sea que use la CLI de Azure o psql, debe conectarse al servidor de Azure PostgreSQL con un usuario que se haya configurado como administrador de Microsoft Entra en la instancia del servidor. Solo las cuentas de Microsoft Entra configuradas como administrador de PostgreSQL pueden configurar identidades administradas y otros roles de administrador de Microsoft en el servidor.
Obtenga un token de acceso para la cuenta de Azure mediante el comando az account get-access-token
. Use el token de acceso en los pasos siguientes. az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken
El token devuelto es largo. Establezca su valor en una variable de entorno para usarla en los comandos del paso siguiente:
MY_ACCESS_TOKEN=<your-access-token>
Agregue la identidad administrada asignada por el usuario como rol de base de datos en el servidor PostgreSQL mediante el comando az postgres flexible-server execute.
az postgres flexible-server execute \ --name <postgres-server-name> \ --database-name postgres \ --querytext "select * from pgaadauth_create_principal('"my-ua-managed-id"', false, false);select * from pgaadauth_list_principals(false);" \ --admin-user <your-Azure-account-email> \ --admin-password $MY_ACCESS_TOKEN
Use estos valores:
Si usó un nombre diferente para la identidad administrada, reemplace
my-ua-managed-id
en el comandopgaadauth_create_principal
por el nombre de la identidad administrada.Para el valor de
--admin-user
, use la dirección de correo electrónico de la cuenta de Azure.Para el valor de
--admin-password
, use el token de acceso de la salida del comando anterior, sin comillas.Asegúrese de que el nombre de la base de datos es
postgres
.
Nota:
Si ejecuta el comando
az postgres flexible-server execute
en la estación de trabajo local, asegúrese de agregar una regla de firewall para la dirección IP de la estación de trabajo. Puede agregar una regla mediante el comando az postgres flexible-server firewall-rule create. El mismo requisito también existe para el comando en el paso siguiente.Conceda a la identidad administrada asignada por el usuario los permisos necesarios en la base de datos de restaurants_reviews usando el siguiente comando az postgres flexible-server execute:
az postgres flexible-server execute \ --name <postgres-server-name> \ --database-name restaurants_reviews \ --querytext "GRANT CONNECT ON DATABASE restaurants_reviews TO \"my-ua-managed-id\";GRANT USAGE ON SCHEMA public TO \"my-ua-managed-id\";GRANT CREATE ON SCHEMA public TO \"my-ua-managed-id\";GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"my-ua-managed-id\";ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO \"my-ua-managed-id\";" \ --admin-user <your-Azure-account-email> \ --admin-password $MY_ACCESS_TOKEN
Use estos valores:
Si usó un nombre diferente para la identidad administrada, reemplace todas las instancias de
my-ua-managed-id
en el comando por el nombre de la identidad administrada. Hay cinco instancias en la cadena de consulta.Para el valor de
--admin-user
, use la dirección de correo electrónico de la cuenta de Azure.Para el valor de
--admin-password
, use el token de acceso de la salida anterior, sin comillas.Asegúrese de que el nombre de la base de datos es
restaurants_reviews
.
Este comando de la CLI de Azure se conecta a la base de datos de restaurants_reviews en el servidor y emite los siguientes comandos SQL:
GRANT CONNECT ON DATABASE restaurants_reviews TO "my-ua-managed-id"; GRANT USAGE ON SCHEMA public TO "my-ua-managed-id"; GRANT CREATE ON SCHEMA public TO "my-ua-managed-id"; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "my-ua-managed-id"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "my-ua-managed-id";
Implementación de la aplicación web en Container Apps
Las aplicaciones de contenedor se implementan en entornos de Azure Container Apps, que actúan como límites seguros. En los siguientes pasos, crearás el entorno y un contenedor dentro de este. A continuación, configure el contenedor para que el sitio web sea visible externamente.
Estos pasos requieren la extensión Azure Container Apps, containerapp.
Cree un entorno de Container Apps con el comando az containerapp env create:
az containerapp env create \ --name python-container-env \ --resource-group pythoncontainer-rg \ --location <location>
<location> es uno de los valores de
Name
de ubicación de Azure de la salida del comandoaz account list-locations -o table
.Obtenga las credenciales de inicio de sesión de la instancia de Azure Container Registry mediante el comando az acr credential show:
az acr credential show -n <registry-name>
Use el nombre de usuario y una de las contraseñas devueltas desde la salida del comando al crear la aplicación contenedora en el paso 5.
Use el comando az identity show para obtener el identificador de cliente y el identificador de recurso de la identidad administrada asignada por el usuario:
az identity show --name my-ua-managed-id --resource-group pythoncontainer-rg --query "[clientId, id]" --output tsv
Use el valor del identificador de cliente (GUID) y el identificador de recurso de la salida del comando al crear la aplicación contenedora en el paso 5. El identificador de recurso tiene el siguiente formato:
/subscriptions/<subscription-id>/resourcegroups/pythoncontainer-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-ua-managed-id
.Ejecute el siguiente comando para generar un valor de clave secreta:
python -c 'import secrets; print(secrets.token_hex())'
Use el valor de clave secreta para establecer una variable de entorno al crear la aplicación contenedora en el paso 5.
Nota:
El comando que muestra este paso es para un shell de Bash. En función del entorno, es posible que tenga que invocar Python mediante
python3
. En Windows, debe incluir el comando en el parámetro-c
entre comillas dobles en lugar de comillas simples. También es posible que tenga que invocar Python mediantepy
opy -3
, en función de su entorno.Crea una aplicación contenedora en el entorno con el comando az containerapp create:
az containerapp create \ --name python-container-app \ --resource-group pythoncontainer-rg \ --image <registry-name>.azurecr.io/pythoncontainer:latest \ --environment python-container-env \ --ingress external \ --target-port <5000 for Flask or 8000 for Django> \ --registry-server <registry-name>.azurecr.io \ --registry-username <registry-username> \ --registry-password <registry-password> \ --user-assigned <managed-identity-resource-id> \ --query properties.configuration.ingress.fqdn \ --env-vars DBHOST="<postgres-server-name>" \ DBNAME="restaurants_reviews" \ DBUSER="my-ua-managed-id" \ RUNNING_IN_PRODUCTION="1" \ AZURE_CLIENT_ID="<managed-identity-client-id>" \ AZURE_SECRET_KEY="<your-secret-key>"
Asegúrese de reemplazar todos los valores entre corchetes angulares por los valores que usa en este tutorial. Tenga en cuenta que el nombre de la aplicación contenedora debe ser único en Azure.
El valor del parámetro
--env-vars
es una cadena compuesta de valores separados por espacios en el key="value" formato con los siguientes valores:DBHOST="\<postgres-server-name>"
DBNAME="restaurants_reviews"
DBUSER="my-ua-managed-id"
RUNNING_IN_PRODUCTION="1"
AZURE_CLIENT_ID="\<managed-identity-client-id>"
AZURE_SECRET_KEY="\<your-secret-key>"
El valor de
DBUSER
es el nombre de la identidad administrada asignada por el usuario.El valor de
AZURE_CLIENT_ID
es el identificador de cliente de la identidad administrada asignada por el usuario. Obtuviste este valor en un paso anterior.El valor de
AZURE_SECRET_KEY
es el valor de clave secreta que generó en un paso anterior.Para Django solamente, migre y cree un esquema de base de datos. (En la app de ejemplo Flask, se hace automáticamente, y puede saltarse este paso).
Conéctese utilizando el comando az containerapp exec.
az containerapp exec \ --name python-container-app \ --resource-group pythoncontainer-rg
A continuación, en la línea de comandos del shell, introduzca
python manage.py migrate
.No es necesario migrar para las revisiones del contenedor.
Pruebe el sitio web.
El comando
az containerapp create
que escribió anteriormente genera una dirección URL de aplicación que puede usar para ir a la aplicación. La dirección URL termina enazurecontainerapps.io
. Vaya a la dirección URL en un explorador. También puede usar el comando az containerapp browse.
Este es un ejemplo del sitio web de ejemplo después de la adición de un restaurante y dos opiniones.
Solución de problemas de implementación
Olvidó la dirección URL de la aplicación para acceder al sitio web.
En Azure Portal:
- Vaya a la página Información general de la aplicación de contenedor y busque URL de aplicación.
En VS Code:
- Vaya a Vista de Azure (Ctrl+Shift+A) y expanda la suscripción en la que está trabajando.
- Expanda el nodo Container Apps, luego expanda el entorno administrado y haga clic con el botón derecho en python-container-app y seleccione Examinar. VS Code abre el explorador con la dirección URL de la aplicación.
En la CLI de Azure:
- Use el comando
az containerapp show -g pythoncontainer-rg -n python-container-app --query properties.configuration.ingress.fqdn
.
En VS Code, la tarea Compilar imagen en Azure devuelve un error.
Si ve el mensaje "Error: no se pudo descargar el contexto. Compruebe si la dirección URL es incorrecta en la ventana de salida de VS Code y actualice el registro en la extensión de Docker. Para actualizar, seleccione la extensión de Docker, vaya a la sección Registros, busque el registro y selecciónelo.
Si vuelve a ejecutar la tarea Compilar imagen en Azure, compruebe si existe el registro de una ejecución anterior. Si es así, úselo.
En Azure Portal, aparece un error de acceso durante la creación de una aplicación de contenedor.
Se produce un error de acceso con el mensaje "No se puede acceder al ACR '<>.azurecr.io'" si se deshabilitan las credenciales de administrador en una instancia de Azure Container Registry.
Para comprobar el estado del administrador en el portal, vaya a la instancia de Azure Container Registry, seleccione el recurso de Claves de acceso y asegúrese de que usuario administrador esté habilitado.
La imagen de contenedor no aparece en la instancia de Azure Container Registry
- Compruebe la salida del comando CLI de Azure o salida de VS Code y busque mensajes que se ha realizado correctamente.
- Compruebe que el nombre del registro se ha especificado correctamente en el comando de compilación con la CLI de Azure o en los mensajes de tarea de VS Code.
- Asegúrese de que sus credenciales no hayan caducado. Por ejemplo, en VS Code, busque el registro de destino en la extensión de Docker y actualícelo. En la CLI de Azure, ejecute
az login
.
El sitio web devuelve "Solicitud incorrecta (400)"
Si recibe un error de "Solicitud incorrecta (400)", compruebe las variables de entorno de PostgreSQL pasadas al contenedor. El error 400 a menudo indica que el código Python no puede conectarse a la instancia PostgreSQL.
El código de ejemplo usado en este tutorial comprueba la existencia de la variable de entorno de contenedor RUNNING_IN_PRODUCTION
, que se puede establecer en cualquier valor (como 1
).
El sitio web devuelve "No encontrado (404)"
- Compruebe el valor de URL de aplicación en la página de Información general del contenedor. Si la dirección URL de la aplicación contiene la palabra "internal", el acceso no se establece correctamente.
- Compruebe la entrada del contenedor. Por ejemplo, en Azure Portal, vaya al recurso Entrada del contenedor. Asegúrese de que Entrada HTTP está habilitado y Aceptar tráfico desde cualquier lugar esté seleccionado.
El sitio web no se inicia, recibes "tiempo de espera de transmisión" o no se devuelve nada.
- Compruebe los registros:
- En Azure Portal, vaya al recurso de administración de revisiones de la aplicación contenedora y compruebe Estado de aprovisionamiento para el contenedor:
- Si el estado es Aprovisionamiento, espere hasta que finalice el aprovisionamiento.
- Si el estado es Error, seleccione la revisión y vea los registros de la consola. Elija el orden de las columnas para mostrar Hora de generación, Stream_s y Log_s. Ordene los registros por más reciente y busque los mensajes
stderr
de Python ystdout
en la columna Stream_s. La salida deprint
de Python son mensajesstdout
.
- En la CLI de Azure, use el comando az containerapp logs show.
- En Azure Portal, vaya al recurso de administración de revisiones de la aplicación contenedora y compruebe Estado de aprovisionamiento para el contenedor:
- Si usa el marco django, compruebe si las tablas de restaurants_reviews existen en la base de datos. Si no es así, use una consola para acceder al contenedor y ejecute
python manage.py migrate
.