Ejercicio: Implementación de una aplicación spring AI en Azure Container Apps
En esta unidad, implementará la aplicación Spring AI en Azure Container Apps para hospedar contenedores escalables y sin servidor.
Configurar variables de entorno
Para este ejercicio, necesita algunas variables de entorno de los ejercicios anteriores. Si usa la misma ventana de Bash, estas variables seguirán existiendo. Si las variables ya no están disponibles, use los siguientes comandos para volver a crearlas. Asegúrese de reemplazar los <...> marcadores de posición por sus propios valores y utilice los mismos valores que empleó anteriormente.
export RESOURCE_GROUP=<resource-group>
export LOCATION=<location>
export OPENAI_RESOURCE_NAME=OpenAISpringAI
export AZURE_OPENAI_ENDPOINT=$(az cognitiveservices account show \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--query "properties.endpoint" \
--output tsv \
| tr -d '\r')
export AZURE_OPENAI_API_KEY=$(az cognitiveservices account keys list \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--query "key1" \
--output tsv \
| tr -d '\r')
export DB_SERVER_NAME=<server-name>
export PGHOST=$(az postgres flexible-server show \
--resource-group $RESOURCE_GROUP \
--name $DB_SERVER_NAME \
--query fullyQualifiedDomainName \
--output tsv \
| tr -d '\r')
También necesita algunas nuevas variables de entorno para esta unidad. Use el siguiente comando para definir estas variables. Asegúrese de reemplazar los marcadores de posición <...> por sus propios valores.
export CONTAINER_APP_NAME=<container-app-name>
export MANAGED_IDENTITY_NAME=<managed-identity-name>
export ENVIRONMENT=<Azure-Container-Apps-environment>
Con estas variables de entorno implementadas, ya está listo para implementar la aplicación en Azure Container Apps.
Creación de un archivo Dockerfile
A continuación, cree un Dockerfile y agregue el siguiente contenido. Este archivo se usa para compilar una imagen de Docker con el código de aplicación para la implementación en Azure Container Apps.
# Step 1: Use microsoft JDK image with maven3 to build the application
FROM mcr.microsoft.com/openjdk/jdk:17-mariner AS builder
RUN tdnf install maven3 -y
WORKDIR /app
COPY pom.xml ./
COPY src ./src
RUN mvn clean package -DskipTests
# Step 2: Use microsoft JDK image for the final image
FROM mcr.microsoft.com/openjdk/jdk:17-mariner
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
Implementación de la aplicación contenedora
Para implementar la aplicación, use el siguiente comando:
az containerapp up \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--environment $ENVIRONMENT \
--source . \
--ingress external \
--target-port 8080 \
--location $LOCATION
Este comando realiza las siguientes tareas:
- Crea el grupo de recursos, si aún no existe.
- Crea el entorno de Container Apps con un área de trabajo de Log Analytics. El entorno se denomina utilizando el valor especificado en el
environmentparámetro . - Crea una instancia de Azure Container Registry.
- Compila la imagen de contenedor mediante el código fuente y el Dockerfile en el directorio especificado por el
sourceparámetro y, a continuación, lo inserta en el registro. - Crea e implementa la aplicación contenedora mediante la imagen de contenedor compilada. La aplicación contenedora se denomina utilizando el valor especificado en el
nameparámetro . - Configura
8080como el puerto HTTP al que la aplicación en contenedor escucha para el tráfico entrante. - Implementa la aplicación contenedora en la región especificada en el
locationparámetro .
Para ver los registros de la aplicación contenedora, use el siguiente comando:
az containerapp logs show \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--tail 80
En el ejemplo siguiente se muestra un registro típico. Al inspeccionar los registros, puede ver que la aplicación no se inicia correctamente debido a que faltan valores de configuración, que se espera en este momento.
{"TimeStamp": "2025-03-04T19:04:52.7673831+00:00", "Log": "F Caused by: org.postgresql.util.PSQLException:
FATAL: Azure AD user token for role[AzureAdmin] is neither an AAD_AUTH_TOKENTYPE_APP_USER or an
AAD_AUTH_TOKENTYPE_APP_OBO token."}
Para volver a implementar la aplicación después de realizar cambios, puede usar el siguiente comando:
az containerapp update \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--source .
Habilitar identidad administrada
La aplicación contenedora debe poder autenticarse en el servidor postgresSQL. Las identidades administradas asignadas por el sistema se usan para la autenticación.
Para habilitar una identidad administrada asignada por el sistema para la aplicación contenedora, use el siguiente comando:
az containerapp identity assign \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--system-assigned
Para obtener el identificador de la identidad administrada asignada por el sistema y mostrarla, use los siguientes comandos:
export MANAGED_IDENTITY_ID=$(az containerapp show \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--query 'identity.principalId' \
--output tsv \
| tr -d '\r')
echo "Managed Identity ID: $MANAGED_IDENTITY_ID"
Para autorizar la identidad administrada de la aplicación contenedora para acceder a la instancia de servidor flexible de Azure Database for PostgreSQL, use el siguiente comando:
az postgres flexible-server ad-admin create \
--resource-group $RESOURCE_GROUP \
--server-name $DB_SERVER_NAME \
--display-name $MANAGED_IDENTITY_NAME \
--object-id $MANAGED_IDENTITY_ID \
--type ServicePrincipal
Configuración del entorno y el secreto de la aplicación contenedora
Para crear un secreto para los valores confidenciales, use el siguiente comando:
az containerapp secret set \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--secrets \
azure-openai-api-key=$AZURE_OPENAI_API_KEY
A continuación, use el siguiente comando para establecer variables de entorno:
az containerapp update \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--set-env-vars \
SPRING_AI_AZURE_OPENAI_API_KEY=secretref:azure-openai-api-key \
SPRING_AI_AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT} \
SPRING_DATASOURCE_USERNAME=${MANAGED_IDENTITY_NAME} \
SPRING_DATASOURCE_URL=jdbc:postgresql://${PGHOST}/postgres?sslmode=require \
SPRING_AI_VECTORSTORE_PGVECTOR_SCHEMA_NAME=containerapp
Este comando usa intencionadamente un nombre de esquema diferente pgvector para evitar conflictos al usar el mismo nombre de esquema con un usuario diferente.
Comprobación de la implementación
Use el siguiente comando para obtener la dirección URL de la aplicación contenedora:
export URL=$(az containerapp show \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--query properties.configuration.ingress.fqdn \
--output tsv)
Use el siguiente comando para probar el punto de conexión:
curl -G "https://$URL/api/rag" \
--data-urlencode "query=How does QuestionAnswerAdvisor work in Spring AI?"
La respuesta debe ser similar al ejemplo siguiente:
In the context of **Spring AI**, the **QuestionAnswerAdvisor** operates as a key component for enabling **Retrieval Augmented Generation (RAG)**, which combines user queries with external contextual data to produce accurate and relevant AI responses.
Use el siguiente comando para probar otra pregunta que no está en el almacén de vectores:
curl -G "https://$URL/api/rag" \
--data-urlencode "query=What is vector similarity search?"
La respuesta debe ser similar al ejemplo siguiente:
**Vector similarity search** refers to the process of comparing and ranking data points - represented as vectors - based on their similarity in a multi-dimensional space. This method is commonly used in applications like information retrieval, recommendation systems, natural language processing, and computer vision.
Use el comando siguiente para probar el punto de conexión de generación de blog:
curl -G "https://$URL/api/blog" \
--data-urlencode "topic=Java on Azure"
Debido al ciclo de iteración de revisión, esta solicitud tarda más tiempo en completarse. Una vez completado, debería ver una respuesta JSON que contenga tanto el contenido del blog como los metadatos sobre el proceso de generación, como se muestra en el ejemplo siguiente:
{
"metadata": {
"totalTokensUsed": 8637,
"approved": false,
"tokenUsage": {
"promptTokens": 5324,
"totalTokens": 8637,
"completionTokens": 3313
},
"model": "Azure OpenAI",
"editorFeedback": [
{
"feedback": "**Feedback:**\n\n1. **Sentence Count Issue:** The draft exceeds the strict 10-sentence maximum requirement. It contains 11 sentences. To comply with the rules, you need to condense the content without losing essential details.\n\n2. **Clarity and Flow of Ideas:** While the draft is informative, the transition between sections feels slightly mechanical. For instance, the sentence about deploying a Spring Boot application being simple could flow better into the discussion about monitoring and diagnostics. Consider smoothing out these transitions to make the blog more cohesive.\n\n3. **Engagement and Reader Interest:** The tone is professional but lacks a conversational spark that would fully engage the reader. Adding a brief anecdote, rhetorical question, or vivid example could help draw readers in. For example, you could open with a scenario like, \"Imagine deploying your Java app to the cloud in minutes, while Azure handles the heavy lifting.\"\n\n4. **Professional Yet Conversational Tone:** While polished, the tone leans slightly towards technical documentation rather than a conversational blog. Use more approachable phrasing to make it relatable to broader audiences, such as developers exploring Azure for the first time.\n\n5. **Structure and Organization:** The draft provides valuable information but feels slightly dense. Breaking it into smaller, more digestible sections or trimming less critical details can improve readability. For example, you could consolidate the points about Azure's tools and services into a single sentence to save space.\n\n6. **Actionable Suggestions:**\n - Reduce sentence count to meet the 10-sentence maximum by combining or trimming redundant ideas. For example, integrate the points about Azure's services and Spring Boot deployment into a single concise statement.\n - Add a conversational hook or engaging opening sentence to draw readers in immediately.\n - Improve transitions between ideas to enhance flow and readability. For instance, connect the infrastructure management point more naturally to the monitoring and diagnostics capabilities.\n - Consider rephrasing to strike a balance between technical detail and approachable language.\n\n7. **Conclusion Improvement:** The conclusion is strong but could be more dynamic. Consider ending with a forward-looking statement or call-to-action, such as, \"Explore how Azure can revolutionize your Java development journey today.\"\n\nBy implementing these changes, the blog can achieve a more refined, engaging, and reader-friendly result while adhering to the rules.",
"iteration": 1
},
{
"feedback": "**Feedback:**\n\n1. **Sentence Count:** The draft contains 11 sentences, exceeding the 10-sentence limit. This violates the stated guidelines and must be corrected. Revising for conciseness is necessary.\n\n2. **Clarity and Flow:** While the ideas are clear, the flow feels slightly disjointed. The transitions between Java frameworks, tools, and Azure services could be smoother to create a more cohesive narrative. Consider linking sections with transitional phrases to enhance readability.\n\n3. **Engagement and Reader Interest:** The opening sentence is engaging but could be more specific to immediately hook the reader. For example, instead of \"Imagine deploying your Java app to the cloud,\" consider adding a concrete benefit or scenario that resonates with developers.\n\n4. **Professional yet Conversational Tone:** The tone is professional but leans too heavily on technical descriptions without enough conversational elements. Adding relatable examples or posing direct questions might make the blog more inviting.\n\n5. **Structure and Organization:** The structure is logical but somewhat crowded. Too many points are packed into a small space, leading to information overload. Break the content into digestible chunks and prioritize key ideas.\n\n6. **Adherence to the 10-Sentence Limit:** Beyond trimming the number of sentences, ensure each sentence delivers maximum impact. Avoid redundancy, such as mentioning \"Azure manages infrastructure effortlessly\" and \"Azure supports popular Java frameworks to simplify your development journey,\" which overlap conceptually.\n\n7. **Suggestions for Improvement:**\n - Reduce sentence count to meet the 10-sentence limit while retaining the essential points.\n - Strengthen transitions to improve flow.\n - Rewrite the opening sentence to include a more compelling example or benefit.\n - Focus on fewer Azure services for clarity and emphasize their unique value instead of listing too many features.\n - Add a more engaging closing statement that calls the reader to action or leaves a memorable impression.\n\n**Actionable Revision Steps:**\n- Consolidate redundant ideas.\n- Use a more concise, focused approach to highlight Azure's benefits for Java developers.\n- Revise for a conversational yet professional tone that balances technical details with reader engagement.\n\nThis draft shows promise but requires significant refinement to meet the strict evaluation standards.",
"iteration": 2
},
{
"feedback": "Here is my detailed feedback on the draft:\n\n1. **Sentence Count**: The blog draft contains **10 sentences**, meeting the sentence limit requirement. However, adhering to the rule that all first iterations must receive a NEEDS_IMPROVEMENT rating, the draft will be evaluated critically.\n\n2. **Clarity and Flow of Ideas**: The draft is clear and flows logically, but it lacks specificity in some areas. For instance, phrases like \"Azure simplifies the process\" and \"streamline development workflows\" are somewhat vague. Readers may appreciate concrete examples or brief technical details to substantiate these claims. For example, how exactly does the integration with IntelliJ IDEA streamline workflows?\n\n3. **Engagement and Reader Interest**: While the draft is informative, it could enhance engagement by including a compelling hook. The opening sentence is functional but lacks the punch to immediately captivate readers. Consider starting with a thought-provoking question, statistic, or anecdote tied to Java and cloud computing.\n\n4. **Tone**: The tone is professional yet conversational, which works well for the target audience. However, certain phrases like \"letting you focus on what matters most—your code\" feel slightly generic. Adding a more nuanced observation tailored to Java developers could elevate the tone further.\n\n5. **Structure and Organization**: The structure is solid, but the final call-to-action (\"Ready to take your Java projects to the next level?\") is abrupt and lacks a sense of closure. A stronger conclusion could summarize the benefits discussed and tie them back to the opening idea, creating a more cohesive experience.\n\n6. **Suggestions for Improvement**: \n - Add more specificity to claims about Azure's tools and services to make the draft more actionable and informative. \n - Craft a more engaging opening sentence to draw readers in immediately. \n - Refine the conclusion to provide a sense of completion and reinforce the value proposition. \n - Consider rephrasing generic statements to better resonate with the Java developer audience. \n\nOverall, the draft has potential but needs refinement in its engagement techniques, specificity, and structural polish.",
"iteration": 3
}
],
"iterations": 3
},
"topic": "Java on Azure",
"content": "JAVA ON AZURE \n\nWhat if deploying your Java app to the cloud was as simple as a few clicks, instantly connecting you to millions of users worldwide? Java, the backbone of enterprise software development, pairs effortlessly with Microsoft Azure to transform how developers create, deploy, and scale cloud applications. Whether you're crafting microservices with Spring Boot or managing enterprise systems with Jakarta EE, Azure empowers you with tools and services designed for speed and reliability. \n\nTake IntelliJ IDEA integration, for example—it streamlines workflows by enabling developers to deploy directly from their IDE, eliminating the need for complex manual setups. Azure App Service simplifies operations even further, allowing you to publish Spring Boot applications with minimal configuration, while Azure Kubernetes Service (AKS) handles container orchestration seamlessly. These features let you focus on writing clean, efficient code without getting bogged down by infrastructure concerns. \n\nAzure also ensures your applications perform flawlessly with Application Insights, providing end-to-end monitoring for debugging and optimization. Built-in security measures like compliance certifications and encryption safeguard your data, while the pay-as-you-go pricing model lets you scale intelligently based on project demands. \n\nWith Azure, Java developers can embrace a cloud-first future without compromising on efficiency or control. Ready to unlock new possibilities for your Java projects? Explore how Azure can revolutionize your development journey today. "
}
Escalar Azure Container Apps
De forma predeterminada, la aplicación contenedora está configurada para usar cero réplicas mínimas y una regla de escalado HTTP para controlar 10 solicitudes por réplica. Para configurar la configuración de escalado, use el siguiente comando:
az containerapp update \
--resource-group $RESOURCE_GROUP \
--name $CONTAINER_APP_NAME \
--min-replicas 1 \
--max-replicas 10 \
--scale-rule-name http-scaler \
--scale-rule-type http \
--scale-rule-http-concurrency 15
Limpieza
Después de realizar las pruebas, use los siguientes comandos para quitar recursos:
az group delete \
--name $RESOURCE_GROUP \
--yes \
--no-wait
Resumen de la unidad
En esta unidad, implementó correctamente una aplicación Spring AI en Azure Container Apps, utilizando un alojamiento de contenedores escalable y sin servidor. Configuró las variables de entorno necesarias, creó un Dockerfile para compilar la imagen de la aplicación e implementó la aplicación contenedora mediante comandos de la CLI de Azure. Ha habilitado la identidad administrada para la autenticación segura en el servidor postgreSQL y ha configurado secretos y variables de entorno para la aplicación. Por último, ha comprobado la implementación mediante la prueba del punto de conexión de la aplicación y ha aprendido a limpiar los recursos después de las pruebas.