<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yoshio Terada</title>
    <description>The latest articles on DEV Community by Yoshio Terada (@yoshioterada).</description>
    <link>https://dev.to/yoshioterada</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F144564%2F29ff312d-746a-43a4-9fae-fb14f0f5cb4c.jpg</url>
      <title>DEV Community: Yoshio Terada</title>
      <link>https://dev.to/yoshioterada</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yoshioterada"/>
    <language>en</language>
    <item>
      <title>Securely Connecting Azure Container Apps to Azure OpenAI Using User Managed Identity</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Mon, 16 Sep 2024 02:15:16 +0000</pubDate>
      <link>https://dev.to/azure/securely-connecting-azure-container-apps-to-azure-openai-using-user-managed-identity-3369</link>
      <guid>https://dev.to/azure/securely-connecting-azure-container-apps-to-azure-openai-using-user-managed-identity-3369</guid>
      <description>&lt;p&gt;Today, I want to share two key points from this entry:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploying Java Applications to Azure Container Apps Without Containerization&lt;/li&gt;
&lt;li&gt;Secure Connection from Azure Container Apps to Azure OpenAI Using User Managed Identity&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The source code used here can be found in the following GitHub repository.&lt;br&gt;
&lt;a href="https://github.com/yoshioterada/Secure-OpenAI-Java-App-on-Azure-Container-Apps" rel="noopener noreferrer"&gt;GitHub: Secure-OpenAI-Java-App-on-Azure-Container-Apps&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Deploying Java Applications to Azure Container Apps Without Containerization
&lt;/h2&gt;

&lt;p&gt;On September 11, 2024, the announcement "&lt;a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/announcing-the-general-availability-of-java-experiences-on-azure/ba-p/4238294" rel="noopener noreferrer"&gt;Announcing the General Availability of Java Experiences on Azure Container Apps&lt;/a&gt;" was made.&lt;/p&gt;

&lt;p&gt;As detailed in the &lt;a href="https://learn.microsoft.com/azure/container-apps/java-overview" rel="noopener noreferrer"&gt;Java on Azure Container Apps overview&lt;/a&gt;, support for Java on Azure Container Apps has been enhanced. For example, Azure Container Apps now supports the following Spring components as managed services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eureka Server for Spring&lt;/li&gt;
&lt;li&gt;Config Server for Spring&lt;/li&gt;
&lt;li&gt;Admin for Spring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, as explained in the &lt;a href="https://learn.microsoft.com/azure/container-apps/java-get-started?pivots=war" rel="noopener noreferrer"&gt;Quickstart: Launch Your First Java Application in Azure Container Apps&lt;/a&gt;, Azure Container Apps now offers a new feature called &lt;code&gt;Cloud Build Service&lt;/code&gt;. This allows you to deploy applications directly to Azure Container Apps from Java artifacts like JAR or WAR files. The service automatically creates and deploys container images from the specified Java artifacts, eliminating the need to manually write Dockerfile container definitions or handle container builds and pushes.&lt;/p&gt;

&lt;p&gt;To achieve this with Azure Container Apps, you use the &lt;code&gt;az containerapp up&lt;/code&gt; command and specify the Java artifact as an argument. Detailed steps are provided later in the guide (see: &lt;code&gt;2.8 Creating an Azure Container Apps Instance&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This significantly simplifies deploying Java applications to Azure Container Apps. Azure Container Apps can also scale the number of instances from zero as needed, making it a highly convenient service. We encourage you to try it.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Securely Connecting Azure Container Apps to Azure OpenAI Using User Managed Identity
&lt;/h2&gt;

&lt;p&gt;In recent times, security measures have become increasingly important, and it is essential for businesses to build more secure systems. Microsoft recommends using Managed Identity for connections instead of password-based access when creating secure environments, such as production environments. This approach utilizes Microsoft Entra ID authentication.&lt;/p&gt;

&lt;p&gt;This method allows you to grant specific permissions for resources within a defined scope, making security management more flexible. For more details on Managed Identity, refer to the article "&lt;a href="https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview" rel="noopener noreferrer"&gt;What are Managed Identities for Azure Resources?&lt;/a&gt;". In this entry, I will clearly explain how to set up a User Managed Identity, step by step.&lt;/p&gt;

&lt;p&gt;Following these steps will help you understand how to configure it, and they can also serve as a reference for setting up other resources.&lt;/p&gt;
&lt;h3&gt;
  
  
  Steps to Set Up User Managed Identity
&lt;/h3&gt;

&lt;p&gt;To connect Azure Container Apps to Azure OpenAI using a User Managed Identity, follow these steps to set up the environment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set Environment Variables&lt;/li&gt;
&lt;li&gt;Create a Resource Group&lt;/li&gt;
&lt;li&gt;Create an Azure OpenAI Instance&lt;/li&gt;
&lt;li&gt;Create a User Managed Identity&lt;/li&gt;
&lt;li&gt;Assign Roles to the User Managed Identity for Azure OpenAI&lt;/li&gt;
&lt;li&gt;Create an Azure Container Apps Environment&lt;/li&gt;
&lt;li&gt;Develop a Spring Boot Web Application&lt;/li&gt;
&lt;li&gt;Create an Azure Container Apps Instance&lt;/li&gt;
&lt;li&gt;Assign the User Managed Identity to Azure Container Apps&lt;/li&gt;
&lt;li&gt;Verify the Setup&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  2.1. Set Environment Variables
&lt;/h3&gt;

&lt;p&gt;When setting up the environment, configure environment variables to avoid repetitive input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESOURCE_GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshio-OpenAI-rg
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eastus2
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AZURE_OPENAI_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yt-secure-openai
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_DEPLOY_MODEL_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gpt-4o
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER_MANAGED_IDENTITY_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshio-user-managed-id
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SUBSCRIPTION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az account show &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below are the environment variable names and their descriptions. If you need to change the names to suit your environment, please refer to the descriptions below to modify each resource name accordingly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment Variable Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RESOURCE_GROUP&lt;/td&gt;
&lt;td&gt;Name of the resource group to create&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOCATION&lt;/td&gt;
&lt;td&gt;Location where the environment will be set up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USER_MANAGED_IDENTITY_NAME&lt;/td&gt;
&lt;td&gt;Name of the User Managed Identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AZURE_OPENAI_NAME&lt;/td&gt;
&lt;td&gt;Name of the Azure OpenAI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OPENAI_DEPLOY_MODEL_NAME&lt;/td&gt;
&lt;td&gt;Name of the AI model to be deployed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SUBSCRIPTION&lt;/td&gt;
&lt;td&gt;Subscription ID to be used&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2.2. Create a Resource Group
&lt;/h3&gt;

&lt;p&gt;First, create a resource group in the Azure environment. Use the &lt;code&gt;--location&lt;/code&gt; argument to specify the Azure region where it will be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az group create --name $RESOURCE_GROUP --location $LOCATION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3. Create an Azure OpenAI Instance
&lt;/h3&gt;

&lt;p&gt;Next, create an Azure OpenAI instance by running the &lt;code&gt;az cognitiveservices account create&lt;/code&gt; command. In this step, specify &lt;code&gt;--kind OpenAI&lt;/code&gt; and &lt;code&gt;--custom-domain&lt;/code&gt; for the instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az cognitiveservices account create \
  --name $AZURE_OPENAI_NAME \
  --resource-group $RESOURCE_GROUP \
  --kind OpenAI \
  --custom-domain $AZURE_OPENAI_NAME \
  --sku S0 \
  --location $LOCATION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It is crucial to specify &lt;code&gt;--custom-domain&lt;/code&gt; when creating an Azure OpenAI instance.&lt;br&gt;
If omitted, a &lt;code&gt;region endpoint&lt;/code&gt; like &lt;code&gt;https://eastus2.api.cognitive.microsoft.com/&lt;/code&gt; will be automatically generated. As outlined in "&lt;a href="https://learn.microsoft.com/azure/ai-services/authentication#authenticate-with-microsoft-entra-id" rel="noopener noreferrer"&gt;Authenticate with Microsoft Entra ID&lt;/a&gt;", you cannot perform authentication using Microsoft Entra ID, in this case Managed Identity, without specifying this option. To enable Managed Identity authentication, you need to specify &lt;code&gt;--custom-domain&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, deploy the OpenAI model to your newly created Azure OpenAI instance using the &lt;code&gt;az cognitiveservices account deployment create&lt;/code&gt; command. Here, specify the model name with &lt;code&gt;--model-name&lt;/code&gt; and the model version with &lt;code&gt;--model-version&lt;/code&gt;. You should also define the service capacity using &lt;code&gt;--sku-capacity&lt;/code&gt; and select the service plan with &lt;code&gt;--sku-name&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az cognitiveservices account deployment create \
  --name $AZURE_OPENAI_NAME \
  --resource-group  $RESOURCE_GROUP \
  --deployment-name $OPENAI_DEPLOY_MODEL_NAME \
  --model-name $OPENAI_DEPLOY_MODEL_NAME \
  --model-version "2024-08-06"  \
  --model-format OpenAI \
  --sku-capacity "20" \
  --sku-name "GlobalStandard"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, the creation of the Azure OpenAI instance is complete. After creating the instance, store the necessary information for your Java program implementation and other operations in environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPEN_AI_RESOURCE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az cognitiveservices account list &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"[0].id"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPEN_AI_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az cognitiveservices account show &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_OPENAI_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"properties.endpoint"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPEN_AI_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az cognitiveservices account keys list &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_OPENAI_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                    &lt;span class="nt"&gt;--query&lt;/span&gt; key1 &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are setting the following environment variables:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment Variable Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OPEN_AI_RESOURCE_ID&lt;/td&gt;
&lt;td&gt;Resource ID of OpenAI&lt;br&gt; (Needed for role assignment scope)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OPEN_AI_ENDPOINT&lt;/td&gt;
&lt;td&gt;Endpoint of OpenAI&lt;br&gt; (Required for Java app connection)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OPEN_AI_ACCESS_KEY&lt;/td&gt;
&lt;td&gt;Access key for OpenAI&lt;br&gt; (Needed for Java app development locally)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2.4. Create a User Managed Identity
&lt;/h3&gt;

&lt;p&gt;Now that the Azure OpenAI instance is set up, the next step is to create a User Managed Identity. Use the &lt;code&gt;az identity create&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az identity create -g $RESOURCE_GROUP -n $USER_MANAGED_IDENTITY_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the User Managed Identity is created, retrieve the necessary information for future command execution and Java program usage, and assign it to the environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER_MANAGED_ID_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az identity list &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"[0].clientId"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER_MANAGED_ID_PRINCIPAL_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az identity list &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"[0].principalId"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER_MANAGED_ID_RESOURCE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az identity list &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"[0].id"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                                            &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is an explanation of each environment variable's value and its usage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment Variable Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;USER_MANAGED_ID_CLIENT_ID&lt;/td&gt;
&lt;td&gt;Client ID of the User Managed Identity&lt;br&gt; (Needed for Java app implementation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USER_MANAGED_ID_PRINCIPAL_ID&lt;/td&gt;
&lt;td&gt;Principal ID of the User Managed Identity&lt;br&gt; (Required for role assignment)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USER_MANAGED_ID_RESOURCE_ID&lt;/td&gt;
&lt;td&gt;Resource ID of the User Managed Identity&lt;br&gt; (Needed for assigning ID to Container Apps)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2.5. Assign Roles to User Managed Identity for Azure OpenAI
&lt;/h3&gt;

&lt;p&gt;Use the &lt;code&gt;az role assignment create&lt;/code&gt; command to assign a role to the User Managed Identity, allowing it to interact with the OpenAI resource using the &lt;code&gt;Cognitive Services OpenAI User&lt;/code&gt; permission.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$OPEN_AI_RESOURCE_ID&lt;/code&gt; represents the OpenAI resource ID, and the role is assigned specifically to that resource. This method grants only the necessary permissions for the app to run, enhancing security by avoiding unnecessary permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az role assignment create --assignee $USER_MANAGED_ID_PRINCIPAL_ID \
                              --scope $OPEN_AI_RESOURCE_ID \
                              --role "Cognitive Services OpenAI User"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the roles mentioned, you can also assign the following roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cognitive Services OpenAI User&lt;/li&gt;
&lt;li&gt;Cognitive Services OpenAI Contributor&lt;/li&gt;
&lt;li&gt;Cognitive Services Contributor&lt;/li&gt;
&lt;li&gt;Cognitive Services Usages Reader&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For detailed information about the capabilities of each role, please refer to the &lt;a href="https://learn.microsoft.com/azure/ai-services/openai/how-to/role-based-access-control" rel="noopener noreferrer"&gt;Role-based Access Control for Azure OpenAI Service&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.6. Create an Azure Container Apps Environment
&lt;/h3&gt;

&lt;p&gt;Next, create an Azure Container Apps Environment. To do this using the Azure CLI, you need to register additional extensions and providers. If you haven't executed the following commands before, please execute them now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az upgrade
az extension add --name containerapp --upgrade -y
az provider register --namespace Microsoft.Web
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, define the name of the Azure Container Apps Environment as an environment variable. Choose a name that suits your environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_ENVIRONMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YTContainerEnv3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, run the &lt;code&gt;az containerapp env create&lt;/code&gt; command to set up the environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az containerapp env create --name $CONTAINER_ENVIRONMENT \
                               --enable-workload-profiles \
                               -g $RESOURCE_GROUP \
                               --location $LOCATION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.7. Creating a Spring Boot Web Application
&lt;/h3&gt;

&lt;p&gt;With the Azure OpenAI and Azure Container Apps Environment set up, we will now create a Java project to implement a simple app that invokes an OpenAI model from a Java Application. We will use Spring Boot for this implementation.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.7.1 Creating a Spring Boot Project
&lt;/h4&gt;

&lt;p&gt;Execute the following command to create a Spring Boot project. After creating and downloading the project, unzip the archive to extract its contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://start.spring.io/starter.zip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maven-project &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;java &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;bootVersion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.3.3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;baseDir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Yoshio-AI-App-Spring-Boot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.yoshio3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Yoshio-AI-App &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myproject &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;packageName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.yoshio3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; YoshioAIProject.zip

unzip YoshioAIProject.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will generate a project with the following directory structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── yoshio3
    │   │           └── MyprojectApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── yoshio3
                    └── MyprojectApplicationTests.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.7.2 Editing the pom.xml Project File
&lt;/h4&gt;

&lt;p&gt;Add the following dependencies to the &lt;code&gt;pom.xml&lt;/code&gt; file located in the root directory. This will include the necessary libraries for connecting to and authenticating with OpenAI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    ......
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.azure&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;azure-ai-openai&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0-beta.11&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.azure&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;azure-identity&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.13.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.16&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;ch.qos.logback&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;logback-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;ch.qos.logback&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;logback-classic&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.7.3 Implementing a RESTful Endpoint (Main Part)
&lt;/h4&gt;

&lt;p&gt;Next, create an &lt;code&gt;AIChatController.java&lt;/code&gt; file in the &lt;code&gt;src/main/java/com/yoshio3&lt;/code&gt; directory. Implement the following code to define a RESTful endpoint that queries OpenAI upon receiving a request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.yoshio3&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RestController&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.OpenAIClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.OpenAIClientBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.ChatCompletions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.ChatCompletionsOptions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.ChatRequestAssistantMessage&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.ChatRequestMessage&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.ChatRequestSystemMessage&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.ChatRequestUserMessage&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.core.credential.AzureKeyCredential&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.identity.ManagedIdentityCredential&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.identity.ManagedIdentityCredentialBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.fasterxml.jackson.core.JsonProcessingException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.fasterxml.jackson.databind.ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.PostMapping&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RequestBody&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;


&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AIChatController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="no"&gt;LOGGER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AIChatController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${USER_MANAGED_ID_CLIENT_ID}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userManagedIDClientId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${OPENAI_ENDPOINT}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;openAIEndpoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${OPENAI_KEY}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;openAIKey&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;OPEN_AI_CHAT_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-4o"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * This API is used to chat with OpenAI's GPT-4 model. And if user ask somethings, it will
     * return the message with Pirate language.
     * 
     * Ex. You can invoke the API by using the following command: curl -X POST
     * http://localhost:8080/askAI -H "Content-Type: application/json" -d '{"message":"Please tell
     * me about the appeal of Spring Boot in Japanese."}'
     * 
     * @param message RequestMessage
     * @return String Response from OpenAI
     */&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/askAI"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;RequestMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getResponseFromOpenAI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * This method is used to get the response from OpenAI.
     * 
     * For production environment, you can use Managed Identity to authenticate with OpenAI. If you
     * want to use Managed Identity, please use the ManagedIdentityCredentialBuilder.
     * 
     * For local development, you can use AzureKeyCredential to authenticate with OpenAI.
     * 
     * @param message RequestMessage
     * @return String Response from OpenAI
     */&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getResponseFromOpenAI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Create OpenAI client with User Managed Identity&lt;/span&gt;
            &lt;span class="nc"&gt;ManagedIdentityCredential&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagedIdentityCredentialBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userManagedIDClientId&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;OpenAIClient&lt;/span&gt; &lt;span class="n"&gt;openAIClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIClientBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;openAIEndpoint&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;buildClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Create OpenAI client without Managed Identity (For local development)&lt;/span&gt;
            &lt;span class="c1"&gt;// OpenAIClient openAIClient = new OpenAIClientBuilder().endpoint(openAIEndpoint)&lt;/span&gt;
            &lt;span class="c1"&gt;// .credential(new AzureKeyCredential(openAIKey)).buildClient();&lt;/span&gt;

            &lt;span class="c1"&gt;// Create Chat Request Messages&lt;/span&gt;
            &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChatRequestMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chatMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;chatMessages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatRequestSystemMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You are a helpful assistant. You will talk like a pirate."&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;chatMessages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatRequestUserMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Can you help me?"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;chatMessages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatRequestAssistantMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Of course, me hearty! What can I do for ye?"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;chatMessages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatRequestUserMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="nc"&gt;ChatCompletionsOptions&lt;/span&gt; &lt;span class="n"&gt;chatCompletionsOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatCompletionsOptions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatMessages&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Invoke OpenAI Chat API&lt;/span&gt;
            &lt;span class="nc"&gt;ChatCompletions&lt;/span&gt; &lt;span class="n"&gt;chatCompletions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openAIClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getChatCompletions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;OPEN_AI_CHAT_MODEL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatCompletionsOptions&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;chatCompletions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getChoices&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getContent&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;StackTraceElement&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLocalizedMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;cause&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCause&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cause&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCause&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StackTraceElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the &lt;code&gt;OpenAIClient&lt;/code&gt; instance is described in two different ways. The current code uses &lt;code&gt;ManagedIdentityCredential&lt;/code&gt; to connect to Azure OpenAI with a User Managed Identity. This code works only when running in an Azure environment and won't work in a local or non-Azure environment.&lt;/p&gt;

&lt;p&gt;During development, you need to test and verify functionality locally. In such cases, a User Managed Identity cannot be used. Instead, connect using the OpenAI Access Key by uncommenting the line with &lt;code&gt;AzureKeyCredential(openAIKey)&lt;/code&gt; to create the OpenAIClient instance.&lt;/p&gt;

&lt;p&gt;Additionally, &lt;code&gt;SLF4J&lt;/code&gt; and &lt;code&gt;Logback&lt;/code&gt; are used for logging in the implementation. Configure them by creating a &lt;code&gt;logback-spring.xml&lt;/code&gt; file in the &lt;code&gt;/src/main/resources&lt;/code&gt; directory. While detailed logging configuration is not covered here, the original code is available on GitHub for reference if needed.&lt;/p&gt;

&lt;p&gt;Finally, here's a brief overview of the code: When a question or message is received from a user, it responds in a pirate tone as defined by &lt;code&gt;SYSTEM&lt;/code&gt;. Enjoy the pirate-style replies!&lt;/p&gt;

&lt;h4&gt;
  
  
  2.7.4 Defining the JSON Format for Endpoint Reception
&lt;/h4&gt;

&lt;p&gt;Next, define the JSON data format to be sent to this RESTful service. To process messages like &lt;code&gt;{"message":"What is the benefit of Spring Boot"}&lt;/code&gt; in the HTTP request body, define the following class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.yoshio3&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RequestMessage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we have completed the minimal code necessary for operation verification.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.7.5 Application Configuration
&lt;/h4&gt;

&lt;p&gt;Next, configure the settings to connect to Azure OpenAI. During the systems setup from sections 2.1 to 2.6, all required information was stored in environment variables. Execute the following command to retrieve the necessary information in the Java program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"USER_MANAGED_ID_CLIENT_ID"&lt;/span&gt; : &lt;span class="nv"&gt;$USER_MANAGED_ID_CLIENT_ID&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OPEN_AI_ENDPOINT"&lt;/span&gt; : &lt;span class="nv"&gt;$OPEN_AI_ENDPOINT&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OPEN_AI_ACCESS_KEY"&lt;/span&gt; : &lt;span class="nv"&gt;$OPEN_AI_ACCESS_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write the execution results above into the &lt;code&gt;application.properties&lt;/code&gt; file located in the &lt;code&gt;/src/main/resources/&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.application.name=AI-Chatbot
logging.level.root=INFO
logging.level.org.springframework.web=INFO

USER_MANAGED_ID_CLIENT_ID=********-****-****-****-************
OPENAI_ENDPOINT=https://********.openai.azure.com/
OPENAI_KEY=********************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;OPENAI_KEY&lt;/code&gt; is the access key for OpenAI. Use it only during development in a development environment and avoid using it in a production environment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  2.7.6 (Optional): Verifying Operation in a Local Environment
&lt;/h4&gt;

&lt;p&gt;To verify if the Java program works locally, swap the comments in the &lt;code&gt;OpenAIClient&lt;/code&gt; instance creation part of the &lt;code&gt;AIChatController&lt;/code&gt; class code and run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ManagedIdentityCredential credential = new ManagedIdentityCredentialBuilder().clientId(userManagedIDClientId).build();&lt;/span&gt;
&lt;span class="c1"&gt;// OpenAIClient openAIClient = new OpenAIClientBuilder().credential(credential)&lt;/span&gt;
&lt;span class="c1"&gt;//                    .endpoint(openAIEndpoint).buildClient();&lt;/span&gt;

 &lt;span class="nc"&gt;OpenAIClient&lt;/span&gt; &lt;span class="n"&gt;openAIClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIClientBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;openAIEndpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AzureKeyCredential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;openAIKey&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;buildClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making the changes, execute the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the Spring Boot application starts successfully, it will be listening on port 8080. Use the following &lt;code&gt;curl&lt;/code&gt; command to verify if you can query Azure OpenAI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/askAI &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"message":"What is the benefit of the Spring Boot?"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response will vary each time you run the command, but it will reply in a pirate tone, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Aye, Captain! Let me explain the benefits of Spring Boot.
Spring Boot is a framework that aids rapid application development. 
It allows you to create standalone applications with minimal configuration.

It also comes with auto-configuration, reducing manual setup. Managing dependencies is easy, and it includes commonly used libraries.
It's fast to start up, easy to deploy, and suitable for cloud operations. 

It's a powerful tool for boosting developer productivity.
Anything else I can assist with?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After completing local verification, revert the changes to generate the &lt;code&gt;OpenAIClient&lt;/code&gt; instance using &lt;code&gt;ManagedIdentityCredential&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.7.7 Building the Application and Creating Artifacts
&lt;/h4&gt;

&lt;p&gt;Once these steps are complete, build the application and create the artifacts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon building the project, the artifacts will be created in the &lt;code&gt;target&lt;/code&gt; directory. Here, the Spring Boot application is created as &lt;code&gt;Yoshio-AI-App-0.0.1-SNAPSHOT.jar&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; target 
total 40876
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 teradayoshio wheel 41847613  9 14 14:52 Yoshio-AI-App-0.0.1-SNAPSHOT.jar
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 teradayoshio wheel     7003  9 14 14:52 Yoshio-AI-App-0.0.1-SNAPSHOT.jar.original
drwxr-xr-x 5 teradayoshio wheel      160  9 14 20:34 classes
drwxr-xr-x 3 teradayoshio wheel       96  9 14 14:52 generated-sources
drwxr-xr-x 3 teradayoshio wheel       96  9 14 14:52 generated-test-sources
drwxr-xr-x 3 teradayoshio wheel       96  9 14 14:52 maven-archiver
drwxr-xr-x 3 teradayoshio wheel       96  9 14 14:52 maven-status
drwxr-xr-x 4 teradayoshio wheel      128  9 14 14:52 surefire-reports
drwxr-xr-x 3 teradayoshio wheel       96  9 14 20:34 test-classes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.8. Creating an Azure Container Apps Instance
&lt;/h3&gt;

&lt;p&gt;Now that the implementation of the Java program is complete, let's deploy this Java Application to Azure Container Apps.&lt;/p&gt;

&lt;p&gt;Specify the name for the container application using the environment variable &lt;code&gt;CONTAINER_APP_NAME&lt;/code&gt;. Define the path and filename of the Spring Boot artifact with &lt;code&gt;JAR_FILE_PATH_AND_NAME&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshio-ai-app
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;JAR_FILE_PATH_AND_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./target/Yoshio-AI-App-0.0.1-SNAPSHOT.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As explained in "&lt;a href=""&gt;1. Deploying Java Applications to Azure Container Apps Without Containerization&lt;/a&gt;", you no longer need to create and deploy your own container image when deploying to Azure Container Apps. We only have the Java artifact &lt;code&gt;Yoshio-AI-App-0.0.1-SNAPSHOT.jar&lt;/code&gt;, and we will deploy based on this.&lt;/p&gt;

&lt;p&gt;To do so, use the &lt;code&gt;az containerapp up&lt;/code&gt; command. As you can see from the arguments, you only need to specify &lt;code&gt;--artifact $JAR_FILE_PATH_AND_NAME&lt;/code&gt;, without any container image arguments. This command will automatically set up the build environment, build the container, and deploy it.&lt;/p&gt;

&lt;p&gt;Please execute the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az containerapp up \
  --name $CONTAINER_APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --subscription $SUBSCRIPTION \
  --location $LOCATION \
  --environment $CONTAINER_ENVIRONMENT \
  --artifact $JAR_FILE_PATH_AND_NAME \
  --ingress external \
  --target-port 8080 \
  --env-vars AZURE_LOG_LEVEL=2 \
  --query properties.configuration.ingress.fqdn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can slightly customize the container creation. Use the environment variables provided below as needed:&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/container-apps/java-build-environment-variables" rel="noopener noreferrer"&gt;Build Environment Variables for Java in Azure Container Apps&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.9. Assigning a User Managed Identity to Azure Container Apps
&lt;/h3&gt;

&lt;p&gt;Having deployed the app to Azure Container Apps, the final step is to apply a User Managed Identity to the container we created. Execute the &lt;code&gt;az containerapp identity assign&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az containerapp identity assign --name $CONTAINER_APP_NAME \
                                    --resource-group $RESOURCE_GROUP \
                                    --user-assigned $USER_MANAGED_ID_RESOURCE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, the User Managed Identity configuration is complete.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.10. Verifying Operation
&lt;/h3&gt;

&lt;p&gt;Now that all the settings are complete, let's verify the operation. First, obtain the FQDN host name assigned to the container's Ingress.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REST_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az containerapp show &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_APP_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
              &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
              &lt;span class="nt"&gt;--query&lt;/span&gt; properties.configuration.ingress.fqdn &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, append the RESTful endpoint URL to the obtained host name and connect to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://&lt;span class="nv"&gt;$REST_ENDPOINT&lt;/span&gt;/askAI &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"message":"What is Spring Boot? Please explain around 200 words?"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each time it is executed, the response may vary, but you can expect results like those below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Arrr, Spring Boot be a powerful framework fer buildin' Java applications with minimal fuss, savvy? 
It sails under the banner of the larger Spring ecosystem, providin' a swift and easy approach fer creatin' scalable and stand-alone web apps.

Ye see, it comes with embedded servers like Tomcat or Jetty, meanin' ye don't have the hassle of deployin' to external servers. 
Spring Boot simplifies the setup by makin' configurations automatic, allowin' developers to focus on writin' their code without worryin' about the boilerplate.

It also hoists the flag of convention over configuration, offerin' defaults that make gettin’ started as smooth as a voyage with favorable winds. 
Should ye need to adjust yer sails, customization be available through its easy-to-use properties.

And if ye treasure quick development, Spring Boot supports ye well with its rich assortment of pre-configured starters, integratin' smoothly with other technologies like databases and messaging systems.

In essence, Spring Boot be a trusty vessel fer any sea-farin' coder seekin' speed, efficiency, and a treasure chest of features in their Java web applications. 
Aye, it be a boon to all developers, whether seasoned or green as a fresh landlubber!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.11. Reusing the Same User Managed Identity to Access Azure OpenAI from Other Azure Resources
&lt;/h3&gt;

&lt;p&gt;Previously, we discussed how to apply a &lt;code&gt;User Managed Identity&lt;/code&gt; to &lt;code&gt;Azure Container Apps&lt;/code&gt; to connect to &lt;code&gt;Azure OpenAI&lt;/code&gt;. However, this User Managed Identity can also be reused by other services.&lt;/p&gt;

&lt;p&gt;In other words, applications deployed on other Azure resources can use the same User Managed Identity to connect to Azure OpenAI.&lt;/p&gt;

&lt;p&gt;Some resources allow you to specify this identity during creation, while for others, you can assign it later.&lt;/p&gt;

&lt;p&gt;Below, we demonstrate how to assign a User Managed Identity to existing Azure resources, except for Azure Container Instances.&lt;/p&gt;

&lt;h4&gt;
  
  
  For Azure VM
&lt;/h4&gt;

&lt;p&gt;To assign a User Managed Identity to an Azure VM, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az vm identity assign -g $RESOURCE_GROUP \
                      -n $VM_NAME \
                      --identities $USER_MANAGED_ID_RESOURCE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  For Azure App Service
&lt;/h4&gt;

&lt;p&gt;To assign a User Managed Identity to an Azure App Service, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az webapp identity assign -g $RESOURCE_GROUP \
                          --name $APP_SERVICE_NAME \
                          --identities $USER_MANAGED_ID_RESOURCE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  For Azure Functions
&lt;/h4&gt;

&lt;p&gt;To assign a User Managed Identity to Azure Functions, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az functionapp identity assign -g $RESOURCE_GROUP \
                               -n $AZURE_FUNCTION_NAME \
                               --identities $USER_MANAGED_ID_RESOURCE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  For Azure Container Instances
&lt;/h4&gt;

&lt;p&gt;For Azure Container Instances, you can assign a User Managed Identity during the instance creation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az container create \
                        --resource-group $RESOURCE_GROUP  \
                        --name $CONTAINER_INSTANCE_NAME \
                        --image $CONTAINER_IMAGE \
                        --assign-identity $USER_MANAGED_ID_RESOURCE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  For Azure Kubernetes Service
&lt;/h4&gt;

&lt;p&gt;To assign a User Managed Identity to Azure Kubernetes Service, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks update \
                    -g $RESOURCE_GROUP \
                    --name $AKS_CLUSTER_NAME \
                    --enable-managed-identity \
                    --assign-identity $USER_MANAGED_ID_RESOURCE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like this, by using a User Managed Identity, you can securely connect to target resources across different Azure services by reusing correctly configured access roles.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.12. Comparing Access Keys and User Managed Identities from a Security Perspective
&lt;/h3&gt;

&lt;p&gt;This section explains the security differences between using Access Keys and User Managed Identities for Azure OpenAI.&lt;/p&gt;

&lt;p&gt;When using a User Managed Identity, you specify the &lt;code&gt;client ID&lt;/code&gt; of the User Managed Identity when creating an instance of the &lt;code&gt;ManagedIdentityCredential&lt;/code&gt; class in your Java Application. This &lt;code&gt;client ID&lt;/code&gt; value is set as an environment variable &lt;code&gt;$USER_MANAGED_ID_CLIENT_ID&lt;/code&gt; when the User Managed Identity is created.&lt;/p&gt;

&lt;p&gt;At first glance, it might seem that this is the only critical piece of information needed for the connection, aside from the endpoint URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ManagedIdentityCredential&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagedIdentityCredentialBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userManagedIDClientId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;OpenAIClient&lt;/span&gt; &lt;span class="n"&gt;openAIClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIClientBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;openAIEndpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's consider the impact of a leaked &lt;code&gt;client ID&lt;/code&gt; versus a leaked &lt;code&gt;Access Key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;Access Key&lt;/code&gt; is like a regular password. If it is leaked, anyone who knows the password can access the resource. In the case of Azure OpenAI, this means anyone could use AI models like GPT-4. If the network is publicly accessible, the impact could be even greater.&lt;/p&gt;

&lt;p&gt;On the other hand, if the &lt;code&gt;client ID&lt;/code&gt; is leaked, the impact is limited. This is because the &lt;code&gt;client ID&lt;/code&gt; alone cannot connect to Azure OpenAI. To use a User Managed Identity, the service must be running on Azure. Even if Azure OpenAI is publicly accessible, you cannot connect from a local environment or over a network using a Java application.&lt;/p&gt;

&lt;p&gt;Additionally, the following role assignment is configured for the User Managed Identity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az role assignment create --assignee $USER_MANAGED_ID_PRINCIPAL_ID \
    --scope $OPEN_AI_RESOURCE_ID \
    --role "Cognitive Services OpenAI User" 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets what actions can be performed using this user ID. Here, the &lt;code&gt;Cognitive Services OpenAI User&lt;/code&gt; role is granted for Azure OpenAI services, limiting permissions to operations within Azure OpenAI.&lt;/p&gt;

&lt;p&gt;This means that even with this ID, you cannot perform administrative actions like adding models, not just across Azure but even within Azure OpenAI.&lt;/p&gt;

&lt;p&gt;Furthermore, to use this user ID, you must log in to Azure as an administrator, and only the resources specified by the administrator can be accessed within the scope of this ID's permissions.&lt;/p&gt;

&lt;p&gt;In summary, compared to the impact of a leaked access key, a leaked client ID requires multiple steps to exploit, making it more secure.&lt;/p&gt;

&lt;p&gt;For these reasons, User Managed Identities offer a more secure way to manage operations than access keys. We encourage you to use Managed Identities to build a secure environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 Summary
&lt;/h2&gt;

&lt;p&gt;In this guide, we walked through a detailed, step-by-step process for securely connecting Azure Container Apps to Azure OpenAI using a User Managed Identity. While setting up a User Managed Identity might seem cumbersome at first, it offers the significant advantage of reusability. If your systems are few or flexibility isn't a major concern, a System Managed Identity might be preferable.&lt;/p&gt;

&lt;p&gt;However, as the number of systems increases, User Managed Identities become very handy. After creating a User Managed Identity and assigning roles, you can reuse the same ID across various services like Azure App Service, Azure Functions, and Azure Kubernetes Services. The more systems or services you manage, the more beneficial this becomes.&lt;/p&gt;

&lt;p&gt;Please try using Managed Identities to effectively build secure environments.&lt;/p&gt;

</description>
      <category>java</category>
      <category>security</category>
      <category>managedidentity</category>
      <category>azurecontainerapps</category>
    </item>
    <item>
      <title>Comparison of Two Methods for Deploying Azure Functions to Azure Container Apps</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Tue, 10 Sep 2024 15:51:51 +0000</pubDate>
      <link>https://dev.to/azure/comparison-of-two-methods-for-deploying-azure-functions-to-azure-container-apps-2o7o</link>
      <guid>https://dev.to/azure/comparison-of-two-methods-for-deploying-azure-functions-to-azure-container-apps-2o7o</guid>
      <description>&lt;p&gt;Yesterday, I wrote an article titled "&lt;a href="https://dev.to/azure/deploying-a-java-azure-function-on-azure-container-apps-1oj"&gt;Deploying a Java Azure Function on Azure Container Apps&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;In that entry, I mentioned using the &lt;code&gt;Azure's integrated management capabilities&lt;/code&gt; and I want to clarify what that means and how it differs from previous methods in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old Method: Creating with &lt;code&gt;az containerapp create&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Azure Container Apps is one of Azure's container execution environments, allowing you to run any containerized service. Previously, if you wanted to run Azure Functions in Azure Container Apps, you would create an instance using the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az containerapp create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; general-container-app &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--environment&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_ENVIRONMENT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--registry-server&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_SERVER&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--image&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_SERVER&lt;/span&gt;/&lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--target-port&lt;/span&gt; 80 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--ingress&lt;/span&gt; external &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--query&lt;/span&gt; properties.configuration.ingress.fqdn


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After executing the command, you would see a message like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Container app created. Access your app at https://general-container-app.niceocean-********.eastus.azurecontainerapps.io/


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You could then use a &lt;code&gt;curl&lt;/code&gt; command to connect to your Azure Functions service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl https://general-container-app.niceocean-&lt;span class="k"&gt;********&lt;/span&gt;.eastus.azurecontainerapps.io/api/httpexample?name&lt;span class="o"&gt;=&lt;/span&gt;World


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Upon accessing the Azure Container Apps Environment, you would see that the &lt;code&gt;general-container-app&lt;/code&gt; is created as a &lt;code&gt;Container App&lt;/code&gt;, and this management interface is available for any deployed containerized application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7h5f4c76bdyh0sj3fs89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7h5f4c76bdyh0sj3fs89.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/yoshioterada/Azure-Functions-Deploy-To-Azure-Container-Apps/main/images/ACA-Instance-for-Azure-Functions.png" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/yoshioterada/Azure-Functions-Deploy-To-Azure-Container-Apps/main/images/ACA-Instance-for-Azure-Functions.png&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New Method: Creating with &lt;code&gt;az functionapp create&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The new method allows you to create Azure Functions in Azure Container Apps using the &lt;code&gt;az functionapp create&lt;/code&gt; command instead of &lt;code&gt;az containerapp create&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az functionapp create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_FUNCTION_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--environment&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_ENVIRONMENT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--storage-account&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--workload-profile-name&lt;/span&gt; &lt;span class="s2"&gt;"Consumption"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--max-replicas&lt;/span&gt; 15 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--min-replicas&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--functions-version&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--runtime&lt;/span&gt; java &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--image&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_SERVER&lt;/span&gt;/&lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--assign-identity&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this command, your Azure Functions will be created in Azure Container Apps, and the management interface will clearly show that it is an &lt;code&gt;Function App&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dm8x5ch0h0koffmvc29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dm8x5ch0h0koffmvc29.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means Azure Functions can now be managed through a dedicated &lt;code&gt;Azure Functions management interface&lt;/code&gt;, making it difference from other container application.&lt;/p&gt;

&lt;p&gt;However, there are some differences between the management features provided in Azure App Service and those available for Azure Functions on Container Apps. For instance, certain functionalities like diagnostic tools, deployment features, and others may not be available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy68gs8islmfub8sv3j5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy68gs8islmfub8sv3j5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference: Azure Functions on App Service (Portal)
&lt;/h3&gt;

&lt;p&gt;For comparison, here’s the management interface for Azure Functions deployed on Azure App Service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8oaa3uzwybcwxf4lpnx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8oaa3uzwybcwxf4lpnx0.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The differences in management capabilities between App Service and Azure Container Apps can include:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fli32on69uylzarz1gr9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fli32on69uylzarz1gr9f.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick up:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

- Diagnose and solve problems
- Microsoft Defender for Cloud
- Events (preview)
- Log stream
- Deployment
- App Service plan
- Development Tools
- Monitoring
- Support + troubleshooting


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Some may think that the lack of certain features suggests missing functionality.&lt;/p&gt;

&lt;p&gt;However, when deployed to Azure Container Apps, the operating environment is container-based, which changes deployment and management methods. Features not included in the Azure Functions management interface will need to be managed separately through the Azure Container Apps interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Management of Containers in Azure Container Apps
&lt;/h2&gt;

&lt;p&gt;When using the &lt;code&gt;az functionapp create&lt;/code&gt; command to create an Azure Functions instance on Azure Container Apps, a new resource group is automatically created that houses the container instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylpmo99a5gr05imcy06p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylpmo99a5gr05imcy06p.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my environment, the resource group name follows this convention: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$CONTAINER_ENVIRONMENT_FunctionApps_$UUID&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will see that an Azure Container Apps instance named after your specified &lt;code&gt;$AZURE_FUNCTION_NAME&lt;/code&gt; has been generated.&lt;/p&gt;

&lt;p&gt;When you click on this instance, you'll be directed to a management interface specific to Azure Container Apps, where the Azure Functions run as container instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F381ebk51gw3qzrfq2auu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F381ebk51gw3qzrfq2auu.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Azure Container Apps provides different CI/CD and deployment methods than Azure App Service. It also allows for features offered at the container level, such as Dapr and Service Connector, which can be utilized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Previously, it was possible to run Azure Functions by containerizing them in a container execution environment, but there was no dedicated management interface for Azure Functions.&lt;/p&gt;

&lt;p&gt;With this new method, Azure Functions and Azure Container Apps have integrated, offering a container environment with an associated Azure Functions management interface.&lt;/p&gt;

&lt;p&gt;I know some customers operate Azure Functions Container on Azure Kubernetes Service (AKS). Previously, they lacked a dedicated management interface. However, by deploying to Azure Container Apps, they can now use Azure Functions management while enjoying the simplicity of managing Azure Container Apps compared to managing operations on AKS.&lt;/p&gt;

&lt;p&gt;The methods for deploying Azure Functions to Azure Container Apps are likely to evolve further. I look forward to seeing how this develops.&lt;/p&gt;

</description>
      <category>java</category>
      <category>functions</category>
      <category>container</category>
    </item>
    <item>
      <title>Deploying a Java Azure Function on Azure Container Apps</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Mon, 09 Sep 2024 13:52:38 +0000</pubDate>
      <link>https://dev.to/azure/deploying-a-java-azure-function-on-azure-container-apps-1oj</link>
      <guid>https://dev.to/azure/deploying-a-java-azure-function-on-azure-container-apps-1oj</guid>
      <description>&lt;p&gt;Azure Functions provides integrated support for developing, deploying, and managing containerized function apps on Azure Container Apps. This makes it easier to run and manage Azure Functions using the integrated Azure management portal, compared to running Azure Functions independently in container environments like Azure Kubernetes Service (AKS). Additionally, by leveraging features provided by Azure Container Apps, you can easily utilize functionalities such as KEDA, Dapr, Envoy, scaling, monitoring, security, and access control for your Azure Functions.&lt;/p&gt;

&lt;p&gt;[Reference]&lt;br&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-container-apps-hosting" rel="noopener noreferrer"&gt;Azure Container Apps hosting of Azure Functions&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-deploy-container-apps?tabs=acr%2Cbash&amp;amp;pivots=programming-language-java" rel="noopener noreferrer"&gt;Create your first containerized functions on Azure Container Apps&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Environment Variables
&lt;/h2&gt;

&lt;p&gt;Below are the environment variables related to creating Azure Container Apps resources. Here, you specify various names and installation locations for the resources you will create, as well as the container image name and tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Azure Container Apps resource names&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eastus
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESOURCE_GROUP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshio-rg
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_REGISTRY_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cajava2411
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_ENVIRONMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YoshioContainerEnvironment
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;STORAGE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshiojavastorage
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AZURE_FUNCTION_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshiojavafunc

&lt;span class="c"&gt;# Container image name and tag&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;C_IMAGE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tyoshio2002/java-function-on-aca
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;C_IMAGE_TAG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating and Testing a Java Azure Function Project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create an Azure Functions for Java Maven Project
&lt;/h3&gt;

&lt;p&gt;First, create a Maven project for Azure Functions for Java. This Maven project is designed for creating Azure Functions using Java 21. Use the &lt;code&gt;mvn archetype:generate&lt;/code&gt; command to create the project, modifying parameters as needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn archetype:generate &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DinteractiveMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DarchetypeGroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.microsoft.azure &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DarchetypeArtifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;azure-functions-archetype &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DgroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.yoshio3 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-Dpackage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.yoshio3 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DartifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yoshiojavafunc &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DappName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Java-Azure-Functions &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DappRegion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$LOCATION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-DjavaVersion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;21 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-Dversion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0-SNAPSHOT &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-Ddocker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executing the above command will automatically create a directory structure, and &lt;code&gt;Function.java&lt;/code&gt; will contain sample code for an Azure Function with an HTTP trigger. A &lt;code&gt;Dockerfile&lt;/code&gt; will also be created, which contains the configuration for running Azure Functions in a Docker container environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Dockerfile
├── host.json
├── local.settings.json
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── yoshio3
    │               └── Function.java
    └── test
        └── java
            └── com
                └── yoshio3
                    ├── FunctionTest.java
                    └── HttpResponseMessageMock.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Run Azure Function Locally
&lt;/h3&gt;

&lt;p&gt;Build the Maven project and run the Azure Functions locally. Execute the following commands to start the Azure Functions with the HTTP trigger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean package
mvn azure-functions:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the Azure Functions are running, open another terminal and execute the following command to send a request to the HTTP trigger. You should receive a response saying "Hello, World".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"http://localhost:7071/api/HttpExample?name=World"&lt;/span&gt;
&lt;span class="c"&gt;# Output: &lt;/span&gt;
Hello, World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating and Testing the Azure Functions Container Image
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Build and Test the Docker Image
&lt;/h3&gt;

&lt;p&gt;Use the automatically generated &lt;code&gt;Dockerfile&lt;/code&gt; to build the Azure Functions container image. Execute the following command to build the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ./Dockerfile &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the build is complete, run the following command to check if the image has been created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;
&lt;span class="c"&gt;# Output: &lt;/span&gt;
tyoshio2002/java-function-on-aca    1.0    bcf471e6f774   9 hours ago     1.46GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the image is created, run the following command to test the Azure Functions container image locally. The Azure Functions container internally uses HTTP port 80, so you will map it to port 8080 for local access. After the container starts, execute the curl command to send a request to the Azure Functions HTTP trigger. If everything is working correctly, you should receive "Hello, World".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt;
curl &lt;span class="s2"&gt;"http://localhost:8080/api/HttpExample?name=World"&lt;/span&gt;
&lt;span class="c"&gt;# Output: &lt;/span&gt;
Hello, World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pushing the Container Image to Azure Container Registry
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Log in to Azure CLI
&lt;/h3&gt;

&lt;p&gt;First, log in to Azure using the Azure CLI. Execute the following command to log in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create a Resource Group
&lt;/h3&gt;

&lt;p&gt;Create a resource group in Azure. This resource group will be used to group resources related to Azure Container Registry and Azure Container Apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az group create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nv"&gt;$LOCATION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create and Log in to Azure Container Registry
&lt;/h3&gt;

&lt;p&gt;Create an Azure Container Registry and log in. Azure Container Registry is a private container registry for pushing container images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az acr create &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_NAME&lt;/span&gt; &lt;span class="nt"&gt;--sku&lt;/span&gt; Basic
az acr login &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_NAME&lt;/span&gt;
az acr update &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_NAME&lt;/span&gt; &lt;span class="nt"&gt;--admin-enabled&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Retrieve the Azure Container Registry Server Name
&lt;/h3&gt;

&lt;p&gt;Retrieve the server name of the created Azure Container Registry. The server name will be in the format &lt;code&gt;$CONTAINER_REGISTRY_NAME.azurecr.io&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CONTAINER_REGISTRY_SERVER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az acr show &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_NAME&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; loginServer &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Push the Image to Azure Container Registry
&lt;/h3&gt;

&lt;p&gt;To push the locally created container image to Azure Container Registry, tag the image using the &lt;code&gt;tag&lt;/code&gt; command. After tagging, use the &lt;code&gt;push&lt;/code&gt; command to push the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker tag &lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_SERVER&lt;/span&gt;/&lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt;
docker push &lt;span class="nv"&gt;$CONTAINER_REGISTRY_SERVER&lt;/span&gt;/&lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating Azure Container Apps and Deploying the Java Azure Function
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Register Extensions and Resource Providers in Azure CLI
&lt;/h3&gt;

&lt;p&gt;To create and manage Azure Container Apps from Azure CLI, register the necessary extensions and resource providers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az upgrade
az extension add &lt;span class="nt"&gt;--name&lt;/span&gt; containerapp &lt;span class="nt"&gt;--upgrade&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt;
az provider register &lt;span class="nt"&gt;--namespace&lt;/span&gt; Microsoft.Web
az provider register &lt;span class="nt"&gt;--namespace&lt;/span&gt; Microsoft.App
az provider register &lt;span class="nt"&gt;--namespace&lt;/span&gt; Microsoft.OperationalInsights
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create Azure Container Apps Environment
&lt;/h3&gt;

&lt;p&gt;Create an environment for Azure Container Apps. This command sets up the configuration needed to host Azure Container Apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az containerapp &lt;span class="nb"&gt;env &lt;/span&gt;create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_ENVIRONMENT&lt;/span&gt; &lt;span class="nt"&gt;--enable-workload-profiles&lt;/span&gt; &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nv"&gt;$LOCATION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create Storage Account for Azure Functions
&lt;/h3&gt;

&lt;p&gt;Azure Functions requires a storage account when creating a Function App instance. Therefore, create a general-purpose storage account for Azure Functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az storage account create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_NAME&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nv"&gt;$LOCATION&lt;/span&gt; &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="nt"&gt;--sku&lt;/span&gt; Standard_LRS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Create an Instance of Java Azure Function in Azure Container Apps
&lt;/h3&gt;

&lt;p&gt;Create an instance of the Java Azure Function in Azure Container Apps. Execute the following command to create the instance. Since the Azure Function is created using Java 21, specify &lt;code&gt;--runtime java&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az functionapp create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_FUNCTION_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--environment&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_ENVIRONMENT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--storage-account&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--workload-profile-name&lt;/span&gt; &lt;span class="s2"&gt;"Consumption"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--max-replicas&lt;/span&gt; 15 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--min-replicas&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--functions-version&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--runtime&lt;/span&gt; java &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--image&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_SERVER&lt;/span&gt;/&lt;span class="nv"&gt;$C_IMAGE_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$C_IMAGE_TAG&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--assign-identity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Assign Role for Azure Function to Access Azure Container Registry
&lt;/h3&gt;

&lt;p&gt;Finally, configure secure access for Azure Functions to Azure Container Registry. Enable the system-managed identity for Azure Functions and assign the &lt;code&gt;ACRPull&lt;/code&gt; role for access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FUNCTION_APP_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az functionapp identity assign &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_FUNCTION_NAME&lt;/span&gt; &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; principalId &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;ACR_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az acr show &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_REGISTRY_NAME&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
az role assignment create &lt;span class="nt"&gt;--assignee&lt;/span&gt; &lt;span class="nv"&gt;$FUNCTION_APP_ID&lt;/span&gt; &lt;span class="nt"&gt;--role&lt;/span&gt; AcrPull &lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="nv"&gt;$ACR_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Retrieve the URL of the Azure Function
&lt;/h3&gt;

&lt;p&gt;Finally, retrieve the HTTP trigger function URL of the deployed Azure Function. Use the &lt;code&gt;az functionapp function show&lt;/code&gt; command to get the details of the Azure Functions function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az functionapp function show --resource-group $RESOURCE_GROUP_NAME --name $AZURE_FUNCTION_NAME --function-name HttpExample --query invokeUrlTemplate
# Output: "https://yoshiojavafunc.niceocean-********.eastus.azurecontainerapps.io/api/httpexample"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then send a request to the retrieved URL using &lt;code&gt;curl&lt;/code&gt; command to confirm that the Azure Functions is working correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://yoshiojavafunc.niceocean-********.eastus.azurecontainerapps.io/api/httpexample?name=World"&lt;/span&gt;
&lt;span class="c"&gt;# Expected Output: &lt;/span&gt;
Hello, World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is set up correctly, you should receive a response saying "Hello, World", confirming that your Azure Function is functioning as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this guide, you learned how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up environment variables for your Azure resources.&lt;/li&gt;
&lt;li&gt;Create a Java Azure Function project using Maven.&lt;/li&gt;
&lt;li&gt;Run the Azure Function locally for testing.&lt;/li&gt;
&lt;li&gt;Build a Docker image for the Azure Function.&lt;/li&gt;
&lt;li&gt;Push the Docker image to Azure Container Registry.&lt;/li&gt;
&lt;li&gt;Create an Azure Container Apps environment and deploy the Java Azure Function.&lt;/li&gt;
&lt;li&gt;Assign necessary roles for secure access to Azure Container Registry.&lt;/li&gt;
&lt;li&gt;Retrieve and test the URL of the deployed Azure Function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By following these steps, you can successfully deploy a Java Azure Function on Azure Container Apps, leveraging the benefits of containerization and Azure's integrated management capabilities. If you have any further questions or need assistance with specific steps, feel free to ask!&lt;/p&gt;

</description>
      <category>java</category>
      <category>functions</category>
      <category>containerapps</category>
    </item>
    <item>
      <title>Automated PDF-to-Text Conversion and Vector Search with Azure OpenAI and Blob Storage</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Wed, 14 Jun 2023 03:30:09 +0000</pubDate>
      <link>https://dev.to/azure/how-to-use-the-azure-openai-embedding-model-to-find-the-most-relevant-documents-2457</link>
      <guid>https://dev.to/azure/how-to-use-the-azure-openai-embedding-model-to-find-the-most-relevant-documents-2457</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;Recently, I wrote a blog post &lt;a href="https://dev.to/azure/how-to-use-the-azure-openai-embedding-model-to-find-the-most-relevant-documents-42lo"&gt;how to use the Azure OpenAI Embedding model to find the most relevant documents&lt;/a&gt;. By utilizing this feature, you can easily locate the most pertinent documents. In this article, I will explain how to automatically convert PDF files to text by uploading them to Azure Blob Storage and perform vector searches using the Azure OpenAI Embedding model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;By using this service, you can effortlessly search for any document, be it internal company documents or various academic papers, as long as they are in PDF format. Simply upload the files to Azure Blob Storage, and the system will automatically make them searchable. When you actually perform a search, ChatGPT will summarize and display the relevant sections for you.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Overview of the Service
&lt;/h3&gt;

&lt;p&gt;The service introduced in this article processes the data through the following steps:&lt;/p&gt;

&lt;p&gt;Please obtain the source code of the application from the "&lt;a href="https://github.com/yoshioterada/PostgreSQL-Vector-Search-pgvector--for-PDF-file-on-Blob-Storage-english" rel="noopener noreferrer"&gt;Source Code is Here&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971732748_1dc14e38f2_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971732748_1dc14e38f2_b.jpg" alt="Azure-Function-Spring-Embedding-Search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload a PDF file to Azure Blob Storage&lt;/li&gt;
&lt;li&gt;Azure Functions' Blob Trigger detects the uploaded file and converts the PDF into text on a per-page basis&lt;/li&gt;
&lt;li&gt;The converted text is vectorized by calling Azure OpenAI Embedding&lt;/li&gt;
&lt;li&gt;The vectorized data is saved to Azure PostgreSQL Flexible Server.&lt;/li&gt;
&lt;li&gt;The user enters a search query.&lt;/li&gt;
&lt;li&gt;The input query is vectorized by calling Azure OpenAI Embedding.&lt;/li&gt;
&lt;li&gt;Based on the vectorized data, similar data is retrieved from Azure PostgreSQL Flexible Server.&lt;/li&gt;
&lt;li&gt;The relevant sections of the highly similar result documents are analyzed by Azure OpenAI ChatGPT and returned in a streaming.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1.2. Technologies Used
&lt;/h3&gt;

&lt;p&gt;The service introduced in this article utilizes the following Azure services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction" rel="noopener noreferrer"&gt;Azure Blob Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/cosmos-db/introduction" rel="noopener noreferrer"&gt;Azure Cosmos DB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/cognitive-services/openai/overview" rel="noopener noreferrer"&gt;Azure OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-java" rel="noopener noreferrer"&gt;Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/postgresql/flexible-server/overview" rel="noopener noreferrer"&gt;Azure PostgreSQL Flexible Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pdfbox.apache.org/" rel="noopener noreferrer"&gt;Apache Apache PDFBox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Setup Environment
&lt;/h2&gt;

&lt;p&gt;Currently, there is no Azure CLI command available for creating an Azure OpenAI instance, so you will need to create one using the Azure Portal. Before proceeding with the steps below, please create an Azure OpenAI instance using the Azure Portal's GUI (as of June 13, 2023).&lt;/p&gt;

&lt;p&gt;For other Azure resources, you can easily create them using the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; create-env-en.sh 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note :&lt;br&gt;&lt;br&gt;
Occasionally, even after enabling the vector search (pgvector) feature in Azure PostgreSQL Flexible Server multiple times, it may not be activated, and the execution of queries using vectors may fail. In such cases, please run the script above again to create a new PostgreSQL Flexible Server instance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before executing the commands above, please modify the variables within the script to match your environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;####################### Setting Environment Variables for Creating Azure Resources #######################
# Configuring the Resource Group and location settings
export RESOURCE_GROUP_NAME=Document-Search-Vector1
export DEPLOY_LOCATION=japaneast

# Settings for Azure PostgreSQL Flexible Server (In my environment, there are construction restrictions, so it is set to eastus)
export POSTGRES_INSTALL_LOCATION=eastus
export POSTGRES_SERVER_NAME=documentsearch1
export POSTGRES_USER_NAME=azureuser
export POSTGRES_USER_PASS='!'$(head -c 12 /dev/urandom | base64 | tr -dc '[:alpha:]'| fold -w 8 | head -n 1)$RANDOM
export POSTGRES_DB_NAME=VECTOR_DB
export POSTGRES_TABLE_NAME=DOCUMENT_SEARCH_VECTOR
export PUBLIC_IP=$(curl ifconfig.io -4)

# Settings for Azure Blob Storage
export BLOB_STORAGE_ACCOUNT_NAME=documentsearch1

# Note: If you change the values below, you will also need to modify the implementation part of the BlobTrigger in Functions.java.
export BLOB_CONTAINER_NAME_FOR_PDF=pdfs

# Settings for Azure Cosmos DB
export COSMOS_DB_ACCOUNT_NAME=odocumentsearchstatus1
export COSMOS_DB_DB_NAME=documentregistrystatus
export COSMOS_DB_CONTAINER_NAME_FOR_STATUS=status

# Obtaining the Azure subscription ID (If you are using the default subscription, you do not need to make the changes below)
export SUBSCRIPTION_ID="$(az account list --query "[?isDefault].id" -o tsv)"
####################### Setting Environment Variables for Creating Azure Resources #######################
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.1 Setting Environment Variables
&lt;/h3&gt;

&lt;p&gt;After executing the script above, if it is successful, you will see a message like below. Please update the &lt;code&gt;local.settings.json&lt;/code&gt; file for Azure Functions (BlobUploadDetector) and the &lt;code&gt;application.properties&lt;/code&gt; file for Spring Boot (PDF-Summarizer), respectively, according to the output content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;####################### Setting Environment Variables for Creating Azure Resources #######################
########## Please write the following content in the local.settings.json file ##########
-----------------------------------------------------------------------------
# Azure-related environment settings

"AzureWebJobsStorage": "****************************",
"AzurePostgresqlJdbcurl": "jdbc:postgresql://documentsearch1.postgres.database.azure.com:5432/VECTOR_DB?sslmode=require",
"AzurePostgresqlUser": "azureuser",
"AzurePostgresqlPassword": "********",
"AzurePostgresqlDbTableName": "DOCUMENT_SEARCH_VECTOR",
"AzureBlobstorageName": "documentsearch1",
"AzureBlobstorageContainerName": "pdfs",
"AzureCosmosDbEndpoint": "https://documentsearchstatus1.documents.azure.com:443/",
"AzureCosmosDbKey": "********************",
"AzureCosmosDbDatabaseName": "documentregistrystatus",
"AzureCosmosDbContainerName": "status",
"AzureOpenaiUrl": "https://YOUR_OPENAI.openai.azure.com",
"AzureOpenaiModelName": "gpt-4",
"AzureOpenaiApiKey": "YOUR_OPENAI_ACCESS_KEY",
-----------------------------------------------------------------------------

### Please write the following content in the application.properties file for Spring Boot ###
-----------------------------------------------------------------------------

# Settings for Azure PostgreSQL connection information

azure.postgresql.jdbcurl=jdbc:postgresql://documentsearch1.postgres.database.azure.com:5432/VECTOR_DB?sslmode=require
azure.postgresql.user=azureuser
azure.postgresql.password=**********
azure.postgresql.db.table.name=DOCUMENT_SEARCH_VECTOR

# The following Blob-related settings

azure.blobstorage.name=documentsearch1
azure.blobstorage.container.name=pdfs

# Settings for Azure Cosmos DB

azure.cosmos.db.endpoint=https://documentsearchstatus1.documents.azure.com:443
azure.cosmos.db.key=********************************************
azure.cosmos.db.database.name=documentregistrystatus
azure.cosmos.db.container.name=status

# Settings for Azure OpenAI

azure.openai.url=https://YOUR_OPENAI.openai.azure.com
azure.openai.model.name=gpt-4
azure.openai.api.key=********************************************
-----------------------------------------------------------------------------

# After creating PostgreSQL, please connect using the following command:
-----------------------------------------------------------------------------
&amp;gt; psql -U azureuser -d VECTOR_DB \
     -h documentsearch1.postgres.database.azure.com

Auto-generated PostgreSQL password: **********

# Once connected to PostgreSQL, please execute the following command:
-------------------------------------------------------------
VECTOR_DB=&amp;gt; CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
VECTOR_DB=&amp;gt; CREATE EXTENSION IF NOT EXISTS "vector";

# Finally, execute the following command to create the TABLE:

VECTOR_DB=&amp;gt; CREATE TABLE IF NOT EXISTS DOCUMENT_SEARCH_VECTOR
                 (id uuid, embedding VECTOR(1536),
                  origntext varchar(8192), fileName varchar(2048),
                  pageNumber integer, PRIMARY KEY (id));
-----------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note:&lt;br&gt;&lt;br&gt;
For the above OpenAI-related settings, please set the Connection URL, Model name, and API Key that were created in the Azure Portal, respectively.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  2.1.1 Setting PostgreSQL Extensions
&lt;/h4&gt;

&lt;p&gt;After generating the PostgreSQL instance, please check if it is accessible from your local environment by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; azureuser &lt;span class="nt"&gt;-d&lt;/span&gt; VECTOR_DB &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-h&lt;/span&gt; documentsearch1.postgres.database.azure.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;※ The password is displayed in the terminal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once connected to PostgreSQL, please execute the following command to add the extensions. In the example below, the &lt;code&gt;UUID&lt;/code&gt; and &lt;code&gt;pgvector&lt;/code&gt; extensions are enabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"uuid-ossp"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"vector"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, please execute the following command to create a table that can utilize vectors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;DOCUMENT_SEARCH_VECTOR&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;origntext&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;pageNumber&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Running the Application
&lt;/h2&gt;

&lt;p&gt;Once the environment setup is complete, follow the steps below to run the application:&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1Running Azure Functions (BlobUploadDetector)
&lt;/h3&gt;

&lt;p&gt;Since the environment variables have been changed, please build Azure Functions first and then execute it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;BlobUploadDetector
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mvn clean package
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mvn azure-functions:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 Running Spring Boot
&lt;/h3&gt;

&lt;p&gt;Since the environment variables have been changed, please build Spring Boot first and then execute it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;SpringBoot
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mvn clean package
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3 Uploading Files to Blob Storage
&lt;/h3&gt;

&lt;p&gt;You can connect to the Azure Portal and upload files individually, but to make it easier to upload files, I will use Azure Storage Explorer.&lt;/p&gt;

&lt;p&gt;Please download and install Azure Storage Explorer from &lt;a href="https://azure.microsoft.com/products/storage/storage-explorer/" rel="noopener noreferrer"&gt;Azure Storage Explorer Download&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you launch the &lt;code&gt;Azure Storage Explorer&lt;/code&gt;, you will be prompted to connect with your Azure account. Please connect, and once connected, you will see a screen like the one below, where you can drag and drop multiple files to upload them all at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971844298_690e552bd4_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971844298_690e552bd4_b.jpg" alt="Azure-Storage-Explorer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Verifying the Spring Boot Application
&lt;/h3&gt;

&lt;p&gt;When you access &lt;code&gt;http://localhost:8080/&lt;/code&gt;, you will see a screen like the one below. Please enter the keyword you want to search for in the text area and click the &lt;code&gt;Submit&lt;/code&gt; button. The search results will then be displayed in a streaming format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971893208_4a609ecc49_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971893208_4a609ecc49_b.jpg" alt="PDF-Document-Search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, if you click on the &lt;code&gt;Registered File List&lt;/code&gt; link, you will see a list of files registered in the database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971893213_3ce16bcee5_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971893213_3ce16bcee5_b.jpg" alt="Registered-PDF-files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By clicking on the &lt;code&gt;Failed Registration File List&lt;/code&gt; link, you will see a list of files that failed to register in the database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971577659_2c76c97669_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971577659_2c76c97669_b.jpg" alt="Failed-PDF-Files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Points to Note for Application Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Key Points for Implementing Azure Functions (BlobUploadDetector)
&lt;/h3&gt;

&lt;p&gt;First, I will explain the points to note for the implementation of &lt;code&gt;BlobUploadDetector&lt;/code&gt;, which is implemented in Azure Functions.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1.1 Extending the Execution Time of Azure Functions
&lt;/h4&gt;

&lt;p&gt;By default, Azure Functions have a runtime limit of 5 to 30 minutes. If this limit is exceeded, Azure Functions will time out. However, when analyzing and processing PDF files with a large number of pages, the processing may not be completed within this time limit. Therefore, I have extended the execution time of Azure Functions.&lt;/p&gt;

&lt;p&gt;In this sample, I have added the following settings to &lt;code&gt;host.json&lt;/code&gt; to extend the execution time of Azure Functions indefinitely. However, please note that only the &lt;code&gt;Premium plan&lt;/code&gt; and &lt;code&gt;Dedicated plan&lt;/code&gt; can be set to unlimited. The &lt;code&gt;Consumption plan&lt;/code&gt; cannot be set to unlimited.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"functionTimeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reference :&lt;br&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-scale#timeout" rel="noopener noreferrer"&gt;Function app timeout duration&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1.2 Adjusting the Usage Interval of Azure OpenAI Embedding API
&lt;/h3&gt;

&lt;p&gt;The maximum number of calls per minute for the Azure OpenAI &lt;code&gt;text-embedding-ada-002&lt;/code&gt; varies depending on the instance. If the limit is exceeded, the Azure OpenAI Embedding API will return a 400 error. Therefore, please adjust the call interval of the Azure OpenAI Embedding API according to your environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Azure OpenAI Call Interval (milliseconds)&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;OPENAI_INVOCATION_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Reference:&lt;br&gt;&lt;br&gt;
The above setting is for when the number of calls per minute for the &lt;code&gt;text-embedding-ada-002&lt;/code&gt; model is set to the maximum allowable value of 240k Token/min (approximately 1440 req/min) in my environment. If the number of calls per minute is different, please adjust this setting accordingly. In some cases, it may be necessary to change the setting in units of 5-10 seconds instead of milliseconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can check and change the number of calls per minute from the &lt;code&gt;Quotas&lt;/code&gt; section in &lt;a href="https://oai.azure.com/portal/" rel="noopener noreferrer"&gt;Azure OpenAI Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971493166_04d2a0dd79_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52971493166_04d2a0dd79_b.jpg" alt="open-ai-quotas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1.3 Setting Environment Variables in Azure Functions
&lt;/h3&gt;

&lt;p&gt;In Azure Functions, environment variables are set in the &lt;code&gt;local.settings.json&lt;/code&gt; file for local environments. When deploying to Azure Functions, the settings are configured in the &lt;code&gt;Configuration&lt;/code&gt; section of Azure Functions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;br&gt;
JBe aware that environment variables cannot be set in the property files under &lt;code&gt;src/main/resources/&lt;/code&gt;, which are commonly used in Java.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The values of environment variables set in &lt;code&gt;local.settings.json&lt;/code&gt; can be retrieved in the program by calling the &lt;code&gt;System.getenv()&lt;/code&gt; method.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1.4 Points to Consider When Changing the Container Name Created in Azure Blob Storage
&lt;/h4&gt;

&lt;p&gt;If you want to change the value of &lt;code&gt;"AzureBlobstorageContainerName": "pdfs"&lt;/code&gt;, in the environment variables, please also modify the following part of the &lt;code&gt;Function.java&lt;/code&gt; source code. The value that can be specified for &lt;code&gt;path&lt;/code&gt; requires a definition in constants, so it cannot be obtained from environment variables and set to &lt;code&gt;path&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@FunctionName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ProcessUploadedFile"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@StorageAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AzureWebJobsStorage"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nd"&gt;@BlobTrigger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pdfs/{name}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"binary"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nd"&gt;@BindingName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nd"&gt;@BlobInput&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"inputBlob"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pdfs/{name}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;dataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"binary"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;inputBlob&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ExecutionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;UnsupportedEncodingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.1.5 Points to Consider in PDF Parsing Process (Especially When Using Models Other Than ChatGPT-4)
&lt;/h3&gt;

&lt;p&gt;The following steps are performed when converting PDF files to text:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split the PDF file by the number of pages&lt;/li&gt;
&lt;li&gt;Convert each split page to text&lt;/li&gt;
&lt;li&gt;If the converted text contains &lt;code&gt;\n&lt;/code&gt; and &lt;code&gt;multiple spaces&lt;/code&gt;, remove them and replace with &lt;code&gt;a single white space character&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Measure the size of the converted text&lt;/li&gt;
&lt;li&gt;If the text size is within the range of (7200-7500) characters and characters such as ".", "?", "!" are found, split the text at that point&lt;/li&gt;
&lt;li&gt;If the above delimiter characters are not found up to MAX_SEPARATE_TOKEN_LENGTH (7500), forcibly split the text&lt;/li&gt;
&lt;li&gt;Send the split text to Azure OpenAI Embedding API to obtain vectors&lt;/li&gt;
&lt;li&gt;Register the vectors data into the PostgreSQL vector database table&lt;/li&gt;
&lt;li&gt;Register and update the status of each process in Cosmos DB as appropriate&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note:&lt;br&gt;
The &lt;code&gt;text-embedding-ada-002&lt;/code&gt; and &lt;code&gt;gpt-4&lt;/code&gt; models have a maximum token limit of 8192 per request. In our experience, specifying a value close to the maximum may cause errors depending on the request conditions. Therefore, I have set the maximum number of characters per page to 7500. However, to avoid forcibly splitting the text in the middle of a sentence as much as possible, I have implemented the process so that if there is a delimiter character within the range of 7200 to 7500 characters, the text can be split there. If you use &lt;code&gt;gpt-35 turbo&lt;/code&gt;, the &lt;code&gt;MAX is 4000 tokens&lt;/code&gt;, so the current MAX_SEPARATE_TOKEN_LENGTH value is too large. Please change this value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4.1.6 About the Data to Insert
&lt;/h3&gt;

&lt;p&gt;Based on my experience, I believe that inserting pages with a certain number of characters into the PostgreSQL database is more effective. For example, if you insert a page with only one line written, such as &lt;code&gt;Please refer to this for information on Azure Functions,&lt;/code&gt; into the database, the vector values obtained with &lt;code&gt;text-embedding-ada-002&lt;/code&gt; will have little difference from other data, resulting in a higher similarity. Therefore, by inserting pages with a certain number of characters, you can increase the difference in vector values.&lt;/p&gt;

&lt;p&gt;In other words, to put it simply, if you search for the term &lt;code&gt;Azure Functions,&lt;/code&gt; the above-mentioned page will be more likely to be found, regardless of what kind of text follows. Therefore, please register pages with a certain number of characters in the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Points to Consider in Spring Boot Implementation
&lt;/h3&gt;

&lt;p&gt;Next, I will describe the points to consider when implementing a Spring Boot application.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2.1 Implementing as Server Sent Event
&lt;/h3&gt;

&lt;p&gt;When sending requests to OpenAI, the Java SDK provides instances for both synchronous and asynchronous processing. In this case, I will use the &lt;code&gt;OpenAIAsyncClient&lt;/code&gt; class for asynchronous processing. By using this, you can return results as a real-time stream.&lt;/p&gt;

&lt;p&gt;Since the Server-Side returns results as a Realtime streaming, you can, of course, return the results to the client in Realtime using Server Sent Events.&lt;/p&gt;

&lt;p&gt;To implement the Spring Boot application as a Server Sent Event, I will use Spring Boot's WebFlux. Additionally, when implementing SSE with WebFlux, I have added the following implementation to enable 1-to-1 communication:&lt;/p&gt;

&lt;p&gt;The client's browser (JavaScript) generates a UUID and connects to &lt;code&gt;/openai-gpt4-sse-stream&lt;/code&gt; with that UUID.&lt;/p&gt;

&lt;p&gt;Below is the &lt;code&gt;JavaScript&lt;/code&gt; code snipet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;eventSource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;setupEventSource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setupEventSource&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;eventSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/openai-gpt4-sse-stream?userId=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note :&lt;br&gt;&lt;br&gt;
The method of generating UUIDs in JavaScript is implemented very simply in this example.&lt;br&gt;
If you plan to use this in a production environment, please consider a more secure method for generating UUIDs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When connecting to the server, the server registers the client's UUID and &lt;code&gt;Sinks.Many&amp;lt;String&amp;gt;&lt;/code&gt; in a &lt;code&gt;1 to 1&lt;/code&gt; relationship using a Map.&lt;/p&gt;

&lt;p&gt;Below is an excerpt from the &lt;code&gt;Java&lt;/code&gt; code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Many&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userSinks&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/openai-gpt4-sse-stream"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_EVENT_STREAM_VALUE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@ResponseBody&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Flux&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;sseStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Many&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getUserSink&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSink&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;userSink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createUserSink&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"USER ID IS ADDED: {}}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asFlux&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;delayElements&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofMillis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Many&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createUserSink&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Many&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;many&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;multicast&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;directBestEffort&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;userSinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User ID: {} User Sink: {} is Added."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get User Sinks&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Many&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUserSink&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userSinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, by calling &lt;code&gt;tryEmitNext&lt;/code&gt; on the &lt;code&gt;Sinks.Many&amp;lt;String&amp;gt;&lt;/code&gt; associated with this UUID, you can return a string to the client's browser.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;userSink.tryEmitNext(jsonMessage);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The above process is automatically performed when accessing the website with &lt;code&gt;window.onload&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2.２ Processing when a string is entered and the Submit button is pressed
&lt;/h4&gt;

&lt;p&gt;The process when a search string is entered in the browser and the Submit button is pressed is as follows:&lt;br&gt;
At the time of &lt;code&gt;Submit&lt;/code&gt;, you also pass the &lt;code&gt;UUID&lt;/code&gt; to &lt;code&gt;/openai-gpt4-sse-submit&lt;/code&gt; and access it via POST.&lt;/p&gt;

&lt;p&gt;Below is an excerpt from the &lt;code&gt;JavaScript&lt;/code&gt; code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;        &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submitText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#target *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textFieldValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputText&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/openai-gpt4-sse-submit?userId=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textFieldValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the server side, the user-input string received with &lt;code&gt;@RequestBody&lt;/code&gt; is vectorized using &lt;code&gt;text-embedding-ada-002&lt;/code&gt;, and then a vector search is performed in PostgreSQL. The search results from PostgreSQL are processed by calling OpenAI's ChatGPT for summarization. Finally, the results are returned to the client's browser using Server Sent Events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/openai-gpt4-sse-submit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@ResponseBody&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;openaiGpt4Sse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;inputText&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getUserSink&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"InputText --------------: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Receive user input and search for documents in the PostgreSQL Vector DB  &lt;/span&gt;
        &lt;span class="n"&gt;findMostSimilarString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputText&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findMostSimilarString&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Based on the search results of the documents, perform summarization using OpenAI and send the results to the client&lt;/span&gt;
            &lt;span class="n"&gt;findMostSimilarString&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docSummary&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;requestOpenAIToGetSummaryAndSendMessageToClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docSummary&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputText&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2.3 Points to Consider in Asynchronous Implementation
&lt;/h4&gt;

&lt;p&gt;When implementing with Spring WebFlux's asynchronous processing, all internal processing must be implemented as asynchronous. If you &lt;code&gt;block()&lt;/code&gt; during intermediate processing, an error will occur.&lt;/p&gt;

&lt;p&gt;For example, when sending a query to PostgreSQL and returning the results, instead of returning them as a &lt;code&gt;List&amp;lt;DocumentSummarizer&amp;gt;&lt;/code&gt;, you return them as a &lt;code&gt;Mono&amp;lt;List&amp;lt;DocumentSummarizer&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, when calling OpenAI, the implementation is done as follows, without blocking any processing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;        &lt;span class="c1"&gt;// Send a request to OpenAI and send the results to the client&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getChatCompletionsStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;OPENAI_MODEL_NAME&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatCompletionsOptions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatMessages&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doOnSubscribe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Send a request-event to create a DIV area in the HTML for displaying the link and result string&lt;/span&gt;
                    &lt;span class="n"&gt;sendCreateAreaEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;docSummary&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="c1"&gt;// Send a request-event in the HTML to display the link&lt;/span&gt;
                    &lt;span class="n"&gt;sendCreateLinkEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;docSummary&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;})&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatCompletions&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Send the results from OpenAI to the client via streaming&lt;/span&gt;
                    &lt;span class="n"&gt;sendChatCompletionMessages&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;docSummary&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatCompletions&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;},&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error Occurred: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                    &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryEmitError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;},&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Completed"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When processing asynchronously in a non-blocking manner, there is a possibility that multiple returned results may get mixed up if there are multiple answers. Therefore, to correctly identify which summary result corresponds to which search result, the UUID associated with the document (included in the docSummary) is also sent to the client.&lt;/p&gt;

&lt;p&gt;For example, a request is sent in JSON format to create a display area associated with the documentID, in order to separate the display area for each document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Send a request-event in the HTML to create a DIV area for displaying the link and result string&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendCreateAreaEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Sinks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Many&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DocumentSummarizer&lt;/span&gt; &lt;span class="n"&gt;docSummary&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;documentID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docSummary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;createArea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CreateAreaInHTML&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"create"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documentID&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;gson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Gson&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jsonCreateArea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createArea&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jsonCreateArea: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonCreateArea&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;userSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryEmitNext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonCreateArea&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// wait few mill seconds&lt;/span&gt;
        &lt;span class="n"&gt;intervalToSendClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JavaScript implementation that receives the above JSON is as follows.&lt;br&gt;
In the example below, when the JSON &lt;code&gt;type&lt;/code&gt; is received as the string &lt;code&gt;create&lt;/code&gt;, an area corresponding to the documentID is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="c1"&gt;// Add a child element under the target&lt;/span&gt;
                        &lt;span class="nf"&gt;addArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createLink&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pageNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="c1"&gt;// Add a link to the link description part under the child&lt;/span&gt;
                        &lt;span class="nf"&gt;createLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addMessage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="c1"&gt;// Add text to the text description part under the child&lt;/span&gt;
                        &lt;span class="nf"&gt;addMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By implementing in this way, even when multiple search results are obtained, it is possible to display them separately for each search result.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2.4 Points to Consider in Cosmos DB Implementation
&lt;/h4&gt;

&lt;p&gt;The following content is addressed in the &lt;code&gt;create-env-en.sh&lt;/code&gt; script and is not particularly important, but it is mentioned here for the sake of information sharing.&lt;/p&gt;

&lt;p&gt;To execute a query in Cosmos DB and perform sorting, the following SQL is executed:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"SELECT * FROM c WHERE c.status = 'COMPLETED' ORDER BY c.fileName ASC, c.pageNumber ASC&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In Cosmos DB, when sorting with &lt;code&gt;ORDER BY&lt;/code&gt;, it is &lt;code&gt;necessary to create an index&lt;/code&gt; on the target property. If you do not create one, the query results will not be displayed correctly.&lt;/p&gt;

&lt;p&gt;In this case, when creating the Cosmos DB container in the &lt;code&gt;create-env-en.sh&lt;/code&gt; script, the &lt;code&gt;cosmos-index-policy.json&lt;/code&gt; file is read, and indexes are created for the &lt;code&gt;fileName&lt;/code&gt; and &lt;code&gt;pageNumber&lt;/code&gt; properties.&lt;/p&gt;

&lt;p&gt;The following command is executed in the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cosmosdb sql container create &lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_DB_ACCOUNT_NAME&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP_NAME&lt;/span&gt; &lt;span class="nt"&gt;--database-name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_DB_DB_NAME&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_DB_CONTAINER_NAME_FOR_STATUS&lt;/span&gt; &lt;span class="nt"&gt;--partition-key-path&lt;/span&gt; &lt;span class="s2"&gt;"/id"&lt;/span&gt;  &lt;span class="nt"&gt;--throughput&lt;/span&gt; 400  &lt;span class="nt"&gt;--idx&lt;/span&gt; @cosmos-index-policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2.5 Points to Consider in Spring Data JPA Implementation
&lt;/h4&gt;

&lt;p&gt;Initially, I considered implementing queries for PostgreSQL using Spring Data JPA, but I was unable to handle the &lt;code&gt;pgvector type&lt;/code&gt; in PostgreSQL with Spring Data JPA. Therefore, I abandoned the implementation using Spring Data JPA for this project.&lt;/p&gt;

&lt;p&gt;Despite trying various approaches, even implementing with &lt;code&gt;Native Query&lt;/code&gt; resulted in errors, so I have implemented using standard JDBC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Notes
&lt;/h2&gt;

&lt;p&gt;At this point, there are still some unimplemented features. For example, I have not yet implemented the deletion-related functions (deleting Blob files matching the UUID of failed file registrations, deleting entries in CosmosDB).&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, by using this service, you can search for any internal documents, various research papers, or any PDF files by simply uploading them to Azure Storage. When you actually perform a search, ChatGPT will summarize and display the relevant sections for you.&lt;/p&gt;

&lt;p&gt;Furthermore, not only PDFs but also Word and Excel files, as well as other text documents, can be handled by utilizing libraries.&lt;/p&gt;

&lt;p&gt;If you are interested in this content, please feel free to give it a try.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to use the Azure OpenAI Embedding model to find the most relevant documents</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Fri, 09 Jun 2023 04:29:21 +0000</pubDate>
      <link>https://dev.to/azure/how-to-use-the-azure-openai-embedding-model-to-find-the-most-relevant-documents-42lo</link>
      <guid>https://dev.to/azure/how-to-use-the-azure-openai-embedding-model-to-find-the-most-relevant-documents-42lo</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;Initially, I had never worked with machine learning concepts like "Embedding", "Integrated", or "Embedded" before, so I was quite puzzled when I came across these terms. I didn't understand what could be done with this model. Therefore, I decided to research and actually use the model to grasp its usefulness. In this entry, I'd like to share my findings with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. High-Accuracy and Affordable Models Have Arrived!
&lt;/h2&gt;

&lt;p&gt;OpenAI has a model called &lt;code&gt;text-embedding-ada-002&lt;/code&gt; for text embedding purposes. By using this model, you can find the most relevant documents at a much lower cost.&lt;/p&gt;

&lt;p&gt;There are other embedding models available, such as the &lt;code&gt;Davinci&lt;/code&gt; model and a few others. However, &lt;code&gt;text-embedding-ada-002&lt;/code&gt; offers higher accuracy in most processes and is considerably more affordable compared to the others. Therefore, it is highly recommended to use this model for tasks like similarity search.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href="https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/" rel="noopener noreferrer"&gt;Azure OpenAI Service Pricing&lt;/a&gt;, as of June 8, 2023, there were the following differences in pricing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Embedding Models&lt;/th&gt;
&lt;th&gt;Per 1,000 Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ada&lt;/td&gt;
&lt;td&gt;$0.0004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Babbage&lt;/td&gt;
&lt;td&gt;$0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Curie&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Davinci&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  3. What is Embedding?
&lt;/h2&gt;

&lt;p&gt;Before using embedding, it is essential to understand its basic concept; otherwise, we won't know how to use it effectively. In short, the idea of embedding is based on the concept of vectors, which we learned in high school.&lt;/p&gt;

&lt;p&gt;During high school, we learned that two arrows are considered the same vector if they point in the same direction and have the same length. By applying this concept, we can find vectors with the closest possible length and direction, which implies that they are the most similar. In the illustration below, the blue line represents an identical vector. If we can find the vector "1" that is closest to this blue line, it would indicate the content most similar to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52959955338_19b89bc1d1_b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F52959955338_19b89bc1d1_b.jpg" alt="Vector Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In practice, when you pass a natural language string to the &lt;code&gt;text-embedding-ada-002 model&lt;/code&gt;, you will obtain a high-dimensional array (vector) consisting of 1536 floating-point numbers, as shown below.&lt;/p&gt;

&lt;p&gt;Example: An excerpt of the result for the string "Please tell me about Azure Blob"&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[-0.013197514, -0.025243968, 0.011384923, -0.015929632, -0.006410221, 0.031038966, 
-0.016921926, -0.010776317, -0.0019300125, -0.016300088, 0.01767607, -0.0047100903,
0.009691408, -0.014183193, -0.017001309, -0.014434575, 0.01902559, 0.010961545, 
0.013561356, -0.017371766, -0.007964816, 0.0026841562, 0.0019663966, -0.0019878964, 
-0.025614424, -0.0030298054, 0.020229574, -0.01455365, 0.022703694, -0.02033542, 
0.035696134, -0.002441044, -0.008057429, 0.0061191483, 0.004263558, -0.0025518502,
0.018046526, 0.011411385, 0.0063804523, -0.0021020102, 0.027572552, -0.017967142,
0.0077663567, 0.005361697, -0.0116693815, 0.004524862, -0.043581568, -0.01028017, 

.... Omitted

-0.0017265921, 0.083035186, -0.006205147, -0.008646191, 0.0070651355, -0.019052051, 
0.008374964, 0.024225213, 0.01522841, 0.019951731, -0.006516066, 0.017967142, 
0.0058082296, -0.0053253127, -0.009929558, -0.039109625, -0.031277116, -0.015863478, 
0.011040928, 0.012529369, 0.013012286, 0.022981536, -0.013706892, 0.012965979, 
0.011953839, -0.01903882, 0.015347485, 0.019052051, -0.0046538603, 0.012191989, 
-0.020983716, 0.0078722015, -0.0018605519, -0.02775778, -0.026739024, -0.010359553, 
-0.013918581, -0.011933993, 0.0066814483, 0.005196315, -0.0045744767, -2.7598185E-4, 
0.012251527, -0.018178832, -0.013276898, 0.011709073, -0.022928614, 0.002131779, 
-0.007462053, 0.0044554016]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The method using embeddings involves comparing the vector of the user's input string with pre-saved vectors in a database and searching for the closest ones.&lt;/p&gt;

&lt;p&gt;There are several ways to find the closest match, but one of the most commonly known methods is calculating the cosine similarity. When you pass two vectors to calculate cosine similarity, you'll get a result ranging from -1 to 1. This calculation is performed alongside the data stored in the database.&lt;/p&gt;

&lt;p&gt;Ultimately, the content with the result closest to 1 is considered the most similar.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Example of a user's input text:
AAA BBB CCC DDD EEE FFF GGG HHH III JJJ

Calculation results of cosine similarity with stored strings in the database:
AAA BBB CCC DDD EEE FFF GGG HHH III JJ  =       0.9942949478994986  &amp;lt;---- Closest to 1 (highest similarity)
AAA BBB KKK LLL MMM NNN OOO PPP QQQ RRR =       0.930036739659776   &amp;lt;---- Next closest to 1
Today, we are presenting at an IT event.=           0.7775105340227892  &amp;lt;---- Furthest from 1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this way, the user's input query string is vectorized, and by combining it with the pre-saved vectors (arrays) in the database, a similarity search is performed.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Points to consider when handling strings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Token limit
&lt;/h3&gt;

&lt;p&gt;The maximum number of tokens (roughly equivalent to the character count) that can be handled by &lt;code&gt;text-embedding-ada-002&lt;/code&gt; is 8192 tokens. Therefore, when dealing with texts exceeding approximately 8000 characters, splitting is necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing strings for processing
&lt;/h3&gt;

&lt;p&gt;As mentioned in the "&lt;a href="https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/embeddings?tabs=console#replace-newlines-with-a-single-space" rel="noopener noreferrer"&gt;Replace newlines with a single space&lt;/a&gt;" section, it has been confirmed that "&lt;strong&gt;&lt;em&gt;the presence of newline characters may result in unexpected outcomes.&lt;/em&gt;&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;Hence, it is recommended to replace newline characters (\n) with a space before sending the message to &lt;code&gt;text-embedding-ada-002&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you have a text like the one below, replace all newline characters and convert it into a single line string (please refer to the sample code provided).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Visual Studio Code for Java is an open-source code editor provided by Microsoft.

It is an extension on Visual Studio Code that supports the Java programming language.

It provides an environment for Java developers to efficiently write, build, debug, test, and execute code. Visual Studio Code is a lightweight text editor that supports multiple languages and is known for its high extensibility. For Java developers, Visual Studio Code for Java can be used as an excellent development environment.

Visual Studio Code for Java can be used by installing the Java Development Kit (JDK), a basic toolset for compiling and running Java programs.

To start a Java project in Visual Studio Code, first install the JDK, and then install the Java Extension Pack from the Visual Studio Code extension marketplace.

The Java Extension Pack includes features such as Java language support, debugging, testing, and project management.

The main features of Visual Studio Code for Java are as follows:

1. Syntax highlighting: Color-coding for Java code to improve readability.
2. Code completion: Suggests possible code during input, allowing for efficient code writing.
3. Code navigation: Easy jumping to classes, methods, and variables, and searching for definitions.
4. Refactoring: Features to change code structure and names, improving code quality.
5. Debugging: Setting breakpoints, step execution, and variable monitoring.
6. Testing: Supports testing frameworks like JUnit and TestNG, creating, running, and displaying test results.
7. Project management: Supports build tools like Maven and Gradle, managing project configurations and dependencies.
8. Git integration: Integrated with Git for source code version control.

Visual Studio Code for Java offers a wealth of features to improve developer productivity and provides an environment suitable for Java project development. In addition, the Visual Studio Code extension marketplace offers various Java-related extensions that can be added as needed. With these extensions, Java developers can use Visual Studio Code as an integrated development environment.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  4. Verification of Operation
&lt;/h2&gt;
&lt;h3&gt;
  
  
  4.1 Vector DB options available in Azure
&lt;/h3&gt;

&lt;p&gt;As of June 8, 2023, there are several options for storing vectors in Azure. Please choose the appropriate database according to your needs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-use-pgvector" rel="noopener noreferrer"&gt;How to enable and use pgvector on Azure Database for PostgreSQL - Flexible Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/vcore/vector-search" rel="noopener noreferrer"&gt;Using vector search on embeddings in Azure Cosmos DB for MongoDB vCore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aka.ms/VectorSearchSignUp" rel="noopener noreferrer"&gt;Azure Cognitive Search (Private Preview)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/t5/azure-developer-community-blog/introducing-vector-search-similarity-capabilities-in-azure-cache/ba-p/3827512" rel="noopener noreferrer"&gt;Azure Cache for Redis Enterprise&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  4.2 Vector Search with Azure PostgreSQL Flexible Server
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, there are various options for Vector DB, and you can choose the one that suits your needs. However, for verification purposes, we have decided to use PostgreSQL Flexible Server in this case. The steps to set up PostgreSQL Flexible Server to handle vectors are described below. Please give it a try if you're interested. If you choose a different persistence destination, please skip this section.&lt;/p&gt;
&lt;h4&gt;
  
  
  4.2.1 Setting environment variables
&lt;/h4&gt;

&lt;p&gt;To create resources on Azure, please modify and set the following environment variables accordingly.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

export RESOURCE_GROUP=PostgreSQL
export LOCATION=eastus
export POSTGRES_SERVER_NAME=yoshiopgsql3
export POSTGRES_USER_NAME=yoterada
export POSTGRES_USER_PASS='!'$(head -c 12 /dev/urandom | base64 | tr -dc '[:alpha:]'| fold -w 8 | head -n 1)$RANDOM
echo "GENERATED PASSWORD: " $POSTGRES_USER_PASS
export POSTGRES_DB_NAME=VECTOR_DB
export SUBSCRIPTION_ID=********-****-****-****-************
export PUBLIC_IP=$(curl ifconfig.io -4)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the above configuration example, the password is automatically generated and output to the standard output. Please enter your own password or make a note of the generated password.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2.2 Installing Azure PostgreSQL Flexible Server
&lt;/h4&gt;

&lt;p&gt;Please execute the following three commands. When you run these commands, the following tasks will be performed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Azure PostgreSQL Flexible Server&lt;/li&gt;
&lt;li&gt;Configure the firewall&lt;/li&gt;
&lt;li&gt;Create a new database&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az postgres flexible-server create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nv"&gt;$LOCATION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--admin-user&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_USER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--admin-password&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_USER_PASS&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--public-access&lt;/span&gt; &lt;span class="nv"&gt;$PUBLIC_IP&lt;/span&gt;
    &lt;span class="nt"&gt;--yes&lt;/span&gt;
az postgres flexible-server firewall-rule create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-r&lt;/span&gt; AllowAllAzureIPs &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--start-ip-address&lt;/span&gt; 0.0.0.0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--end-ip-address&lt;/span&gt; 255.255.255.255
az postgres flexible-server db create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_DB_NAME&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  4.2.3 Configuring Azure PostgreSQL Flexible Server for multi language support
&lt;/h4&gt;

&lt;p&gt;Since the data to be persisted in this case includes Japanese strings, please perform the following settings to enable handling of Japanese UTF-8 within the database.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az postgres flexible-server parameter &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--server-name&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--subscription&lt;/span&gt; &lt;span class="nv"&gt;$SUBSCRIPTION_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; lc_monetary &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"ja_JP.utf-8"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az postgres flexible-server parameter &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--server-name&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--subscription&lt;/span&gt; &lt;span class="nv"&gt;$SUBSCRIPTION_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; lc_numeric &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"ja_JP.utf-8"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az postgres flexible-server parameter &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--server-name&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--subscription&lt;/span&gt; &lt;span class="nv"&gt;$SUBSCRIPTION_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; timezone &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"Asia/Tokyo"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  4.2.4 Installing extensions on Azure PostgreSQL Flexible Server
&lt;/h4&gt;

&lt;p&gt;To enable handling of UUID and Vector in PostgreSQL, we will make use of extensions. Please execute the following command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note：&lt;br&gt;&lt;br&gt;
Do not leave any space between "VECTOR,UUID-OSSP".&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az postgres flexible-server parameter &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$RESOURCE_GROUP&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--server-name&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--subscription&lt;/span&gt; &lt;span class="nv"&gt;$SUBSCRIPTION_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; azure.extensions &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"VECTOR,UUID-OSSP"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  4.3 Creating a table to handle Vector in PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Now that the PostgreSQL configuration is complete, execute the following command to connect.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_USER_NAME&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_DB_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="nv"&gt;$POSTGRES_SERVER_NAME&lt;/span&gt;.postgres.database.azure.com 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once connected successfully, enable the use of the extensions added earlier within PostgreSQL. Please execute the &lt;code&gt;CREATE EXTENSION&lt;/code&gt; command for each, as shown below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

VECTOR_DB=&amp;gt;
VECTOR_DB=&amp;gt; CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION
VECTOR_DB=&amp;gt; CREATE EXTENSION IF NOT EXISTS "vector";
CREATE EXTENSION


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, create a table to store the Vector data. The Vector information will be stored in the &lt;code&gt;embedding VECTOR(1536)&lt;/code&gt; part. For simplicity, we will also save the original text together, and display the original string of the most similar string. In practice, you may want to use a URL as the link destination, or you can join it with another table later if desired.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

VECTOR_DB=&amp;gt; CREATE TABLE TBL_VECTOR_TEST(
    id uuid,
    embedding VECTOR(1536),
    origntext varchar(8192),
    PRIMARY KEY (id)
    );
CREATE TABLE


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  4.4 Creating a Java application
&lt;/h3&gt;
&lt;h4&gt;
  
  
  4.4.1 Adding dependencies to the Maven project
&lt;/h4&gt;

&lt;p&gt;To use the Azure OpenAI library, connect to PostgreSQL, and perform data persistence, at least the following dependencies need to be added. Please add them to your &lt;code&gt;pom.xml&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.azure&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;azure-ai-openai&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0-beta.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- https://mvnrepository.com/artifact/org.postgresql/postgresql --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.postgresql&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;postgresql&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;42.6.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  4.4.2 Creating and setting the properties file
&lt;/h4&gt;

&lt;p&gt;Please create an application.properties file in the &lt;code&gt;src/main/resources&lt;/code&gt; directory and write the property settings information in it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

azure.openai.url=https://YOUR_OWN_AZURE_OPENAI.openai.azure.com
azure.openai.model.name=gpt-4
azure.openai.api.key=************************************

azure.postgresql.jdbcurl=jdbc:postgresql://YOUR_POSTGRESQL.postgres.database.azure.com:5432/VECTOR_DB
azure.postgresql.user=yoterada
azure.postgresql.password=************************************

logging.group.mycustomgroup=com.yoshio3
logging.level.mycustomgroup=DEBUG
logging.level.root=INFO


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  4.4.3 Implementing the Java program
&lt;/h4&gt;

&lt;p&gt;Finally, implement the Java code.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.yoshio3&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Arrays&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Properties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.DriverManager&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.PreparedStatement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.ResultSet&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.SQLException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.UUID&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.TimeUnit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.OpenAIClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.OpenAIClientBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.ai.openai.models.EmbeddingsOptions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.azure.core.credential.AzureKeyCredential&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VectorTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="no"&gt;LOGGER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VectorTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Azure OpenAI API KEY&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;OPENAI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Azure OpenAI Instance URL&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;OPENAI_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_JDBC_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;INPUT_DATA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Visual Studio Code for Java is an extension for the open-source code editor Visual Studio Code provided by Microsoft, which supports the Java programming language. It offers an environment for Java developers to efficiently write, build, debug, test, and execute code. Visual Studio Code is a lightweight text editor with multi-language support and high extensibility. For Java developers, Visual Studio Code for Java can be an excellent development environment. Visual Studio Code for Java can be used by installing the Java Development Kit (JDK), which is a basic toolset for compiling and running Java programs. To start a Java project in Visual Studio Code, install the JDK and then install the Java Extension Pack from the Visual Studio Code extension marketplace. The Java Extension Pack includes features such as Java language support, debugging, testing, and project management. The main features of Visual Studio Code for Java are as follows: 1. Syntax highlighting: Color-coding Java code to improve readability. 2. Code completion: Suggesting possible code while entering it, enabling efficient code writing.3. Code navigation: Easy jumping to classes, methods, variables, and finding definitions. 4. Refactoring: Changing the structure and names of code to improve its quality. 5. Debugging: Setting breakpoints, stepping through code, and monitoring variables. 6. Testing: Supporting testing frameworks such as JUnit and TestNG, allowing test creation, execution, and result display. 7. Project management: Supporting build tools such as Maven and Gradle, enabling project configuration and dependency management. 8. Git integration: Integrating with Git for source code version control. Visual Studio Code for Java offers a wealth of productivity-enhancing features and provides an environment suitable for Java project development. Additionally, the Visual Studio Code extension marketplace has various Java-related extensions, which can be added as needed. With these extensions, Java developers can use Visual Studio Code as an integrated development environment."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure App Service for Java is a fully managed platform on Microsoft's cloud platform Azure, designed for hosting, deploying, and managing Java applications. Azure App Service supports the development and execution of web applications, mobile apps, APIs, and other backend applications, allowing Java developers to quickly deploy and scale their applications. By abstracting infrastructure management, developers can focus on their application code. Azure App Service for Java includes the Java Development Kit (JDK) and a web server, supporting Java runtimes such as Tomcat, Jetty, and JBoss EAP. Furthermore, Azure App Service provides features to support the entire lifecycle of Java applications, such as building CI/CD (Continuous Integration/Continuous Delivery) pipelines, setting up custom domains, managing SSL certificates, and monitoring and diagnosing applications."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Container Apps is a fully managed service on Microsoft's cloud platform Azure for deploying, managing, and scaling container-based applications. Azure Container Apps is suitable for applications that implement microservices architecture, web applications, backend services, and job execution. This service abstracts container orchestration platforms like Kubernetes, freeing developers from infrastructure management and scaling, allowing them to focus on application code. Azure Container Apps deploys applications using Docker container images and provides features such as automatic scaling, rolling updates, and auto-recovery. Moreover, Azure Container Apps is platform-independent, supporting any programming language or framework. Developers can easily deploy applications using the Azure portal, Azure CLI, or CI/CD pipelines such as GitHub Actions.In terms of security, Azure Container Apps offers features like network isolation, private endpoints, and Azure Active Directory (AAD) integration, ensuring the safety of your applications. Additionally, it provides features to support application monitoring and diagnostics, enabling the identification of performance and issues using tools like Azure Monitor and Azure Application Insights."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Cosmos DB is a global, distributed multi-model database service from Microsoft, offering low latency, high availability, and high throughput. Cosmos DB is a NoSQL database that supports multiple data models, including key-value, document, column-family, and graph. This fully managed service caters to various applications and can be used for the development of web, mobile, IoT, and gaming solutions. The key features of Azure Cosmos DB include: Global distribution: Automatically replicates data across multiple geographic regions, providing high availability and low latency. Horizontal scaling: Utilizes partition keys to split data across multiple physical partitions, enabling flexible scaling of throughput and storage capacity. Five consistency models: Choose from five consistency models, ranging from strong to eventual consistency, depending on the consistency requirements of your globally distributed applications. Real-time analytics: Integrates with Azure Synapse Analytics and Azure Functions for real-time data processing and analysis. Additionally, Azure Cosmos DB offers multiple APIs, such as SQL API, MongoDB API, Cassandra API, Gremlin API, and Table API, enabling developers to build applications using familiar APIs. In terms of data security, Cosmos DB provides features like encryption, network isolation, and access control to ensure data protection. Furthermore, Azure Monitor and Azure Application Insights can be utilized to identify database performance and issues."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Kubernetes Service (AKS) is a Kubernetes cluster management service provided by Microsoft that simplifies the deployment, scaling, and operation of containerized applications. As a managed Kubernetes service, AKS automates tedious infrastructure management and update tasks, allowing developers to focus on application development. AKS offers enterprise-grade security, monitoring, and operational management features, and it easily integrates with DevOps pipelines. Additionally, it can work with other Azure services to support flexible application development. The main features and benefits of AKS are as follows: Cluster provisioning and scaling: AKS automates cluster infrastructure management, allowing you to add or remove nodes as needed, ensuring efficient resource usage and operations. Security and access control: AKS provides built-in Azure Active Directory (AD) integration and enables secure cluster access management using role-based access control (RBAC). Integration with CI/CD pipelines: AKS integrates with CI/CD tools such as Azure DevOps and Jenkins, automating application build, test, and deployment processes. Monitoring and logging: AKS integrates with monitoring tools like Azure Monitor, Prometheus, and Grafana, allowing you to monitor cluster performance and resource usage. Logs can be centrally managed through Azure Log Analytics. Networking and storage: AKS uses Azure Virtual Networks (VNet) to run clusters within private networks. It also provides persistent data storage using Azure Storage and Azure Disks. Collaboration with other Azure services: AKS can work with other Azure services such as Azure Functions and Azure Cosmos DB, extending the functionality of your applications. These features enable AKS to reduce the burden of infrastructure management and operations for developers, allowing them to focus on application development. The provision of enterprise-grade security, monitoring, and operational management features ensures a reliable user experience."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Cognitive Services is a cloud-based service that integrates AI capabilities provided by Microsoft, allowing you to easily add artificial intelligence features to applications, websites, and bots. Even without deep learning or machine learning expertise, you can use these features through APIs. Azure Cognitive Services is divided into the following five categories: 1. Vision: Analyzes images and videos, providing features such as facial recognition, image recognition, and Optical Character Recognition (OCR). It includes Computer Vision, Custom Vision, Face API, Form Recognizer, and Video Indexer. 2. Speech: Provides speech-related features such as speech recognition, speech synthesis, and speech translation. It includes Speech Services, Speech Translation, and Speaker Recognition. 3. Language: Offers natural language processing (NLP) capabilities, allowing text analysis, machine translation, document summarization, and keyword extraction. It includes Text Analytics, Language Understanding (LUIS), QnA Maker, and Translation. 4. Decision: Provides features to support decision-making and recommendations, enabling personalized content and actions for individual users. It includes Personalization, Anomaly Detector, and Content Moderator. 5. Web Search: Utilizes Bing's search engine to provide web search, image search, video search, news search, and map search capabilities. It includes Bing Web Search API, Bing Image Search API, Bing Video Search API, Bing News Search API, and Bing Maps API. By combining these AI features, you can improve user experience and enhance the value of applications and services. In addition, Azure Cognitive Services is designed with privacy and security in mind, allowing businesses and developers to use it with confidence."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Container Instances (ACI) is a service provided by Microsoft that allows quick and easy deployment of containers. With ACI, you can run application containers without managing virtual machines or orchestration, reducing the workload on infrastructure management for developers. ACI offers per-second billing, with costs generated based on resource usage. The main features and benefits are as follows: 1. Simple and fast deployment: ACI can deploy containers quickly using Docker container images. Containers running on ACI are also compatible with Docker commands and Kubernetes clusters. 2. No need to manage the operating system: ACI eliminates the need to manage and update the host OS, allowing developers to focus on application development and operations. 3. Seamless scaling: ACI enables flexible scaling of the number of containers, allowing you to increase or decrease resources according to load. 4. Security: ACI uses Azure's security features to protect containers and data, and also offers network isolation. 5. Flexible resource allocation based on requirements: With ACI, you can allocate CPU and memory individually, optimizing resources according to application requirements. 6. Event-driven container execution: ACI can be integrated with services like Azure Functions and Logic Apps to enable event-driven container execution. These features make Azure Container Instances effective for various scenarios, such as short-term workloads, batch processing, and development and testing environments. Additionally, by combining with AKS, you can also achieve container management with orchestration capabilities."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Data Lake Storage (ADLS) is a large-scale data lake solution provided by Microsoft, designed to efficiently store, process, and analyze petabyte-scale data. ADLS is part of Azure Storage and centrally manages unstructured, semi-structured, and structured data, enabling advanced analytics such as big data analysis, machine learning, and real-time analysis. The main features and benefits of ADLS are as follows: 1. Scalability: ADLS provides high scalability that can store petabyte-scale data, flexibly adapting to the growth of data. 2. Performance: ADLS offers optimized performance for large-scale data reads and writes, making it suitable for big data processing and real-time analysis. 3. Security and Compliance: ADLS provides security features such as data encryption, access control, and audit logs, addressing corporate compliance requirements. 4. High Compatibility: ADLS is compatible with the Hadoop Distributed File System (HDFS) and can be integrated with existing Hadoop ecosystems as well as big data analytics tools like Apache Spark and Azure Databricks. 5. Hierarchical Storage: ADLS offers three storage tiers - hot, cool, and archive - providing optimal cost-performance based on data access frequency. 6. Integration of Data Lake and Object Storage: Azure Data Lake Storage Gen2 integrates ADLS and Azure Blob Storage, offering a solution that combines the benefits of large-scale data lakes and object storage. Azure Data Lake Storage is a powerful platform for enterprises to efficiently manage large amounts of data and achieve advanced data processing, such as big data analysis and machine learning. This enables businesses to fully leverage the value of their data, gaining business insights and improving decision-making."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Azure Blob Storage is an object storage service provided by Microsoft, offering a cloud-based solution for storing and managing large amounts of unstructured data. It can securely and scalably store various types of data, such as text, binary data, images, videos, and log files. The main features and benefits are as follows: 1. Scalability: Azure Blob Storage provides high scalability that can store petabyte-scale data, flexibly adapting to the growth of data. 2. Performance: Azure Blob Storage offers high performance for data reads and writes, enabling rapid processing of large amounts of data. 3. Hierarchical Storage: Azure Blob Storage provides three storage tiers - hot, cool, and archive - offering optimal cost-performance based on data access frequency. 4. Security and Compliance: Azure Blob Storage offers security features such as data encryption, access control, and audit logs, addressing corporate compliance requirements. 5. Global Access: Azure Blob Storage leverages Microsoft's Azure data centers, allowing fast and secure data access from anywhere in the world. 6. Integration and Compatibility: Azure Blob Storage can be integrated with Azure Data Lake Storage Gen2, other Azure services, and on-premises systems, enabling centralized data management and analysis. Azure Blob Storage is effectively used in various scenarios, such as web applications, backups, archives, big data analytics, and IoT devices. This enables businesses to fully leverage the value of their data, gaining business insights and improving decision-making."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;OpenAIClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;VectorTest&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getResourceAsStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/application.properties"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="no"&gt;OPENAI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"azure.openai.api.key"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;OPENAI_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"azure.openai.url"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRESQL_JDBC_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"azure.postgresql.jdbcurl"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRESQL_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"azure.postgresql.user"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRESQL_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"azure.postgresql.password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIClientBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AzureKeyCredential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;OPENAI_URL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;VectorTest&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorTest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="c1"&gt;// Execute the insertion into the database only once.&lt;/span&gt;
            &lt;span class="c1"&gt;// test.insertDataToPostgreSQL();&lt;/span&gt;

            &lt;span class="c1"&gt;// Retrieve similar documents using vector search for the data registered in the DB&lt;/span&gt;
            &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findMostSimilarString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please tell me about Azure Blob Storage"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error : "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Invoke Azure OpenAI (text-embedding-ada-002)
     */&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;invokeTextEmbedding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;originalText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;EmbeddingsOptions&lt;/span&gt; &lt;span class="n"&gt;embeddingsOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmbeddingsOptions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originalText&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmbeddings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text-embedding-ada-002"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddingsOptions&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getEmbedding&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;insertDataToPostgreSQL&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;POSTGRESQL_JDBC_URL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_USER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;insertSql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INSERT INTO TBL_VECTOR_TEST (id, embedding, origntext) VALUES (?, ?::vector, ?)"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;originText&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;INPUT_DATA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Call the text embedding and obtain the vector array&lt;/span&gt;
                &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;invokeTextEmbedding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// Sleep for 10 seconds to prevent errors &lt;/span&gt;
            &lt;span class="c1"&gt;// due to sending a large number of requests in a short period of time&lt;/span&gt;
                &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;insertStatement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insertSql&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createArrayOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"double"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toArray&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;originText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection failure."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findMostSimilarString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;POSTGRESQL_JDBC_URL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_USER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Create a vector array by calling the text embedding for the string the user wants to search&lt;/span&gt;
            &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;invokeTextEmbedding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Embedding: \n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Search with the vector array (find the closest string to the user's input)&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;querySql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT origntext FROM TBL_VECTOR_TEST ORDER BY embedding &amp;lt;-&amp;gt; ?::vector LIMIT 1;"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;queryStatement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querySql&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;queryStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;resultSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queryStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;origntext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resultSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"origntext"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Origntext: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;origntext&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection failure."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Point 1
&lt;/h5&gt;

&lt;p&gt;A list of strings called &lt;code&gt;private final static List&amp;lt;String&amp;gt; INPUT_DATA&lt;/code&gt; is defined. This list contains descriptions of the following services, saved as a list of character arrays. As mentioned earlier, if newline characters are included, the results may not be accurate, so all newline characters are replaced with whitespace.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visual Studio Code&lt;/li&gt;
&lt;li&gt;Azure App Service for Java&lt;/li&gt;
&lt;li&gt;Azure Container Apps&lt;/li&gt;
&lt;li&gt;Azure Cosmos DB&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Service&lt;/li&gt;
&lt;li&gt;Azure Cognitive Service&lt;/li&gt;
&lt;li&gt;Azure Container Instances&lt;/li&gt;
&lt;li&gt;Azure Data Lake Storage &lt;/li&gt;
&lt;li&gt;Azure Blob Storage&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;
  
  
  Point 2
&lt;/h5&gt;

&lt;p&gt;In the following &lt;code&gt;invokeTextEmbedding&lt;/code&gt; method, the Azure OpenAI Embedded model is called. By providing a string to this method, a list of floating-point numbers is returned as the result.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;invokeTextEmbedding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;originalText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;EmbeddingsOptions&lt;/span&gt; &lt;span class="n"&gt;embeddingsOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmbeddingsOptions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originalText&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmbeddings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text-embedding-ada-002"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddingsOptions&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getEmbedding&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Point 3
&lt;/h5&gt;

&lt;p&gt;The following method takes one element at a time from the prepared list of strings (&lt;code&gt;INPUT_DATA&lt;/code&gt;), calls Azure OpenAI's Embedded, receives a multidimensional array (vector), and then saves it to the database. This process is for inserting test data, so please execute it only once.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;insertDataToPostgreSQL&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;insertDataToPostgreSQL&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;POSTGRESQL_JDBC_URL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_USER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;insertSql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INSERT INTO TBL_VECTOR_TEST (id, embedding, origntext) VALUES (?, ?::vector, ?)"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;originText&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;INPUT_DATA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Call the text embedding and obtain the vector array&lt;/span&gt;
                &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;invokeTextEmbedding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// Sleep for 10 seconds to prevent errors &lt;/span&gt;
            &lt;span class="c1"&gt;// due to sending a large number of requests in a short period of time&lt;/span&gt;
                &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;insertStatement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insertSql&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createArrayOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"double"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toArray&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;originText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;insertStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeUpdate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection failure."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Point 4
&lt;/h5&gt;

&lt;p&gt;Finally, compare the information stored in the database with the information entered by the user, and find the most relevant document.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;VectorTest&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorTest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="c1"&gt;// Retrieve similar documents using vector search for the data registered in the DB&lt;/span&gt;
            &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findMostSimilarString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please tell me about Azure Blob Storage"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this sample, the string "Please tell me about Azure Blob" is entered in the main() method as shown above. Please note that a multidimensional array is also created by calling &lt;code&gt;invokeTextEmbedding(data);&lt;/code&gt; for this string.&lt;/p&gt;

&lt;p&gt;That multidimensional array is passed to the following query:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT origntext FROM TBL_VECTOR_TEST ORDER BY embedding &amp;lt;-&amp;gt; ?::vector LIMIT 1;"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;LIMIT 1&lt;/code&gt; is specified above, only the most relevant document is output. If you want to return multiple results, change this value.&lt;/p&gt;

&lt;p&gt;Furthermore, the &lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt; notation can be changed. In PostgreSQL's &lt;code&gt;pgvector&lt;/code&gt;, you can calculate similarity by specifying one of the following three operators. Change the operator as needed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operator&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;-&amp;gt;&lt;/td&gt;
&lt;td&gt;Euclidean distance: measures the straight-line distance between two vectors in n-dimensional space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;#&amp;gt;&lt;/td&gt;
&lt;td&gt;Negative inner product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;=&amp;gt;&lt;/td&gt;
&lt;td&gt;Cosine similarity: measures the cosine of the angle between two vectors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Euclidean distance measures the straight-line distance between two vectors in n-dimensional space, while cosine similarity measures the cosine of the angle between two vectors.&lt;/p&gt;

&lt;p&gt;The query result is implemented to return the original text.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findMostSimilarString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;POSTGRESQL_JDBC_URL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_USER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;POSTGRESQL_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Create a vector array by calling the text embedding for the string the user wants to search&lt;/span&gt;
            &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;invokeTextEmbedding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Embedding: \n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Search with the vector array (find the closest string to the user's input)&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;querySql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT origntext FROM TBL_VECTOR_TEST ORDER BY embedding &amp;lt;-&amp;gt; ?::vector LIMIT 1;"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;queryStatement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querySql&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;queryStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;resultSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queryStatement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;origntext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resultSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"origntext"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Origntext: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;origntext&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection failure."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By using multidimensional vector arrays in this way, you can find highly relevant documents.&lt;br&gt;
If you have such use cases, please give it a try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference Information
&lt;/h2&gt;

&lt;p&gt;The reference information is listed below. Please take a look as needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/embeddings?tabs=console" rel="noopener noreferrer"&gt;Learn how to generate embeddings with Azure OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/cognitive-services/openai/tutorials/embeddings?tabs=command-line" rel="noopener noreferrer"&gt;Tutorial: Explore Azure OpenAI Service embeddings and document search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-use-pgvector" rel="noopener noreferrer"&gt;How to enable and use pgvector on Azure Database for PostgreSQL - Flexible Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/howto-optimize-performance-pgvector" rel="noopener noreferrer"&gt;How to optimize performance when using pgvector on Azure Database for PostgreSQL - Flexible Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>openai</category>
      <category>embedding</category>
      <category>ada</category>
    </item>
    <item>
      <title>MicroProfile Config in Azure Kubernetes Service</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Thu, 26 Mar 2020 05:19:42 +0000</pubDate>
      <link>https://dev.to/azure/microprofile-config-in-azure-kubernetes-service-37o6</link>
      <guid>https://dev.to/azure/microprofile-config-in-azure-kubernetes-service-37o6</guid>
      <description>&lt;h2&gt;
  
  
  1. MicroProfile Config in Azure Kubernetes Service
&lt;/h2&gt;

&lt;p&gt;The application should separates the external system configuration such like the connection information (DB and external HTTP endpoint). Because there is the difference in environment settings between development environment, test environment, and production environment.&lt;br&gt;
If you separate the configuration from the program source code, you can easily change the setting and you can write the settings in a setting file.&lt;br&gt;
By writing to an external setting file, you do not need to edit the application source code to switch the connection destination, and you can use the same source code without the test.&lt;/p&gt;

&lt;p&gt;Excluding configuration information is very important for building cloud-native applications.&lt;br&gt;&lt;br&gt;
「&lt;a href="https://12factor.net/"&gt;Refer：The Twelve Factors&lt;/a&gt; &lt;a href="https://12factor.net/config"&gt;III. Config&lt;/a&gt; : Store config in the environment」&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Twelve-Factor strict separation of config from code. 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With MicroProfile Config, the configuration information can be obtained from various locations.&lt;br&gt;
These configuration locations are called ConfigSources, and if the same property is defined in more than one ConfigSource, apply a policy to specify which values are valid.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From Java VM System Properties&lt;/li&gt;
&lt;li&gt;OS environment variables&lt;/li&gt;
&lt;li&gt;From external configuration files (.properties, .xml)&lt;/li&gt;
&lt;li&gt;External data sources such as LDAP, DB, and key-value stores&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In some situations, you may want to switch some data sources dynamically. Then, the changed value must use the updated content from the program without restarting the application.&lt;br&gt;&lt;br&gt;
To meet these requirment, MicroProfile Config makes the configured values available immediately after modification.&lt;/p&gt;
&lt;h2&gt;
  
  
  About Runtime for MicroProfile Config
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/index.html"&gt;Microprofile Config specifies only API&lt;/a&gt; and it does not include implementation.&lt;br&gt;&lt;br&gt;
The MicroProfile Config implementation is provided separately by each MicroProfile implementation provider like follow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://svn.apache.org/repos/asf/geronimo/components/config/trunk"&gt;Apache Geronimo Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.ibm.com/wasdev/"&gt;WebSphere Liberty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.payara.fish/documentation/microprofile/config.html"&gt;Payara Server and Payara Micro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/smallrye/smallrye-config"&gt;WildFly &amp;amp; Thorntail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microbean.github.io/microbean-microprofile-config/"&gt;microBean™ MicroProfile Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Overview of MicroProfile Config
&lt;/h2&gt;

&lt;p&gt;MicroProfile Config consists of a few APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/index.html"&gt;List of MicroProfile Config API 1.4&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/Config.html"&gt;Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigBuilder.html"&gt;ConfigBuilder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/inject/ConfigProperty.html"&gt;ConfigProperty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/ConfigProvider.html"&gt;ConfigProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigProviderResolver.html"&gt;ConfigProviderResolver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigSource.html"&gt;ConfigSource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigSourceProvider.html"&gt;ConfigSourceProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/Converter.html"&gt;Converter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Priority of ConfigSource
&lt;/h2&gt;

&lt;p&gt;MicroProfile Config consists of org.eclipse.microprofile.config.spi.ConfigSource. The ConfigSources has a priority and are sorted according to order. This allows you to overwrite the settings from outside.&lt;/p&gt;

&lt;p&gt;By default, there are three default ConfigSources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System.getProperties() (Priority = 400)&lt;/li&gt;
&lt;li&gt;System.getenv() (Priority = 300)&lt;/li&gt;
&lt;li&gt;META-INF/microprofile-config.properties file on ClassPath (default priority = 100, priority can be set individually by setting config_ordinal property in each file)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example,at first you can be specified the default values in the property file when packaging the application, and the values can be overridden later for each deployment in the environment value. *** "The higher the priority, the higher the priority." ***&lt;/p&gt;
&lt;h2&gt;
  
  
  Obtain the Configuration Value
&lt;/h2&gt;

&lt;p&gt;The MicroProfile Config specification provides two methods for obtain the setting value.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obtain the setting value programmatic &lt;/li&gt;
&lt;li&gt;Obtain the setting value using annotations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1. Obtain the setting value programmatic
&lt;/h3&gt;

&lt;p&gt;The following is an example of creating a Config instance programmatically and obtaining a configuration information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;  &lt;span class="nc"&gt;MyAppWithGetConfigFromProgram&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;invokeMicroserviceWithConfig&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create Config Instnce&lt;/span&gt;
        &lt;span class="nc"&gt;Config&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConfigProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConfig&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// Obtain the URL Endpoint from Config for Microservices A&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;microserviceA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"URL_OF_MICROSERVICE_A"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Invoke Microservices A&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;invokeMicroservice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;microserviceA&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To obtain the configuration information, at first you must get a &lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/Config.html"&gt;Config&lt;/a&gt;  instance. To get a Config instance programmatically, you can get it by calling &lt;a href="https://javadoc.io/static/org.eclipse.microprofile.config/microprofile-config-api/1.4/org/eclipse/microprofile/config/ConfigProvider.html#getConfig--"&gt;ConfigProvider#getConfig()&lt;/a&gt; method.&lt;br&gt;&lt;br&gt;
(An instance of the Config class is registered with the context class loader after it is created.)&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Obtain the setting value using annotations (Recommend)
&lt;/h3&gt;

&lt;p&gt;The following is an example of obtaining a Config instance using annotations and get configuration information with @ConfigProperty.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAppWithGetConfigFromAnnotation&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//The property url.microserviceA must exist in one of the configsources, otherwise a&lt;/span&gt;
    &lt;span class="c1"&gt;//DeploymentException will be thrown.&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"url.microserviceA"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;urlOfMicroserviceA&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//The following code injects an Optional value of port.microserviceA property.&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"port.microserviceA"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;portOfMicroserviceA&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Sample Application of MicroProfile Config
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Creating the MicroProfile Config sample project
&lt;/h3&gt;

&lt;p&gt;Please access to the following URL and create the MicroProfile Project?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://start.microprofile.io/"&gt;MicroProfile Starter&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z_reu7bS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://live.staticflickr.com/65535/49650925377_1310626472_z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z_reu7bS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://live.staticflickr.com/65535/49650925377_1310626472_z.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After enter the value to the form, you can get the MPConfigSample.zip file by pushing the "DOWNLOAD" button. After unarchive the zip file, you can see like the following directory structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="c"&gt;.
&lt;/span&gt;&lt;span class="go"&gt;├── pom.xml
├── readme.md
└── src
    └── main
        ├── java
        │   └── com
        │       └── yoshio3
        │           └── MPConfigSample
        │               ├── HelloController.java
        │               ├── MPConfigSampleRestApplication.java
        │               └── config
        │                   └── ConfigTestController.java
        ├── resources
        │   └── META-INF
        │       └── microprofile-config.properties
        └── webapp
            ├── WEB-INF
            │   └── beans.xml
            └── index.html
11 directories, 8 files
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And the sample code of MicroProfile Config is wrote in ConfigTestController.java as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.yoshio3.MPConfigSample.config&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.microprofile.config.Config&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.microprofile.config.ConfigProvider&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.microprofile.config.inject.ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.enterprise.context.RequestScoped&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.inject.Inject&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.GET&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.Path&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/config"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@RequestScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigTestController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"injected.value"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;injectedValue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/injected"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getInjectedConfigValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Config value as Injected by CDI "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;injectedValue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/lookup"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getLookupConfigValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Config&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConfigProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConfig&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Config value from ConfigProvider "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above code is very simple that returns the value in the property as an HTTP response.&lt;br&gt;
If you invoke the HTTP Endpoint like belows,  the character string  which you specify in Config value will be returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8080/data/config/injected
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8080/data/config/lookup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The actual settings are configured in the microprofile-config.properties file under the META_INF directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Location of the Property file
&lt;span class="go"&gt;└── src
    └── main
        ├── resources
        │   └── META-INF
        │       └── microprofile-config.properties
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The following properties are set by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;injected.value=Injected value
value=lookup value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Build and run the sample project
&lt;/h3&gt;

&lt;p&gt;Build the project and launch the application to confirm the MicroProfile Config behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Build the Project
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mvn clean package
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Launch the Application
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; target/MPConfigSample-microbundle.jar 
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="c"&gt;......
&lt;/span&gt;&lt;span class="go"&gt;Payara Micro URLs:
http://192.168.100.7:8080/

'ROOT' REST Endpoints:
GET     /data/application.wadl
GET     /data/config/injected
GET     /data/config/lookup
GET     /data/hello
GET     /openapi/
GET     /openapi/application.wadl
]]
&lt;/span&gt;&lt;span class="gp"&gt;[2020-03-10T22:19:06.610+0900] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583846346610] [levelValue: 800] Payara Micro  5.194 #&lt;/span&gt;badassmicrofish &lt;span class="o"&gt;(&lt;/span&gt;build 327&lt;span class="o"&gt;)&lt;/span&gt; ready &lt;span class="k"&gt;in &lt;/span&gt;32,755 &lt;span class="o"&gt;(&lt;/span&gt;ms&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;[2020-03-10T22:19:33.646+0900] [] [INFO] [] [javax.enterprise.system.container.web.com.sun.web.security] [tid: _ThreadID=29 _ThreadName=http-thread-pool::http-listener(1)] [timeMillis: 1583846373646] [levelValue: 800] Context path from ServletContext:  differs from path from bundle: /
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the application is started as described above, execute the curl command to confirm the behavior.&lt;br&gt;&lt;br&gt;
If it works correctly, the string of the setting (Injected value, value) obtained from the property file is displayed as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Invoke endpoint to the destination which is implemented as annotation
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl localhost:8080/data/config/injected
&lt;span class="go"&gt;Config value as Injected by CDI Injected value

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Invoke endpoint to the destination which is implemented as programatic
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl localhost:8080/data/config/lookup
&lt;span class="go"&gt;Config value from ConfigProvider lookup value
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In MicroProfile, the setting value of the property file can be overwritten by the system property or environment value. Then you can overwrite the value set in the "microprofile-config.properties" file and confirm that the value set in the environment variable is displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Configure the Environment Value &lt;span class="o"&gt;[&lt;/span&gt;Replace the character from .&lt;span class="o"&gt;(&lt;/span&gt;dot&lt;span class="o"&gt;)&lt;/span&gt; to _&lt;span class="o"&gt;(&lt;/span&gt;under bar&lt;span class="o"&gt;)]&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;injected_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Environment Value"&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Run the app with Java system properties which is configured on the environment variables
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;java &lt;span class="nt"&gt;-D&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$injected_value&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-jar&lt;/span&gt; target/MPConfigSample-microbundle.jar
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Confirm the Application Behavior
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl http://localhost:8080/data/config/injected
&lt;span class="go"&gt;Config value as Injected by CDI Environment Value
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: Although the property file is written in. (Dot) notation, environment variables cannot use. (Dot) notation in some OS environment. Therefore, in the environment variable settings, replace the .(Dot) notation with _(under bar). Conversion is performed automatically inside the implementation.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Run the Application on Local Docker Environment
&lt;/h3&gt;

&lt;p&gt;Now the application has been verified in the local environment, next you can run MicroProfile in the local Docker environment.&lt;br&gt;&lt;br&gt;
To create a Docker image of Payara Micro's, please create the following Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; payara/micro:5.201&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; payara&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; ${PAYARA_HOME}&lt;/span&gt;

&lt;span class="c"&gt;# Deploy Artifact&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./target/MPConfigSample.war $DEPLOY_DIR&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["--nocluster","--deploymentDir", "/opt/payara/deployments", "--contextroot", "app"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, please build and create an image of the container using the above Dockerfile?&lt;br&gt;&lt;br&gt;
Please execute following command?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; tyoshio2002/payara-config-sample:1.0 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Console output will be look like follows
&lt;span class="go"&gt;Sending build context to Docker daemon  151.2MB
Step 1/5 : FROM payara/micro:5.201
5.201: Pulling from payara/micro
050382585609: Already exists 
59f5185426ac: Already exists 
4d95208cd9c0: Pull complete 
c1409397cf71: Pull complete 
Digest: sha256:3ff92627d0d9b67454ee241cc7d5f2e485e46db81a886c87cf16035df7c80cc8
Status: Downloaded newer image for payara/micro:5.201
&lt;/span&gt;&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a11a548b0a25
&lt;span class="go"&gt;Step 2/5 : USER payara
&lt;/span&gt;&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Running &lt;span class="k"&gt;in &lt;/span&gt;cb755e484e79
&lt;span class="go"&gt;Removing intermediate container cb755e484e79
&lt;/span&gt;&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;564283252ae4
&lt;span class="gp"&gt;Step 3/5 : WORKDIR $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;PAYARA_HOME&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Running &lt;span class="k"&gt;in &lt;/span&gt;f26dd5cd172c
&lt;span class="go"&gt;Removing intermediate container f26dd5cd172c
&lt;/span&gt;&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;f2bf88b18a77
&lt;span class="gp"&gt;Step 4/5 : COPY ./target/MPConfigSample.war $&lt;/span&gt;DEPLOY_DIR
&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;1b54373fe95a
&lt;span class="go"&gt;Step 5/5 : CMD ["--nocluster","--deploymentDir", "/opt/payara/deployments", "--contextroot", "app"]
&lt;/span&gt;&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Running &lt;span class="k"&gt;in &lt;/span&gt;3eb731eb77c3
&lt;span class="go"&gt;Removing intermediate container 3eb731eb77c3
&lt;/span&gt;&lt;span class="gp"&gt; ---&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;1d11549e99b8
&lt;span class="go"&gt;Successfully built 1d11549e99b8
Successfully tagged tyoshio2002/payara-config-sample:1.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the container image is created, please start the container?&lt;br&gt;&lt;br&gt;
Please execute the following command to start the container?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;injected_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;FOOBAR &lt;span class="nt"&gt;-it&lt;/span&gt; tyoshio2002/payara-config-sample:1.0
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Console output will be look like follows
&lt;span class="c"&gt;..... 
&lt;/span&gt;&lt;span class="go"&gt;[2020-03-11T07:46:59.119+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819119] [levelValue: 800] [[ 
{
    "Instance Configuration": {
        "Host": "3877abb54d57",
        "Http Port(s)": "8080",
        "Https Port(s)": "",
        "Instance Name": "payara-micro",
        "Instance Group": "no-cluster",
        "Deployed": [
            {
                "Name": "MPConfigSample",
                "Type": "war",
                "Context Root": "/app"
            }
        ]
    }
}]]
[2020-03-11T07:46:59.131+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819131] [levelValue: 800] [[
Payara Micro URLs:
http://3877abb54d57:8080/app
'MPConfigSample' REST Endpoints:
GET /app/data/application.wadl
GET /app/data/config/injected
GET /app/data/config/lookup
GET /app/data/hello
]]
&lt;/span&gt;&lt;span class="gp"&gt;[2020-03-11T07:46:59.131+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819131] [levelValue: 800] Payara Micro  5.201 #&lt;/span&gt;badassmicrofish &lt;span class="o"&gt;(&lt;/span&gt;build 512&lt;span class="o"&gt;)&lt;/span&gt; ready &lt;span class="k"&gt;in &lt;/span&gt;31,286 &lt;span class="o"&gt;(&lt;/span&gt;ms&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that the created container has been started, please access to the application running on the container?&lt;br&gt;&lt;br&gt;
This time, the port 8080 inside the container is mapped to the local port 8080 at startup, so you can connect to the container application by accessing port 8080 in the local environment.&lt;br&gt;
Please execute the following command?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl http://localhost:8080/app/data/config/injected
&lt;span class="go"&gt;Config value as Injected by CDI FOOBAR
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we gave an startup argument of the environment variable (&lt;strong&gt;&lt;em&gt;-e injected_value = FOOBAR&lt;/em&gt;&lt;/strong&gt;), the character string will be displayed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Run the Application on Azure Kubernetes Service
&lt;/h3&gt;

&lt;p&gt;The basic operation was confirmed in the local Docker environment, so we will also confirm in the &lt;a href="https://aka.ms/docs-aks-tutorial"&gt;Azure Kubernetes Service&lt;/a&gt; environment.   &lt;/p&gt;

&lt;p&gt;Following is the procedure to confirm.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a resource group for Azure Container Registry&lt;/li&gt;
&lt;li&gt;Create Azure Container Registry&lt;/li&gt;
&lt;li&gt;Confirm Azure Container Registry password&lt;/li&gt;
&lt;li&gt;Log in to Azure Container Registry and push the image&lt;/li&gt;
&lt;li&gt;Confirm the image which is pushed to Azure Container Registrys&lt;/li&gt;
&lt;li&gt;Create resource group for Azure Kubernetes Service&lt;/li&gt;
&lt;li&gt;Create service principal for Azure Kubernetes Service&lt;/li&gt;
&lt;li&gt;Grant ACR read permission so that AKS can reference ACR resources&lt;/li&gt;
&lt;li&gt;Create AKS&lt;/li&gt;
&lt;li&gt;Install kubectl command and get AKS connection information&lt;/li&gt;
&lt;li&gt;Create Deployment YAML&lt;/li&gt;
&lt;li&gt;Apply Deployment YAML&lt;/li&gt;
&lt;li&gt;Confirm the Pod behavior&lt;/li&gt;
&lt;li&gt;Set and update environment variables&lt;/li&gt;
&lt;li&gt;Getting configuration information from Kubernetes Config Map&lt;/li&gt;
&lt;li&gt;Update Config Map values and restart pod&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  4.1. Create a resource group for Azure Container Registry
&lt;/h4&gt;

&lt;p&gt;First, please create &lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; and upload the image of Docker image which is created on local?&lt;br&gt;&lt;br&gt;
So, please create a resource group for the Azure Container Registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az group create &lt;span class="nt"&gt;--name&lt;/span&gt; WebApp-Containers &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s2"&gt;"Japan East"&lt;/span&gt;
&lt;span class="go"&gt;{
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers",
  "location": "japaneast",
  "managedBy": null,
  "name": "WebApp-Containers",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2. Create Azure Container Registry
&lt;/h4&gt;

&lt;p&gt;Next, Pleasr create the Azure Container Registry with following options?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name: Specify the name of Container Registry&lt;/li&gt;
&lt;li&gt;--resource-group: Specify the name of the Resouce Group which is created in the above step &lt;/li&gt;
&lt;li&gt;--sku: Specify one of the following "Basic", "Standard", "Premium"
&lt;/li&gt;
&lt;li&gt;--admin-enabled: If you specify "true", you can login to the registry by docker command.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az acr create &lt;span class="nt"&gt;--name&lt;/span&gt; containerreg4yoshio &lt;span class="nt"&gt;--resource-group&lt;/span&gt; WebApp-Containers &lt;span class="nt"&gt;--sku&lt;/span&gt; Basic &lt;span class="nt"&gt;--admin-enabled&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="go"&gt;{
  "adminUserEnabled": true,
  "creationDate": "2020-03-12T02:27:59.357654+00:00",
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio",
  "location": "japaneast",
  "loginServer": "containerreg4yoshio.azurecr.io",
  "name": "containerreg4yoshio",
  "networkRuleSet": null,
  "policies": {
    "quarantinePolicy": {
      "status": "disabled"
    },
    "retentionPolicy": {
      "days": 7,
      "lastUpdatedTime": "2020-03-12T02:28:01.654662+00:00",
      "status": "disabled"
    },
    "trustPolicy": {
      "status": "disabled",
      "type": "Notary"
    }
  },
  "provisioningState": "Succeeded",
  "resourceGroup": "WebApp-Containers",
  "sku": {
    "name": "Basic",
    "tier": "Basic"
  },
  "status": null,
  "storageAccount": null,
  "tags": {},
  "type": "Microsoft.ContainerRegistry/registries"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.3. Confirm Azure Container Registry password
&lt;/h4&gt;

&lt;p&gt;Next, please confirm the password to connect to Azure Container Registry?&lt;br&gt;
  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name: Specify container registry name&lt;/li&gt;
&lt;li&gt;--resource-group: Specify the resource group name which is created above
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az acr credential show &lt;span class="nt"&gt;--name&lt;/span&gt; containerreg4yoshio &lt;span class="nt"&gt;--resource-group&lt;/span&gt; WebApp-Containers
&lt;span class="go"&gt;{
  "passwords": [
    {
      "name": "password",
      "value": "4zaIiLk*************+H1XO4AlYFvN"
    },
    {
      "name": "password2",
      "value": "fT03XPs*************Oq2cAZiVHV+L"
    }
  ],
  "username": "containerreg4yoshio"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  4.4. Log in to Azure Container Registry and push the image
&lt;/h4&gt;

&lt;p&gt;Next, please execute the docker login command to connect to Azure Container Registry?&lt;br&gt;
(For the password, enter the password obtained above.)  &lt;/p&gt;

&lt;p&gt;Once you have logged in, tag your images with the docker tag command. The new tag is used locally created Docker container image name with the "loginServer" name of the container registry (for example, "containerreg4yoshio.azurecr.io").&lt;/p&gt;

&lt;p&gt;Finally, run the docker push command to push the image to Azure Container Registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Login to the Azure Container Registry 
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker login containerreg4yoshio.azurecr.io &lt;span class="nt"&gt;-u&lt;/span&gt; containerreg4yoshio
&lt;span class="go"&gt;Password: 
Login Succeeded

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Tag of Docker Image
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker tag tyoshio2002/payara-config-sample:1.0 containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Push the Docker Image to Azure Container Registry
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker push containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0
&lt;span class="go"&gt;
The push refers to repository [containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample]
bbd197848553: Pushed 
ec40a5d738cc: Pushed 
f95fe3528c56: Pushed 
bded2364df91: Pushed 
1bfeebd65323: Pushed 
1.0: digest: sha256:689dbacc212d37afe09c43417bc79d8e241c3fa7b5cf71c27097ef535cf77f76 size: 1368
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.5. Confirm the image which is pushed to Azure Container Registry
&lt;/h4&gt;

&lt;p&gt;Please verify that the image has been successfully pushed to Azure Container Registry?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az acr repository list &lt;span class="nt"&gt;-n&lt;/span&gt; containerreg4yoshio &lt;span class="nt"&gt;-g&lt;/span&gt; WebApp-Containers
&lt;span class="go"&gt;Argument 'resource_group_name' has been deprecated and will be removed in a future release.
[
  "tyoshio2002/payara-config-sample"
]

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az acr repository show-tags &lt;span class="nt"&gt;--name&lt;/span&gt; containerreg4yoshio  &lt;span class="nt"&gt;--repository&lt;/span&gt; tyoshio2002/payara-config-sample
&lt;span class="go"&gt;[
  "1.0"
]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.6. Create Resource Group for Azure Kubernetes Service
&lt;/h4&gt;

&lt;p&gt;Next, please create resource group for Azure Kubernetes Service (AKS)?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az group create &lt;span class="nt"&gt;--name&lt;/span&gt; MC_yoshio-aks &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s2"&gt;"Japan East"&lt;/span&gt;
&lt;span class="go"&gt;{
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/MC_yoshio-aks",
  "location": "japaneast",
  "managedBy": null,
  "name": "MC_yoshio-aks",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.7. Create service principal for Azure Kubernetes Service
&lt;/h4&gt;

&lt;p&gt;Then please create Service Principal. In this time, there was no assignment for role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az ad sp create-for-rbac &lt;span class="nt"&gt;--skip-assignment&lt;/span&gt;
&lt;span class="go"&gt;{
  "appId": "884ac0da-****-****-****-c9e2d3fce495",
  "displayName": "azure-cli-2020-03-13-03-12-59",
  "name": "http://azure-cli-2020-03-13-03-12-59",
  "password": "03a0e079-****-****-****-a760333af0b0",
  "tenant": "72f988bf-****-****-****-2d7cd011db47"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.8. Grant ACR read permission so that AKS can reference ACR resources
&lt;/h4&gt;

&lt;p&gt;When you are using Azure, do not register the connection information to the container registry in Kubernetes (usually register and use the connection information in Secret), use the service principal of Azure Active Directory (Azure AD) of Azure , You can get images of containers that exist in the Azure Container Registry.&lt;/p&gt;

&lt;p&gt;Refer: &lt;a href="(https://aka.ms/serviceprincipal-auth-for-acr)"&gt;Azure Container Registry authentication by service principal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, you need to get the ACR resource ID with the az acr show command to grant permissions to the ACR.&lt;/p&gt;

&lt;p&gt;Next, use the az role assignment create command to grant acrpull to the service principal (created above) used by AKS for ACR.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--assignee: specifiy appId ("appId": "884ac0da-*&lt;strong&gt;&lt;em&gt;-&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;-&lt;/em&gt;***-c9e2d3fce495",)&lt;/li&gt;
&lt;li&gt;--scope:  specifiy the ID of the above ACR&lt;/li&gt;
&lt;li&gt;--role: acrpull role allows you to pull images from ACR (no security settings in YAML)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az acr show &lt;span class="nt"&gt;--resource-group&lt;/span&gt; WebApp-Containers &lt;span class="nt"&gt;--name&lt;/span&gt; containerreg4yoshio &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; tsv
&lt;span class="go"&gt;/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az role assignment create &lt;span class="nt"&gt;--assignee&lt;/span&gt; 884ac0da-&lt;span class="k"&gt;****&lt;/span&gt;-&lt;span class="k"&gt;****&lt;/span&gt;-&lt;span class="k"&gt;****&lt;/span&gt;&lt;span class="nt"&gt;-c9e2d3fce495&lt;/span&gt; &lt;span class="nt"&gt;--scope&lt;/span&gt; /subscriptions/f77aafe8-&lt;span class="k"&gt;****&lt;/span&gt;-&lt;span class="k"&gt;****&lt;/span&gt;-&lt;span class="k"&gt;****&lt;/span&gt;&lt;span class="nt"&gt;-d0c37687ef70&lt;/span&gt;/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio &lt;span class="nt"&gt;--role&lt;/span&gt; acrpull
&lt;span class="go"&gt;{
  "canDelegate": null,
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio/providers/Microsoft.Authorization/roleAssignments/72cbc68a-****-****-****-1a66c8568cba",
  "name": "72cbc68a-****-****- ****-1a66c8568cba",
  "principalId": "33472555-****-****-****-31e2064fb702",
  "principalType": "ServicePrincipal",
  "resourceGroup": "WebApp-Containers",
  "roleDefinitionId": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/providers/Microsoft.Authorization/roleDefinitions/7f951dda-****-****-****-43fe172d538d",
  "scope": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio",
  "type": "Microsoft.Authorization/roleAssignments"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.9. Create AKS
&lt;/h4&gt;

&lt;p&gt;Finally you can create the AKS with following options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--resource-group: specify the resource group name created in 4.6&lt;/li&gt;
&lt;li&gt;--name: specify the name of the AKS cluster&lt;/li&gt;
&lt;li&gt;--kubernetes-version: specify the Kubernetes version of the AKS cluster&lt;/li&gt;
&lt;li&gt;--node-vm-size: specifies the VM size&lt;/li&gt;
&lt;li&gt;--node-count: specifies the number of Kubernetes worker nodes&lt;/li&gt;
&lt;li&gt;--location: specifies East Japan as location&lt;/li&gt;
&lt;li&gt;--service-principal: specifies appId which is created on the step 4.7&lt;/li&gt;
&lt;li&gt;--client-secret: specifies the password which is created on the step 4.7&lt;/li&gt;
&lt;li&gt;--generate-ssh-keys: creates SSH keys (Public, Private) in .ssh directory in home directory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az aks create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource-group&lt;/span&gt; MC_yoshio-aks &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; yoshioAKSCluster1164 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--kubernetes-version&lt;/span&gt; 1.16.4 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--node-vm-size&lt;/span&gt; Standard_DS2_v2 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--node-count&lt;/span&gt; 3 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; japaneast &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--service-principal&lt;/span&gt; &lt;span class="s2"&gt;"884ac0da-****-****-****-c9e2d3fce495"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--client-secret&lt;/span&gt;  &lt;span class="s2"&gt;"03a0e079-****-****-****-a760333af0b0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--generate-ssh-keys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note: The above commands is for development environment and verification environment. In order to build the production environment, you need more options like virtual network, subnet in association with external service, availability zone for availability. Many options need to be specified. See below for details on the az aks create command.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://aka.ms/detail-az-aks-options"&gt;Refer：detail of az aks command&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4.10. Install kubectl command and get AKS connection information
&lt;/h4&gt;

&lt;p&gt;In order to manage the AKS, you need to use the kubectl command. If you are working with Kubernetes for the first time, you may not have the kubectl command in your operating environment. If the kubectl command is not installed, execute the az aks install-cli command to obtain it.&lt;/p&gt;

&lt;p&gt;After got the kubectl command, you can manage the AKS by using the kubectl command. To connect to the created AKS, you need to get the connection information. Therefore, execute the az aks get-credentials command to obtain connection information (credentials) for AKS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Install the kubectl &lt;span class="nb"&gt;command&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az aks install-cli
&lt;span class="go"&gt;Downloading client to "/usr/local/bin/kubectl" from "https://storage.googleapis.com/kubernetes-release/release/v1.17.4/bin/darwin/amd64/kubectl"
Please ensure that /usr/local/bin is in your search PATH, so the `kubectl` command can be found.
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;which kubectl 
&lt;span class="go"&gt;/usr/local/bin/kubectl

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Obtain the connection infor&lt;span class="o"&gt;(&lt;/span&gt;credential&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;AKS
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az aks get-credentials &lt;span class="nt"&gt;--resource-group&lt;/span&gt; MC_yoshio-aks &lt;span class="nt"&gt;--name&lt;/span&gt; yoshioAKSCluster1164
&lt;span class="go"&gt;Merged "yoshioAKSCluster1164" as current context in /Users/yoterada/.kube/config

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Confirm which version of kubernetes is running
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl version
&lt;span class="go"&gt;Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.4", GitCommit:"8d8aa39598534325ad77120c120a22b3a990b5ea", GitTreeState:"clean", BuildDate:"2020-03-12T21:03:42Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.4", GitCommit:"224be7bdce5a9dd0c2fd0d46b83865648e2fe0ba", GitTreeState:"clean", BuildDate:"2019-12-13T20:40:52Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.11. Create Deployment YAML
&lt;/h4&gt;

&lt;p&gt;After evaluated the AKS running, in order to run the container on AKS, please create a YAML file for Deployment?&lt;/p&gt;

&lt;p&gt;Create the following YAML file and save it as deployment.yaml.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
        &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
        &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000&lt;/span&gt; 
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.12. Apply Deployment YAML
&lt;/h4&gt;

&lt;p&gt;After created the Deployment YAML file, please apply the deployment yaml file to the AKS environment? Please execute the following command to apply the YAML file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml 
&lt;span class="go"&gt;deployment.apps/payara-config-service created
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.13. Confirm the Pod behavior
&lt;/h4&gt;

&lt;p&gt;If you execute the "kubectl get po" command, you can verify the STATUS is Running when it was deploied correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get po
&lt;span class="go"&gt;NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-85f5cdd768-42sh8   1/1     Running   0          28s
payara-config-service-85f5cdd768-fhjrh   1/1     Running   0          28s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If the Running status is not showed, please execute the following command to confirm the cause?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl describe po payara-config-service-85f5cdd768-42sh8  
&lt;span class="go"&gt;
Or
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl logs payara-config-service-85f5cdd768-42sh8  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If the status is Running, the application is running. however it is impossible to access to the application from outside of the AKS cluster. Because there is no public endpoint nor public IP addoress like follows (10.244.2.3 is private IP addoress).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get po &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;span class="go"&gt;NAME                                     READY   STATUS    RESTARTS   AGE   IP           NODE                                NOMINATED NODE   READINESS GATES
&lt;/span&gt;&lt;span class="gp"&gt;payara-config-service-85f5cdd768-42sh8   1/1     Running   0          12d   10.244.2.3   aks-nodepool1-14395993-vmss000002   &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&amp;lt;none&amp;gt;
&lt;span class="gp"&gt;payara-config-service-85f5cdd768-fhjrh   1/1     Running   0          12d   10.244.1.5   aks-nodepool1-14395993-vmss000000   &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&amp;lt;none&amp;gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So In order to access to the application, please execute the following port-forard command? Then you can access to the application from localhost.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl port-forward payara-config-service-85f5cdd768-42sh8 8080:8080
&lt;span class="gp"&gt;Forwarding from 127.0.0.1:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;span class="gp"&gt;Forwarding from [::1]:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After executed the port-forward command, please open another new terminal and start the curl command (or open new browser) to access the application.&lt;br&gt;
If the text is displayed as shown like below, the application is working properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl localhost:8080/app/data/config/injected
&lt;span class="go"&gt;Config value as Injected by CDI Injected value
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.14. Set and update environment variables
&lt;/h4&gt;

&lt;p&gt;We could confirm the application is running in the above steps, but since the environment variables have not been set at this time, in this time the value is took from the properties file.&lt;br&gt;
So we will modify the Kubernetes' Deployment YAML to take values from environment variables outside the application without redeploy.&lt;/p&gt;

&lt;p&gt;The YAML settings to be added are as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;injected_value&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENVIRONMENT VALUE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The modified all of YAML file is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
        &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
        &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000&lt;/span&gt; 
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;injected_value&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENVIRONMENT VALUE&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After modified the above YAML file, please apply the YAML file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt;  deployment.yaml 
&lt;span class="go"&gt;deployment.apps/payara-config-service configured
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After applyed the YAML file, it will launch a new pod with a rolling upgrade. Obtain the name of new Pod and  execute the port-foward command to access from locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;List of all Pods
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get po
&lt;span class="go"&gt;NAME                                    READY   STATUS    RESTARTS   AGE
payara-config-service-58cdfd6c7-gfvcl   1/1     Running   0          37s
payara-config-service-58cdfd6c7-hdm6c   1/1     Running   0          48s

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Port Forawrd &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;local &lt;/span&gt;access
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl port-forward payara-config-service-58cdfd6c7-gfvcl 8080:8080
&lt;span class="gp"&gt;Forwarding from 127.0.0.1:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;span class="gp"&gt;Forwarding from [::1]:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After por-forward for new pod, you can access to the endpoint via curl command or browser.&lt;br&gt;&lt;br&gt;
Then, the environment variables defined in the YAML file will be displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl http://localhost:8080/app/data/config/injected
&lt;span class="go"&gt;Config value as Injected by CDI ENVIRONMENT VALUE
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.15. Getting configuration information from Kubernetes Config Map
&lt;/h4&gt;

&lt;p&gt;In Kubernetes, we can manage centrally the configuration separately from the container management (deployment.yaml).&lt;br&gt;
&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/"&gt;Config Map&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Therefore, we can configure the environment variables in the Config Map.  &lt;/p&gt;

&lt;p&gt;Please create the following Config Map YAML file and save it as configmap.yaml.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;microprofile-service-config&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;injected_value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CONFIG&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;MAP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;VALUE"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, Please apply the Config Map?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Apply the Config Map
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; configmap.yaml 
&lt;span class="go"&gt;configmap/microprofile-service-config createds

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Confirm the applied Config Map
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get cm
&lt;span class="go"&gt;NAME                          DATA   AGE
microprofile-service-config   1      37m
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, Please modify the Deployment YAML file to refer to the value of the Config Map from the Kubernetes Pod.&lt;/p&gt;

&lt;p&gt;The modifications point is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;injected_value&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;configMapKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;microprofile-service-config&lt;/span&gt;
                &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;injected_value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The modified Deployment YAML is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
        &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
        &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000&lt;/span&gt; 
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payara-config-service&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;injected_value&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;configMapKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;microprofile-service-config&lt;/span&gt;
                &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;injected_value&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Please apply after modifying Deployment YAML?&lt;br&gt;&lt;br&gt;
After applying, please confirm that STATUS is Running?&lt;br&gt;&lt;br&gt;
Please execute the port-forward to access to the pod.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Apply the Deployment YAML 
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt;  deployment.yaml 
&lt;span class="go"&gt;deployment.apps/payara-config-service configured

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;List of all Pods 
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get po
&lt;span class="go"&gt;NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-68bb7c8dfb-8tcbx   1/1     Running   0          22s
payara-config-service-68bb7c8dfb-f67x6   1/1     Running   0          20s

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Execute the port-forward to access to the Pod from &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl port-forward payara-config-service-68bb7c8dfb-8tcbx 8080:8080
&lt;span class="gp"&gt;Forwarding from 127.0.0.1:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;span class="gp"&gt;Forwarding from [::1]:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After executed the port-forward command, please access to the application endpoint. Then you can confirm that the value specified in Config Map (CONFIG MAP VALUE) is displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl http://localhost:8080/app/data/config/injected
&lt;span class="go"&gt;Config value as Injected by CDI CONFIG MAP VALUE
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we could confirm that we can get the value from Config Map of Kubernetes.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.16. Update Config Map values and restart pod
&lt;/h4&gt;

&lt;p&gt;Finally, please confirm how to update the value of the Config.&lt;/p&gt;

&lt;p&gt;Update the value of Config Map like follows which is configured on the step 4.15.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;microprofile-service-config&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;injected_value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CONFIG&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;MAP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;VALUE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;NEW"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After saved the file, Please apply the updated Config Map?&lt;br&gt;
After applied it, please  execute the describe command to confirm the value had change correctly?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Apply the new Config Map
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; configmap.yaml 
&lt;span class="go"&gt;configmap/microprofile-service-config configured

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Confirm the value had modified correctly on the Config Map
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl describe cm microprofile-service-config
&lt;span class="go"&gt;Name:         microprofile-service-config
Namespace:    default
&lt;/span&gt;&lt;span class="gp"&gt;Labels:       &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":{"injected_value":"CONFIG MAP VALUE NEW"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"microprofile-...

Data
====
injected_value:
----
CONFIG MAP VALUE NEW
&lt;/span&gt;&lt;span class="gp"&gt;Events:  &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After applied the new Config Map, please access the application endpoint? In this time, you may confirm that the new settings are not reflected. Because the Kubernetes Pod read the environment value during the startup time and not automatically reloading. As a result it will show the old configuration information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI CONFIG MAP VALUE
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So you need to restart the pod to reflect the setting information.&lt;br&gt;
In order to restart the pod, plese delete the existing pod? The Kubernetes Cluster will automatically create and launched the new pod. (Because the Pod is guaranteed to start for the number of replicas in Deployment YAML)&lt;/p&gt;

&lt;p&gt;After getting the list of all pods and please delete one of the pod and wait for the new pod to be restarted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;List of all Pod 
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get po
&lt;span class="go"&gt;NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-68bb7c8dfb-8tcbx   1/1     Running   0          4m24s
payara-config-service-68bb7c8dfb-f67x6   1/1     Running   0          4m22s

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Delete one of the Pod
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl delete po payara-config-service-68bb7c8dfb-8tcbx
&lt;span class="go"&gt;pod "payara-config-service-68bb7c8dfb-8tcbx" deleted

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;List of all Pod （payara-config-service-68bb7c8dfb-dx7sg is new created pod）
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get po
&lt;span class="go"&gt;NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-68bb7c8dfb-dx7sg   1/1     Running   0          26s
payara-config-service-68bb7c8dfb-f67x6   1/1     Running   0          5m27s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Please execute the port-forwad command to accessed from locally?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl port-forward payara-config-service-68bb7c8dfb-dx7sg 8080:8080
&lt;span class="gp"&gt;Forwarding from 127.0.0.1:8080 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you access to the application endpoint, you can confirm that the updated value (CONFIG MAP VALUE NEW) is displayed .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI CONFIG MAP VALUE NEW
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we could confirm the MicroPrifile Config with AKS.&lt;/p&gt;

&lt;p&gt;By taking out the configuration and managing them, we can dynamically change the external connection destination without modifying the source code. This greatly reduces the cost of testing and managing applications, and brings you one step closer to cloud-native apps.  &lt;/p&gt;

&lt;p&gt;Please enjoy!!&lt;/p&gt;

</description>
      <category>java</category>
      <category>microprofile</category>
      <category>azure</category>
    </item>
    <item>
      <title>MicroProfile Fault Tolerance について</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Tue, 17 Mar 2020 14:27:25 +0000</pubDate>
      <link>https://dev.to/azure/microprofile-fault-tolerance-1a6g</link>
      <guid>https://dev.to/azure/microprofile-fault-tolerance-1a6g</guid>
      <description>&lt;p&gt;マイクロサービスでサービスを構築する際、耐障害性を考慮して実装する事がとても重要です。 リトライ・ポリシー、バルクヘッド、サーキットブレーカーなどは、マイクロサービスのデザイン・パターンにも定義される、とても重要な概念です。&lt;/p&gt;

&lt;p&gt;MicroProfile の Fault Tolerance はこうした、耐障害性のあるサービスを構築するために必要な機能を提供しています。実装は CDI によるアノテーション・ベースで容易に開発ができ、CDI のインターセプターを利用して動作しています (クラスは CDI の Bean として実装しなければなりません)。&lt;br&gt;
これにより、ビジネス・ロジックと Fault Torerance 用の冗長的なコードを分離し、かんたんに実装できるようになっています。&lt;/p&gt;

&lt;p&gt;MicroProfile の Fault Tolerance のポリシーは外部設定に外だしして管理することが可能になっており、MicroProfile Config を利用してポリシー管理を行うこともできます。&lt;/p&gt;
&lt;h2&gt;
  
  
  Fault Tolerance の仕様に含まれる主な機能
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fault Tolerance で提供する機能&lt;/th&gt;
&lt;th&gt;使用するアノテーションと概要説明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. タイムアウト:&lt;/td&gt;
&lt;td&gt;@Timeout アノテーションを利用。 処理に要する最大時間を定義します&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. リトライ:&lt;/td&gt;
&lt;td&gt;@Retryアノテーションを利用。 処理に失敗した際のリトライ（再試行）の動作を設定します&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. フォールバック：&lt;/td&gt;
&lt;td&gt;@Fallback アノテーションを利用。 処理に失敗した際の代替の方法を提供（別メソッドの呼び出し）します&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. バルクヘッド(隔壁)：&lt;/td&gt;
&lt;td&gt;@Bulkhead アノテーションを利用。同時実行数を制限します。これにより、高負荷時に単一の処理に負荷が集中してレスポンスが低下し、これを起因としたシステム全体への連鎖的な障害を防ぎます&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. サーキット・ブレーカー:&lt;/td&gt;
&lt;td&gt;@CircuitBreaker アノテーションを利用。処理が繰り返して失敗する場合、その処理呼び出しを自動的に即時に失敗しるようにします&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. 非同期：&lt;/td&gt;
&lt;td&gt;@Asynchronous アノテーションを利用。 処理を非同期にします&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;基本的に、上記のいずれかのポリシーを適用したい場合（複数の指定も可）、実装するクラス、もしくはメソッドにアノテーションを付加するだけで設定できます。&lt;/p&gt;


&lt;h1&gt;
  
  
  1. タイムアウト (@Timeout) ポリシー
&lt;/h1&gt;

&lt;p&gt;タイムアウトを設定する事により、処理の完了を待ち続けるのを防ぎます。 仮にタイムアウトを設定しない場合、ネットワーク障害や、接続先が高負荷でレスポンスをただちに返せないような場合、呼び出し元の接続プールのワーカー・スレッドが枯渇するなど、呼び出し元にも負荷をかけてしまいかねません。&lt;br&gt;&lt;br&gt;
そこで、複数のマイクロサービスを実装する際、もしくは外部サービスを呼び出すような場合、各サービス間の連携においてタイムアウトを設定します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Timeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 接続タイムアウト値 400ms (0.4 sec)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="nf"&gt;getConnectionForServiceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;@Timeout のアノテーションはクラス、もしくはメソッドレベルで付加できます。タイムアウト値に達した場合、TimeoutException が送出されます。&lt;/p&gt;

&lt;h1&gt;
  
  
  2. リトライ (@Retry) ポリシー
&lt;/h1&gt;

&lt;p&gt;軽いネットワーク障害や、接続先からの返信が返ってこないような場合、@Retry アノテーションを使用して、処理呼び出しを再試行できます。 &lt;/p&gt;

&lt;p&gt;リトライポリシーでは以下を構成できます。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;パラメータ&lt;/th&gt;
&lt;th&gt;説明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;maxRetries:&lt;/td&gt;
&lt;td&gt;最大のリトライ回数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delay:&lt;/td&gt;
&lt;td&gt;リトライ間隔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delayUnit:&lt;/td&gt;
&lt;td&gt;delay のユニット&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;maxDuration:&lt;/td&gt;
&lt;td&gt;再試行を実行する最大期間&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;durationUnit:&lt;/td&gt;
&lt;td&gt;duration ユニット&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jitter:&lt;/td&gt;
&lt;td&gt;再試行遅延のランダムな変化 (クロック信号のタイミング（もしくは周期）のズレ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jitterDelayUnit:&lt;/td&gt;
&lt;td&gt;jitter ユニット&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;retryOn:&lt;/td&gt;
&lt;td&gt;再試行する失敗 (Exception, Error) を指定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;abortOn:&lt;/td&gt;
&lt;td&gt;中止する失敗 (Exception, Error) を指定&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;@Retry アノテーションはクラスレベル、もしくはメソッドレベルで付加可能で、クラスに付加した場合、クラス内に存在する全メソッドに適用されます。メソッドに付加した場合、指定したメソッドだけが対象になります。クラスでアノテーションを付加し、メソッドにも付加した場合は、メソッドで指定した設定が有効になります。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;正常に処理が終了した場合、結果を正常に返します。&lt;/li&gt;
&lt;li&gt;送出された例外を abortOn で指定した場合、スローされた例外を再送出します&lt;/li&gt;
&lt;li&gt;送出された例外を retryOn で指定した場合、メソッド呼び出しが再試行されます&lt;/li&gt;
&lt;li&gt;それ以外の場合、送出された例外を再送出します
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;また、他の Fault Tolerance のアノテーションと共に併用できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="cm"&gt;/**
     * serviceA() メソッド呼び出しで、例外が送出された場合に、
     * 例外が IOException でない場合は再試行します。
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retryOn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abortOn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;invokeService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;callServiceA&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * 最大再試行回数は90、再試行を実行する最大期間は 1000 ミリ秒に設定
     * 再試行の最大期間に達すると、最大再試行回数に達していない場合でも、再試行は実行されない。
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxDuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;serviceB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;callServiceB&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
    * クロック周波数のズレ(jitter)を 400ms と仮定した場合、-400ms 〜 400ms つまり
    * 0 (delay - jitter) 〜 800ms (delay + jitter )の差で再試行が行われることが予想されます。
    * 最大遅延が発生した場合を想定し、3200/800=4 で、最低試行回数は４回以上、
    * 最大でも 10 回を超えない試行回数を設定します
    */&lt;/span&gt;
    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxDuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jitter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="nf"&gt;serviceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getConnectionForServiceA&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  3. フォールバック (@Fallback) ポリシー
&lt;/h1&gt;

&lt;p&gt;@Fallback アノテーションはメソッドレベルで指定できます。アノテーションが付加されたメソッドで例外が発生し終了した場合、フォールバックメソッドで指定したメソッドが呼び出されます。&lt;/p&gt;

&lt;p&gt;@Fallback アノテーションは、単体もしくは他の Fault Tolerance アノテーションと一緒に使用できます。 他のアノテーションと併用した場合、フォールバックは、他のすべての Fault Tolerance 処理が行われた後に呼び出されます。&lt;/p&gt;

&lt;p&gt;たとえば、@Retry が定義されている場合、リトライが最大試行回数を超えた場合にフォールバックの処理が実行されます。&lt;br&gt;
また、@CircuitBreaker が共に定義されている場合、メソッド呼び出しが失敗した場合に直ちに呼び出されます。そしてサーキットがオープンしている場合は常に、フォールバック・メソッドが呼び出されます。&lt;/p&gt;
&lt;h2&gt;
  
  
  3.1 FallbackHandler の実装によるフォールバック処理の実装例
&lt;/h2&gt;

&lt;p&gt;FallbackHandler インタフェースを実装した FallbackHandler のクラス (ServiceInvocationAFallbackHandler) を定義します。そして handle メソッド内で代替の処理を実装します。  &lt;/p&gt;

&lt;p&gt;ここでは、MicroProfile Config を利用して app.serviceinvokeA.FallbackReplyMessage のプロパティ、もしくは環境変数などで定義した文字列を返信するように実装しています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Dependent&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServiceInvocationAFallbackHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;FallbackHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"app.serviceinvokeA.FallbackReplyMessage"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Unconfigured Default Reply"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;replyString&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExecutionContext&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;replyString&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;下記の、BusinessLogicServiceBean#invokeServiceA() メソッドが呼び出されると、ここでは内部的に RuntimeException が発生しますが 3 回処理の再試行します、全ての再試行に失敗したのち、ServiceInvocationAFallbackHandler#handle() が呼び出されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RequestScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BusinessLogicServiceBean&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// FallbackHandler の実装クラスを指定し @Fallback アノテーションを付加&lt;/span&gt;
    &lt;span class="c1"&gt;// 最大のリトライ回数 (3回)を超えた場合、FallbackHandler の handle() メソッドが呼ばれる&lt;/span&gt;
    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Fallback&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ServiceInvocationAFallbackHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;invokeServiceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection failed"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;   
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  3.2 fallbackMethod を指定したフォールバック処理の実装例
&lt;/h2&gt;

&lt;p&gt;@Fallback アノテーション内で直接、代替で呼び出すメソッド名を記述します。  &lt;/p&gt;

&lt;p&gt;ここでは、fallbackForServiceB() メソッドを代替メソッドとして定義しています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RequestScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BusinessLogicServiceBean&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Fallback&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fallbackMethod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"fallbackForServiceB"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;invokeServiceB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;counterForInvokingServiceB&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;nameService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="nd"&gt;@ConfigProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"app.serviceinvokeB.FallbackReplyMessage"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Unconfigured Default Reply"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;replyString&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;fallbackForInvokeServiceB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;replyString&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  4. バルクヘッド (@Bulkhead) ポリシー
&lt;/h1&gt;

&lt;p&gt;バルクヘッド・パターンは、システムの一部の障害がシステム全体に伝播し、システム全体がダウンするのを防ぐために利用します。MicroProfile の実装では、インスタンスにアクセスする同時リクエスト数を制限します。 &lt;/p&gt;

&lt;p&gt;Bulkheadパターンは、大量に呼び出される可能性のあるコンポーネントや、高負荷時にレスポンス低下を招くようなサービスに対して適用すると効果的です。&lt;/p&gt;

&lt;p&gt;@Bulkhead アノテーションはクラスレベル、もしくはメソッドレベルで付加可能で、クラスに付加した場合、クラス内に存在する全メソッドに適用されます。メソッドに付加した場合、指定したメソッドだけが対象になります。クラスでアノテーションを付加し、メソッドにも付加した場合は、メソッドで指定した設定が有効になります。&lt;/p&gt;

&lt;p&gt;バルクヘッドには下記の2種類の方法で設定可能です。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;スレッド・プールの分離 : (@Asynchronous アノテーションと併用した場合)
スレッド・プール内の待機中のキューサイズで最大同時リクエスト数を設定します。&lt;/li&gt;
&lt;li&gt;セマフォの分離：(@Asynchronous アノテーションと併用しない場合)
同時リクエスト数の設定のみが許可されます。&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  4.1 スレッド・プールによる分離例
&lt;/h1&gt;

&lt;p&gt;@Asynchronous アノテーションと併用した場合、スレッド・プールの分離が適用されます。下記の例では、最大で５つの同時リクエストが許可され、８つのリクエストが待機キューで保持されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 最大5つの同時リクエストが許可され、最大 8つのリクエストが待機キューで許可される&lt;/span&gt;
&lt;span class="nd"&gt;@Asynchronous&lt;/span&gt;
&lt;span class="nd"&gt;@Bulkhead&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;waitingTaskQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;invokeServiceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="n"&gt;counterForInvokingServiceA&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
   &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;completedFuture&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  4.2 セマフォによる分離例
&lt;/h1&gt;

&lt;p&gt;@Asynchronous アノテーションを併用しない場合は、単に同時リクエスト数を定義します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bulkhead&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 最大5つの同時要求が許可されます&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="nf"&gt;invokeServiceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="n"&gt;counterForInvokingServiceA&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
   &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  5. サーキット・ブレーカー (@CircuitBreaker) ポリシー
&lt;/h1&gt;

&lt;p&gt;サーキット・ブレーカーは、障害のあるサービスに対して繰り返しの呼び出しを防いで、障害のあるサービスもしくは API 呼び出しで直ちに失敗するようにします。サービス呼び出しが頻繁に失敗する場合、サーキットブレーカーがオープンし、一定の時間が経過するまでそのサービスへの呼び出しは試行されません。&lt;/p&gt;

&lt;p&gt;@CircuitBreaker アノテーションはクラスレベル、もしくはメソッドレベルで付加可能で、クラスに付加した場合、クラス内に存在する全メソッドに適用されます。メソッドに付加した場合、指定したメソッドだけが対象になります。クラスでアノテーションを付加し、メソッドにも付加した場合は、メソッドで指定した設定が有効になります。&lt;/p&gt;

&lt;h2&gt;
  
  
  サーキットブレーカーの3つの状態
&lt;/h2&gt;

&lt;h3&gt;
  
  
  クローズド：　(通常時)
&lt;/h3&gt;

&lt;p&gt;通常サーキットブレーカーは閉じています。サーキットブレーカーは、各呼び出しが成功したか失敗したかを記録しており最新の結果を追跡します。障害の割合が failureRatio を超えると、サーキット・ブレーカーがオープンします。&lt;/p&gt;

&lt;h3&gt;
  
  
  オープン： (障害発生時)
&lt;/h3&gt;

&lt;p&gt;サーキットブレーカーが開いている場合、サーキットブレーカーで動作しているサービスへの呼び出しは、CircuitBreakerOpenException で直ちに失敗します。しばらくした後（設定可能）、サーキットブレーカーはハーフ・オープン状態に移行します。&lt;/p&gt;

&lt;h3&gt;
  
  
  ハーフ・オープン： (障害復旧の確認中)
&lt;/h3&gt;

&lt;p&gt;ハーフオープン状態では、サービス呼び出しの試行が始まります(設定可能な数)。仮にいずれかの呼び出しで障害が発生した場合、再度サーキットブレーカはオープン状態に戻ります。すべての試行が成功した場合、サーキットブレーカーはクローズド状態に移行します。&lt;/p&gt;

&lt;h2&gt;
  
  
  サーキット・ブレーカの実装例1
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;successThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestVolumeThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failureRatio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="nf"&gt;serviceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="n"&gt;counterForInvokingServiceA&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
   &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;パラメータ&lt;/th&gt;
&lt;th&gt;説明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;requestVolumeThreshold：&lt;/td&gt;
&lt;td&gt;サーキットブレーカーが「クローズ」のときに使用するローリングウィンドウ(障害比率を計算するための分母の数)のサイズ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;failureRatio：&lt;/td&gt;
&lt;td&gt;サーキットブレーカーを「オープン」にするための、ローリングウィンドウ内の障害比率&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;successThreshold：&lt;/td&gt;
&lt;td&gt;サーキットブレーカーが「ハーフ・オープン」の時、クローズドに移行するための試行回数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delayおよびdelayUnit：&lt;/td&gt;
&lt;td&gt;サーキットブレーカーを「オープン」にしつづける時間&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;上記では、requestVolumeThreshold で指定したローリングウィンドウ数である 4 回の連続した呼び出し中に 2 回（4 x 0.5）の障害が発生すると、サーキットが「オープン」します。 サーキットは 1,000 ミリ秒間「オープン」のままになり、その後「ハーフ・オープン」に移ります。 「ハーフ・オープン」で 10 回呼び出しが成功すると、サーキットは再び「クローズ」になります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;リクエスト1-成功
リクエスト2-失敗
リクエスト3-成功
リクエスト4-成功
リクエスト5-失敗
リクエスト6-CircuitBreakerOpenException
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記のリクエストの場合、最後の4つのリクエストのうち2つが失敗し、failureRatio が 0.5 に達するため、「リクエスト5」 でサーキットが 「オープン」 になり CircuitBreakerOpenException が送出されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  成功/失敗とみなす例外定義を追加
&lt;/h2&gt;

&lt;p&gt;failOn パラメーターと skipOn パラメーターは、サーキットブレーカーを「オープン」にするか否かを決定するため、どの例外を失敗と見なすかを定義するために使用します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;successThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestVolumeThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failureRatio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;failOn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;ExceptionA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExceptionB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt; &lt;span class="n"&gt;skipOn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ExceptionBSub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="nf"&gt;serviceA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="n"&gt;counterForInvokingServiceA&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
   &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;failOn に指定した例外が発生した場合は、失敗とみなします&lt;br&gt;
skipOn に指定した例外が発生した場合は、成功とみなします&lt;/p&gt;
&lt;h1&gt;
  
  
  6. 非同期 (@Asynchronous) ポリシー
&lt;/h1&gt;

&lt;p&gt;Fault Tolerance の主な機能は &lt;a href="https://github.com/eclipse/microprofile-fault-tolerance/blob/master/spec/src/main/asciidoc/asynchronous.asciidoc"&gt;Architecture&lt;/a&gt; に記述されているように、上記 1-5 までにあげた機能です。そこで、非同期処理は直接 Fault Tolerance と関連するわけではありません。しかし、分散処理において非同期処理はとても重要で Fault Tolerance の各種機能と組み合わせる事により、より有効的に働くため仕様内に取り込まれました。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/eclipse/microprofile-fault-tolerance/blob/master/spec/src/main/asciidoc/asynchronous.asciidoc"&gt;引用元：Architecture&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As mentioned above, the Fault Tolerance specification is to focus on the following aspects:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Timeout: Define a duration for timeout
&lt;/li&gt;
&lt;li&gt;Retry: Define a criteria on when to retry
&lt;/li&gt;
&lt;li&gt;Fallback: provide an alternative solution for a failed execution.
&lt;/li&gt;
&lt;li&gt;CircuitBreaker: offer a way of fail fast by automatically failing execution to prevent the system overloading and indefinite wait or timeout by the clients.
&lt;/li&gt;
&lt;li&gt;Bulkhead: isolate failures in part of the system while the rest part of the system can still function.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;@Asynchronousアノテーションはクラスレベル、もしくはメソッドレベルで付加可能で、クラスに付加した場合、クラス内に存在する全メソッドに適用されます。メソッドに付加した場合、指定したメソッドだけが対象になります。クラスでアノテーションを付加し、メソッドにも付加した場合は、メソッドで指定した設定が有効になります。&lt;/p&gt;

&lt;p&gt;@Asynchronous アノテーションが付加されたメソッドが呼び出されると、すぐに Future もしくは CompletionStage を返します。残りのメソッド本体の処理は別スレッドで実行されます。非同期処理が完了するまで、返却された Future もしくは CompletionStage は正しい値を持ちません。仮に処理中に例外が発生した場合は、Future または CompletionStage はその例外で終了します。 &lt;br&gt;
処理が正常に完了した場合、Future もしくは CompletionStage は戻り値（それ自体がFutureまたはCompletionStage）を返します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Asynchronous&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;CompletionStage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;serviceA&lt;/span&gt;&lt;span class="err"&gt;（）&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="n"&gt;counterForInvokingServiceA&lt;/span&gt; &lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionService&lt;/span&gt;&lt;span class="err"&gt;（）&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;completedFuture&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記の例では、serviceA メソッドへの呼び出しが非同期処理になります。serviceA の呼び出しはCompletionStage を返し、メソッド本体の実行は別スレッドで実行されます。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;注意：&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
CDI の RequestScope から @Asynchronous を呼び出す場合、非同期メソッド呼び出し中 RequestScope がアクティブでなければなりません。@Asynchronousアノテーションが付加されたメソッドは、java.util.concurrentパッケージの Future もしくは CompletionStage を返す必要があります。そうでない場合、FaultToleranceDefinitionExceptionが発生します。&lt;/p&gt;
&lt;h1&gt;
  
  
  ソースコードに記載した設定値の上書き方法
&lt;/h1&gt;

&lt;p&gt;各節で確認したように、Fault Tolerance のポリシーは一部を除いてほとんどの場合、アノテーションを使用して適用できます。 &lt;br&gt;
ソースコードの実装後、仮にアノテーションで実装した値を変更したい場合は、MicroProfile Config を使用して設定値を上書きすることもできます。&lt;/p&gt;

&lt;p&gt;アノテーション内のパラメーターは、次の命名規則を使用して、設定プロパティーで上書きできます：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;classname&amp;gt;/&amp;lt;methodname&amp;gt;/&amp;lt;annotation&amp;gt;/&amp;lt;parameter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;たとえば、ある特定のメソッドで指定した Timeout や Retry のアノテーションで指定したパラメータを外部で上書き設定したい場合、MicroProfile Config で下記のように記述します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.yoshio3.FaultToleranceService.resilient.ResilienceController/checkTimeout/Timeout/value=2000
com.yoshio3.FaultToleranceService.resilient.ResilienceController/checkTimeout/Retry/maxDuration=3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;仮に、クラス全体に適用したい場合は下記のように、メソッド名の部分を削除してクラス全体に適用することもできます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.yoshio3.FaultToleranceService.resilient.ResilienceController/Timeout/value=2000
com.yoshio3.FaultToleranceService.resilient.ResilienceController/Retry/maxDuration=3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;そして、プロジェクト内の全コードに対して同一ルールを適用したい場合は、アノテーションとパラメータ設定だけを記載することもできます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Timeout/value=2000
Retry/maxDuration=3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  さいごに
&lt;/h1&gt;

&lt;p&gt;ここでは、MicroProfile Fault Tolerance を利用して耐障害性を高めるアプリケーションを構築するためのコードを確認しました。次は、Fault Tolerance を利用したアプリケーションを実際に構築し、Azure 上で耐障害性を持つ複数のサービスを連携をしてみたいと思います。&lt;/p&gt;

</description>
      <category>java</category>
      <category>microprofile</category>
    </item>
    <item>
      <title>Azure Kubernetes Service 環境で MicroProfile Config 動作検証</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Fri, 13 Mar 2020 06:52:17 +0000</pubDate>
      <link>https://dev.to/azure/azure-kubernetes-service-microprofile-config-3cb2</link>
      <guid>https://dev.to/azure/azure-kubernetes-service-microprofile-config-3cb2</guid>
      <description>&lt;h2&gt;
  
  
  1. Azure Kubernetes Service 環境で MicroProfile Config 動作検証
&lt;/h2&gt;

&lt;p&gt;アプリケーションは、外部システムとの連携のための接続情報 (DB や、外部の HTTP エンドポイント)や、開発環境、テスト環境、本番環境などの環境設定の差を、プログラム・ソースコードから切り離し、外部の設定ファイル等に書き出すことで容易に接続先や設定を切り替えることができます。&lt;br&gt;
また、外部の設定ファイルなどに書き出しておくことで、接続先を切り替えるためにアプリケーションのソースコードの編集やビルドは不要で、同一のソースコードや実行ライブラリを利用できます。&lt;/p&gt;

&lt;p&gt;クラウド・ネィティブなアプリケーションを構築していくために、設定情報の外だしはとても重要です。&lt;br&gt;
「&lt;a href="https://12factor.net/ja/"&gt;参照：The Twelve Factors&lt;/a&gt;  の&lt;a href="https://12factor.net/ja/config"&gt;III. 設定&lt;/a&gt; : 設定を環境変数に格納する」&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Twelve-Factorは 設定をコードから厳密に分離すること を要求する。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;MicroProfile Config を利用すると、設定情報を下記のようなさまざまな場所から取得できます。&lt;br&gt;
これらの設定場所を ConfigSources と呼び、 同じプロパティが複数の ConfigSource で定義されている場合、ポリシーを適用しどの値が有効かを指定します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java VM のシステム ・プロパティから&lt;/li&gt;
&lt;li&gt;OS の環境変数&lt;/li&gt;
&lt;li&gt;外部構成ファイル (.properties, .xml)から&lt;/li&gt;
&lt;li&gt;LDAP, DB, Key-Value ストア などの外部データそ＝す&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;また状況によっては、一部のデータソースを動的に切り替えたい場合があります。そして変更した値は、アプリケーションを再起動することなく、プログラム上から更新した内容を利用する必要があります。こうしたニーズに応えるため、MicroProfile Config では、構成した値を変更直後から利用できるようになっています。&lt;/p&gt;
&lt;h2&gt;
  
  
  MicroProfile Config の実装について
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/index.html"&gt;Microprofile Config は API&lt;/a&gt; のみを規定しており実装は含まれていません。&lt;br&gt;
MicroProfile Config の実装は、各 MicroProfile の実装プロバイダから個別に提供されています。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://svn.apache.org/repos/asf/geronimo/components/config/trunk"&gt;Apache Geronimo Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.ibm.com/wasdev/"&gt;WebSphere Liberty 2017 March-June Beta so far&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.payara.fish/documentation/microprofile/config.html"&gt;Payara Server 173 and Payara Micro 173&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/smallrye/smallrye-config"&gt;WildFly &amp;amp; Thorntail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microbean.github.io/microbean-microprofile-config/"&gt;microBean™ MicroProfile Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  MicroProfile Config の概要
&lt;/h2&gt;

&lt;p&gt;MicroProfile Config は数少ない API から構成されています。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/index.html"&gt;MicroProfile Config API 1.4 の一覧&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/Config.html"&gt;Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigBuilder.html"&gt;ConfigBuilder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/inject/ConfigProperty.html"&gt;ConfigProperty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/ConfigProvider.html"&gt;ConfigProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigProviderResolver.html"&gt;ConfigProviderResolver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigSource.html"&gt;ConfigSource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigSourceProvider.html"&gt;ConfigSourceProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/Converter.html"&gt;Converter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  ConfigSource の優先順位
&lt;/h2&gt;

&lt;p&gt;Configは、登録されたorg.eclipse.microprofile.config.spi.ConfigSourceから収集された情報で構成されます。 これらのConfigSourceは、順序に従ってソートされます。 これにより、外部から重要度の低い設定を上書きできます。&lt;/p&gt;

&lt;p&gt;デフォルトでは、3つのデフォルトConfigSourceがあります。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System.getProperties()（優先順位 = 400）&lt;/li&gt;
&lt;li&gt;System.getenv()（優先順位= 300）&lt;/li&gt;
&lt;li&gt;ClassPath上の META-INF/microprofile-config.properties ファイル（デフォルト優先順位 = 100、各ファイル中に config_ordinal プロパティを設定して個別に優先順位を設定可能）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;デフォルト値は、アプリケーションのパッケージ時にファイル内で指定でき、値はデプロイメントごとに後から上書きできます。 &lt;strong&gt;&lt;em&gt;「優先順位は値が大きいほど優先されます。」&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  設定情報の取得例
&lt;/h2&gt;

&lt;p&gt;MicroProfile Config 仕様では、設定値を読み取るために 2種類の方法を用意しています。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;プログラム的な設定情報の取得&lt;/li&gt;
&lt;li&gt;アノテーションを利用した設定情報の取得&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1. プログラム的な設定情報の取得
&lt;/h3&gt;

&lt;p&gt;プログラム的に Config インスタンスを取得し設定情報を取得するサンプルを下記に示します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class  MyAppWithGetConfigFromProgram {

    public Response invokeMicroserviceWithConfig() {
        // Config インスタンスの取得
        Config config = ConfigProvider.getConfig();
        // マイクロサービス A の URL を取得
        String microserviceA = config.getValue("URL_OF_MICROSERVICE_A", String.class);
        // マイクロサービス A の呼び出し
        return invokeMicroservice(microserviceA);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;設定情報を取得するためには、最初に &lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/Config.html"&gt;Config&lt;/a&gt; インスタンスを取得しなければなりません。&lt;br&gt;
プログラム的に Config インスタンスを取得するためには、&lt;a href="https://javadoc.io/static/org.eclipse.microprofile.config/microprofile-config-api/1.4/org/eclipse/microprofile/config/ConfigProvider.html#getConfig--"&gt;ConfigProvider#getConfig()&lt;/a&gt; を呼び出して取得できます。&lt;br&gt;&lt;br&gt;
（Config クラスのインスタンスは、生成されたのちコンテキストクラスローダーに登録されます。）&lt;/p&gt;
&lt;h3&gt;
  
  
  2. アノテーションを利用した設定情報の取得 (推奨)
&lt;/h3&gt;

&lt;p&gt;アノテーションを利用し Config インスタンスを取得し、@ConfigProperty で設定情報を取得するサンプルを下記に示します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApplicationScoped
public class MyAppWithGetConfigFromAnnotation {

    @Inject
    private Config config;

    //The property myprj.some.url must exist in one of the configsources, otherwise a
    //DeploymentException will be thrown.
    @Inject
    @ConfigProperty(name="myprj.some.url")
    private String someUrl;

    //The following code injects an Optional value of myprj.some.port property.
    //Contrary to natively injecting the configured value, this will not lead to a
    //DeploymentException if the value is missing.
    @Inject
    @ConfigProperty(name="myprj.some.port")
    private Optional&amp;lt;Integer&amp;gt; somePort;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  MicroProfile Config サンプル・アプリケーション
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. MicroProfile Config サンプル・プロジェクトの作成
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://start.microprofile.io/"&gt;MicroProfile Starter&lt;/a&gt; にアクセスし、MicroProfile のプロジェクトを作成します。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z_reu7bS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://live.staticflickr.com/65535/49650925377_1310626472_z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z_reu7bS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://live.staticflickr.com/65535/49650925377_1310626472_z.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(DOWNLOAD) のリンクを押下すると MPConfigSample.zip ファイルがダウンロードできます。ファイルを展開すると下記のようなファイル・ディレクトリ構成が自動的に生成されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── pom.xml
├── readme.md
└── src
    └── main
        ├── java
        │   └── com
        │       └── yoshio3
        │           └── MPConfigSample
        │               ├── HelloController.java
        │               ├── MPConfigSampleRestApplication.java
        │               └── config
        │                   └── ConfigTestController.java
        ├── resources
        │   └── META-INF
        │       └── microprofile-config.properties
        └── webapp
            ├── WEB-INF
            │   └── beans.xml
            └── index.html
11 directories, 8 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;そして、MicroProfile Config のサンプルコードが ConfigTestController.java に下記のように記載されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.yoshio3.MPConfigSample.config;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/config")
@RequestScoped
public class ConfigTestController {

    @Inject
    @ConfigProperty(name = "injected.value")
    private String injectedValue;

    @Path("/injected")
    @GET
    public String getInjectedConfigValue() {
        return "Config value as Injected by CDI " + injectedValue;
    }

    @Path("/lookup")
    @GET
    public String getLookupConfigValue() {
        Config config = ConfigProvider.getConfig();
        String value = config.getValue("value", String.class);
        return "Config value from ConfigProvider " + value;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記のコードでは、プロパティに記載された値を HTTP のレスポンスとして返す簡単なコードです。&lt;br&gt;&lt;br&gt;
下記のように HTTP の GET メソッドで呼び出すと return 文で記載される文字列が返ってきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -X GET http://localhost:8080/data/config/injected
$ curl -X GET http://localhost:8080/data/config/lookup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;実際の設定内容は、META_INF ディレクトリ配下の microprofile-config.properties ファイルに記載されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# プロパティ・ファイルの場所
└── src
    └── main
        ├── resources
        │   └── META-INF
        │       └── microprofile-config.properties
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;デフォルトで下記のプロパティが設定されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# プロパティ・ファイルに設定された値
injected.value=Injected value
value=lookup value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2. サンプル・プロジェクトのビルドと実行
&lt;/h3&gt;

&lt;p&gt;MicroProfile Config の動作確認を行うため、プロジェクトをビルドし、アプリケーションを起動します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# プロジェクトのビルド
$ mvn clean package

# アプリケーションの実行
$ java -jar target/MPConfigSample-microbundle.jar 

......
Payara Micro URLs:
http://192.168.100.7:8080/

'ROOT' REST Endpoints:
GET     /data/application.wadl
GET     /data/config/injected
GET     /data/config/lookup
GET     /data/hello
GET     /openapi/
GET     /openapi/application.wadl
]]
[2020-03-10T22:19:06.610+0900] [] [情報] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583846346610] [levelValue: 800] Payara Micro  5.194 #badassmicrofish (build 327) ready in 32,755 (ms)
[2020-03-10T22:19:33.646+0900] [] [情報] [] [javax.enterprise.system.container.web.com.sun.web.security] [tid: _ThreadID=29 _ThreadName=http-thread-pool::http-listener(1)] [timeMillis: 1583846373646] [levelValue: 800] Context path from ServletContext:  differs from path from bundle: /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記のようにアプリケーションが起動したのち、curl コマンドを実行し動作確認を行います。&lt;br&gt;
正しく動作している場合、下記のようにプロパティ・ファイルから取得した設定 (Injected value, value) の文字列が表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# アノテーションで実装されたエンドポイントへの呼び出し
$ curl localhost:8080/data/config/injected
Config value as Injected by CDI Injected value

# プログラムで実装されたエンドポイントへの呼び出し
$ curl localhost:8080/data/config/lookup
Config value from ConfigProvider lookup value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;MicroProfile ではプロパティ・ファイルの設定値をシステム・プロパティで上書き設定することができます。そこで環境変数を設定し、環境変数の値を Java のシステム・プロパティに代入して実行します。すると "microprofile-config.properties" ファイルに設定した値を上書きし、環境変数に設定した値が表示されている事を確認できます。&lt;br&gt;
&lt;br&gt;
　&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 環境変数の設定 [.(ドット）を _(アンダーバー）に置き換えて設定]
$ export injected_value="Environment Value"

# 環境変数を Java のシステム・プロパティに設定してアプリを実行
$ java -D"$injected_value" -jar target/MPConfigSample-microbundle.jar

# アプリケーションの動作確認
$ curl http://localhost:8080/data/config/injected
Config value as Injected by CDI Environment Value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;ご注意：　properties ファイル中では . (ドット）表記で記載していますが、環境変数は OS によっては . (ドット）表記が使えません。そこで、環境変数の設定では . (ドット）表記箇所を _ (アンダーバー）に置き換えて設定してください。実装内部で自動的に変換をしています。&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. ローカルの Docker 環境での実行
&lt;/h3&gt;

&lt;p&gt;ローカルの環境でアプリケーションの動作確認ができたので、次にローカルの Docker 環境で MicroProfile を動作させます。Payara Micro の Docker コンテナのイメージを作成するため、下記のような Dockerfile を作成してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM payara/micro:5.201

USER payara
WORKDIR ${PAYARA_HOME}

# Deploy Artifact
COPY ./target/MPConfigSample.war $DEPLOY_DIR

CMD ["--nocluster","--deploymentDir", "/opt/payara/deployments", "--contextroot", "app"]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;次に、この Dockerfile を利用してコンテナのイメージを作成します。docker build コマンドを実行しコンテナのイメージを作成してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t tyoshio2002/payara-config-sample:1.0 .

# コマンド実行時のコンソール出力例
Sending build context to Docker daemon  151.2MB
Step 1/5 : FROM payara/micro:5.201
5.201: Pulling from payara/micro
050382585609: Already exists 
59f5185426ac: Already exists 
4d95208cd9c0: Pull complete 
c1409397cf71: Pull complete 
Digest: sha256:3ff92627d0d9b67454ee241cc7d5f2e485e46db81a886c87cf16035df7c80cc8
Status: Downloaded newer image for payara/micro:5.201
 ---&amp;gt; a11a548b0a25
Step 2/5 : USER payara
 ---&amp;gt; Running in cb755e484e79
Removing intermediate container cb755e484e79
 ---&amp;gt; 564283252ae4
Step 3/5 : WORKDIR ${PAYARA_HOME}
 ---&amp;gt; Running in f26dd5cd172c
Removing intermediate container f26dd5cd172c
 ---&amp;gt; f2bf88b18a77
Step 4/5 : COPY ./target/MPConfigSample.war $DEPLOY_DIR
 ---&amp;gt; 1b54373fe95a
Step 5/5 : CMD ["--nocluster","--deploymentDir", "/opt/payara/deployments", "--contextroot", "app"]
 ---&amp;gt; Running in 3eb731eb77c3
Removing intermediate container 3eb731eb77c3
 ---&amp;gt; 1d11549e99b8
Successfully built 1d11549e99b8
Successfully tagged tyoshio2002/payara-config-sample:1.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;コンテナのイメージが作成できたのち、コンテナを起動します。下記のコマンドを実行してコンテナを起動してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -p 8080:8080 -e injected_value=hogehoge -it tyoshio2002/payara-config-sample:1.0

# コマンド実行時のコンソール出力例
..... (中略)
[2020-03-11T07:46:59.119+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819119] [levelValue: 800] [[ 
{
    "Instance Configuration": {
        "Host": "3877abb54d57",
        "Http Port(s)": "8080",
        "Https Port(s)": "",
        "Instance Name": "payara-micro",
        "Instance Group": "no-cluster",
        "Deployed": [
            {
                "Name": "MPConfigSample",
                "Type": "war",
                "Context Root": "/app"
            }
        ]
    }
}]]
[2020-03-11T07:46:59.131+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819131] [levelValue: 800] [[
Payara Micro URLs:
http://3877abb54d57:8080/app
'MPConfigSample' REST Endpoints:
GET /app/data/application.wadl
GET /app/data/config/injected
GET /app/data/config/lookup
GET /app/data/hello
]]
[2020-03-11T07:46:59.131+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819131] [levelValue: 800] Payara Micro  5.201 #badassmicrofish (build 512) ready in 31,286 (ms)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;作成したコンテナの起動が完了したので、コンテナ上で動作するアプリケーションに対して接続をします。&lt;br&gt;&lt;br&gt;
今回は、起動時にコンテナ内部の 8080番ポートを、ローカルの 8080番ポートにマッピングしていますので、ローカル環境の 8080 番ポートにアクセスすることで、コンテナのアプリケーションに接続できます。 &lt;br&gt;
下記のコマンドを実行してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI hogehoge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;コンテナの起動時に引数として環境変数 (&lt;strong&gt;&lt;em&gt;-e injected_value=hogehoge&lt;/em&gt;&lt;/strong&gt;) を与えているため、起動時に入力した文字列が表示されます。&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Azure Kubernetes Service 環境での実行
&lt;/h3&gt;

&lt;p&gt;ローカルの Docker 環境で動作確認ができたので、&lt;a href="https://aka.ms/docs-aks-tutorial"&gt;Azure Kubernetes Service&lt;/a&gt; 環境で動作確認を行います。下記の手順に従い動作確認を行います。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Azure Container Registry 用のリソース・グループを作成
&lt;/li&gt;
&lt;li&gt;Azure Container Registry を作成
&lt;/li&gt;
&lt;li&gt;Azure Container Registry のパスワードの確認
&lt;/li&gt;
&lt;li&gt;Azure Container Registry にログインしイメージを Push
&lt;/li&gt;
&lt;li&gt;Azure Container Registry に Push したイメージの確認
&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Service 用のリソース・グループを作成
&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Service 用のサービス・プリンシパル作成
&lt;/li&gt;
&lt;li&gt;AKS から ACR のリソースを参照できるように ACR に参照権限を付与
&lt;/li&gt;
&lt;li&gt;AKS の作成
&lt;/li&gt;
&lt;li&gt;kubectl コマンドのインストールと AKS 接続情報の取得
&lt;/li&gt;
&lt;li&gt;Deployment YAML の作成
&lt;/li&gt;
&lt;li&gt;Deployment YAML の適用
&lt;/li&gt;
&lt;li&gt;Pod の動作確認
&lt;/li&gt;
&lt;li&gt;環境変数を設定し更新
&lt;/li&gt;
&lt;li&gt;Kubernetes の Config Map からの設定情報の取得
&lt;/li&gt;
&lt;li&gt;Config Map 値の更新と Pod の再起動
&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  4.1. Azure Container Registry 用のリソース・グループを作成
&lt;/h4&gt;

&lt;p&gt;まずは、&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; を作成し、ローカルで作成した Docker コンテナのイメージをアップロードします。そこで、Azure Container Registry を作成するためのリソース・グループを作成します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az group create --name WebApp-Containers --location "Japan East"
{
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers",
  "location": "japaneast",
  "managedBy": null,
  "name": "WebApp-Containers",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2. Azure Container Registry を作成
&lt;/h4&gt;

&lt;p&gt;次に、Azure Container Registry を作成します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name にコンテナ・レジストリ名を指定します
&lt;/li&gt;
&lt;li&gt;--resource-group に上記で作成したリソース・グループ名を指定します
&lt;/li&gt;
&lt;li&gt;--sku は "Basic", "Standard", "Premium" の何れかを指定します
&lt;/li&gt;
&lt;li&gt;--admin-enabled true に設定する事で、コンテナ・レジストリに docker コマンドでアクセスできるようにします
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr create --name containerreg4yoshio --resource-group WebApp-Containers --sku Basic --admin-enabled true
{
  "adminUserEnabled": true,
  "creationDate": "2020-03-12T02:27:59.357654+00:00",
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio",
  "location": "japaneast",
  "loginServer": "containerreg4yoshio.azurecr.io",
  "name": "containerreg4yoshio",
  "networkRuleSet": null,
  "policies": {
    "quarantinePolicy": {
      "status": "disabled"
    },
    "retentionPolicy": {
      "days": 7,
      "lastUpdatedTime": "2020-03-12T02:28:01.654662+00:00",
      "status": "disabled"
    },
    "trustPolicy": {
      "status": "disabled",
      "type": "Notary"
    }
  },
  "provisioningState": "Succeeded",
  "resourceGroup": "WebApp-Containers",
  "sku": {
    "name": "Basic",
    "tier": "Basic"
  },
  "status": null,
  "storageAccount": null,
  "tags": {},
  "type": "Microsoft.ContainerRegistry/registries"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.3. Azure Container Registry のパスワードの確認
&lt;/h4&gt;

&lt;p&gt;次に、Azure Container Registry に接続するためのパスワードを確認します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name にコンテナ・レジストリ名を指定します
&lt;/li&gt;
&lt;li&gt;--resource-group に上記で作成したリソース・グループ名を指定します
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr credential show --name containerreg4yoshio --resource-group WebApp-Containers
{
  "passwords": [
    {
      "name": "password",
      "value": "4zaIiLk*************+H1XO4AlYFvN"
    },
    {
      "name": "password2",
      "value": "fT03XPs*************Oq2cAZiVHV+L"
    }
  ],
  "username": "containerreg4yoshio"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.4. Azure Container Registry にログインしイメージを Push
&lt;/h4&gt;

&lt;p&gt;次に、docker login コマンドを実行し Azure Container Registry に接続します。&lt;br&gt;&lt;br&gt;
(パスワードは上記で取得したパスワードを入力してください。)  &lt;/p&gt;

&lt;p&gt;ログインが完了すると、docker tag コマンドでイメージのタグ付けを行います。ローカルで作成した Docker コンテナのイメージ名に、コンテナ・レジストリの   "loginServer" 名 ( 例："containerreg4yoshio.azurecr.io") を付け加えた名前でタグ付けします。  &lt;/p&gt;

&lt;p&gt;最後に、docker push コマンドを実行し、Azure Container Registry にイメージを Push します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Azure Container Registry にログイン
$ docker login containerreg4yoshio.azurecr.io -u containerreg4yoshio
Password: 
Login Succeeded

# Docker コンテナのタグ付け
$ docker tag tyoshio2002/payara-config-sample:1.0 containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0

# Azure Container Registry にタグ付けしたイメージを Push
$ docker push containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0

The push refers to repository [containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample]
bbd197848553: Pushed 
ec40a5d738cc: Pushed 
f95fe3528c56: Pushed 
bded2364df91: Pushed 
1bfeebd65323: Pushed 
1.0: digest: sha256:689dbacc212d37afe09c43417bc79d8e241c3fa7b5cf71c27097ef535cf77f76 size: 1368
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.5. Azure Container Registry に Push したイメージの確認
&lt;/h4&gt;

&lt;p&gt;Azure Container Registry に正しくイメージが Push されていることを確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr repository list -n containerreg4yoshio -g WebApp-Containers
Argument 'resource_group_name' has been deprecated and will be removed in a future release.
[
  "tyoshio2002/payara-config-sample"
]

$ az acr repository show-tags --name containerreg4yoshio  --repository tyoshio2002/payara-config-sample
[
  "1.0"
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.6. Azure Kubernetes Service 用のリソース・グループを作成
&lt;/h4&gt;

&lt;p&gt;次に Azure Kubernetes Service (AKS)  を作成します。まず、AKS を作成するリソース・グループを作成します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az group create --name MC_yoshio-aks --location "Japan East"
{
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/MC_yoshio-aks",
  "location": "japaneast",
  "managedBy": null,
  "name": "MC_yoshio-aks",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
$ 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.7. Azure Kubernetes Service 用のサービス・プリンシパル作成
&lt;/h4&gt;

&lt;p&gt;まず AKS で利用するサービスプリンシパルを作成します。作成時には既定のロールはアサインしていません。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az ad sp create-for-rbac --skip-assignment
{
  "appId": "884ac0da-****-****-****-c9e2d3fce495",
  "displayName": "azure-cli-2020-03-13-03-12-59",
  "name": "http://azure-cli-2020-03-13-03-12-59",
  "password": "03a0e079-****-****-****-a760333af0b0",
  "tenant": "72f988bf-****-****-****-2d7cd011db47"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.8. AKS から ACR のリソースを参照できるように ACR に参照権限を付与
&lt;/h4&gt;

&lt;p&gt;Azure を利用する場合、Kubernetes 内でコンテナ・レジストリへの接続情報を登録せず (通常は Secret 内に接続情報を登録し利用)、Azure の Azure Active Directory (Azure AD) のサービス プリンシパルを利用して、Azure Container Registry 内に存在するコンテナのイメージを取得することができます。  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://aka.ms/serviceprincipal-auth-for-acr"&gt;参照：サービス プリンシパルによる Azure Container Registry 認証&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;まず、ACR に権限を付与するため、az acr show コマンドで ACR のリソース ID を取得します。&lt;/p&gt;

&lt;p&gt;次に、az role assignment create コマンドで ACR に対して、AKS で利用するサービスプリンシパル(上記で作成)に対して acrpull を許可します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--assignee は appId を指定 ("appId": "884ac0da-*&lt;strong&gt;&lt;em&gt;-&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;-&lt;/em&gt;***-c9e2d3fce495",)&lt;/li&gt;
&lt;li&gt;--scope は 上記 ACR の ID を指定&lt;/li&gt;
&lt;li&gt;--role acrpull ロールを指定すると ACR からイメージをプル可能 (YAML 内でセキュリティ設定不要)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr show --resource-group WebApp-Containers --name containerreg4yoshio --query "id" --output tsv
/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio

$ az role assignment create --assignee 884ac0da-****-****-****-c9e2d3fce495 --scope /subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio --role acrpull
{
  "canDelegate": null,
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio/providers/Microsoft.Authorization/roleAssignments/72cbc68a-****-****-****-1a66c8568cba",
  "name": "72cbc68a-****-****- ****-1a66c8568cba",
  "principalId": "33472555-****-****-****-31e2064fb702",
  "principalType": "ServicePrincipal",
  "resourceGroup": "WebApp-Containers",
  "roleDefinitionId": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/providers/Microsoft.Authorization/roleDefinitions/7f951dda-****-****-****-43fe172d538d",
  "scope": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio",
  "type": "Microsoft.Authorization/roleAssignments"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.9. AKS の作成
&lt;/h4&gt;

&lt;p&gt;最後に、AKS を作成します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--resource-group は 4.6 で作成したリソース・グループ名を指定します&lt;/li&gt;
&lt;li&gt;--name は AKS クラスターの名前を指定します&lt;/li&gt;
&lt;li&gt;--kubernetes-version は AKS クラスターの Kubernetes のバージョンを指定します&lt;/li&gt;
&lt;li&gt;--node-vm-size は VM サイズを指定します&lt;/li&gt;
&lt;li&gt;--node-count は Kubernetes のワーカー・ノードの数を指定します&lt;/li&gt;
&lt;li&gt;--location は東日本を指定します&lt;/li&gt;
&lt;li&gt;--service-principal は 4.7 のサービスプリンシパル作成時の appId を指定します&lt;/li&gt;
&lt;li&gt;--client-secret  は 4.7 のサービスプリンシパル作成時の password を指定します&lt;/li&gt;
&lt;li&gt;--generate-ssh-keys は作成時に SSH キー(Public,Private)がユーザーディレクトリの .ssh に作成されます
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks create \
    --resource-group MC_yoshio-aks \
    --name yoshioAKSCluster1164 \
    --kubernetes-version 1.16.4 \
    --node-vm-size Standard_DS2_v2 \
    --node-count 3 \
    --location japaneast \
    --service-principal "884ac0da-****-****-****-c9e2d3fce495" \
    --client-secret  "03a0e079-****-****-****-a760333af0b0" \
    --generate-ssh-keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;注意：上記の AKS の作成時のコマンドは開発環境用、検証用として作成しています。AKS の本番環境を構築するためには、ネットワーク周りで仮想ネットワークを利用したり、外部サービス連携用のサブネットを切ったり、アベイラビリティ・ゾーンとして構築する必要があるため、本番環境構築のためにはより多くのオプション指定が必要になります。az aks create コマンドの詳細は下記をご参照ください。  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://aka.ms/detail-az-aks-options"&gt;参考：az aks コマンドの詳細&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4.10. kubectl コマンドのインストールと AKS 接続情報の取得
&lt;/h4&gt;

&lt;p&gt;AKS を操作するためには、kubectl コマンドを利用します。初めて Kubernetes を操作する場合、操作環境に kubectl コマンドがインストールされていないかもしれません。kubectl コマンドがインストールされていない場合は az aks install-cli コマンドを実行して入手します。  &lt;/p&gt;

&lt;p&gt;kubectl コマンドを入手後、kubectl コマンドを利用して AKS を操作します。作成した AKS に接続するためには、AKS への接続情報が必要になります。そこで AKS への接続情報（クレデンシャル）を az aks get-credentials コマンドを実行して取得してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# kubectl コマンドのインストール
$ az aks install-cli
Downloading client to "/usr/local/bin/kubectl" from "https://storage.googleapis.com/kubernetes-release/release/v1.17.4/bin/darwin/amd64/kubectl"
Please ensure that /usr/local/bin is in your search PATH, so the `kubectl` command can be found.
$ which kubectl 
/usr/local/bin/kubectl

# AKS の接続情報（クレデンシャル）の取得
$ az aks get-credentials --resource-group MC_yoshio-aks --name yoshioAKSCluster1164
Merged "yoshioAKSCluster1164" as current context in /Users/yoterada/.kube/config

# kubernetes のクライアントとサーバのバージョン確認
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.4", GitCommit:"8d8aa39598534325ad77120c120a22b3a990b5ea", GitTreeState:"clean", BuildDate:"2020-03-12T21:03:42Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.4", GitCommit:"224be7bdce5a9dd0c2fd0d46b83865648e2fe0ba", GitTreeState:"clean", BuildDate:"2019-12-13T20:40:52Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.11. Deployment YAML の作成
&lt;/h4&gt;

&lt;p&gt;次に、AKS 上で作成したコンテナを動作させるために、Deployment の YAML を作成します。&lt;br&gt;
下記の YAML ファイルを作成し deployment.yaml として保存してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: payara-config-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: payara-config-service
  template:
    metadata:
      labels:
        app: payara-config-service
        version: v1
        stage: develop
    spec:
      securityContext:
        runAsUser: 1000 
      containers:
      - name: payara-config-service
        image: containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0
        resources:
          requests:
            cpu: 100m
            memory: 1Gi
          limits:
            cpu: 200m
            memory: 1Gi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.12. Deployment YAML の適用
&lt;/h4&gt;

&lt;p&gt;Deployment の YAML ファイルを作成したのち、AKS 環境に Deploy します。下記のコマンドを実行して YAML ファイルを適用してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f deployment.yaml 
deployment.apps/payara-config-service created
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.13. Pod の動作確認
&lt;/h4&gt;

&lt;p&gt;正しく、Deployment YAML ファイルが適用されると kubectl get po のコマンドで STATUS が Running になっていることを確認できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get po
NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-85f5cdd768-42sh8   1/1     Running   0          28s
payara-config-service-85f5cdd768-fhjrh   1/1     Running   0          28s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;仮に Running のステータスが表示されていない場合は、下記のコマンドを実行して原因を確認してください&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl describe po payara-config-service-85f5cdd768-42sh8  

もしくは
$ kubectl logs payara-config-service-85f5cdd768-42sh8  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ステータスが Running になっている場合、アプリケーションが動作しています。ローカルの環境からアプリケーションの動作確認を行うために、下記の port-forard コマンドを実行してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl port-forward payara-config-service-85f5cdd768-42sh8 8080:8080
Forwarding from 127.0.0.1:8080 -&amp;gt; 8080
Forwarding from [::1]:8080 -&amp;gt; 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;port-forward コマンドを実行した後、別のターミナルを開き curl コマンド、もしくはブラウザを起動しアプリケーションのエンドポイントにアクセスしてください。&lt;br&gt;&lt;br&gt;
下記のように文字列が表示されていればアプリケーションが正しく動作しています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl localhost:8080/app/data/config/injected
Config value as Injected by CDI Injected value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.14. 環境変数を設定し更新
&lt;/h4&gt;

&lt;p&gt;上記で、アプリケーションの動作確認ができましたが現時点で環境変数を設定していないため、アプリケーション内の properties ファイルに設定した値が表示されています。&lt;br&gt;&lt;br&gt;
アプリケーション外部の環境変数から値をとるために、Kubernetes の Deployment YAML を修正し再度デプロイしてください。&lt;/p&gt;

&lt;p&gt;追記する YAML の設定は下記の箇所です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        env:
          - name: injected_value
            value: ENVIRONMENT VALUE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;修正後の YAML ファイルは下記のようになります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: payara-config-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: payara-config-service
  template:
    metadata:
      labels:
        app: payara-config-service
        version: v1
        stage: develop
    spec:
      securityContext:
        runAsUser: 1000 
      containers:
      - name: payara-config-service
        image: containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0
        env:
          - name: injected_value
            value: ENVIRONMENT VALUE
        resources:
          requests:
            cpu: 100m
            memory: 1Gi
          limits:
            cpu: 200m
            memory: 1Gi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記の YAML ファイルを編集した後、YAML ファイルを適用してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f  deployment.yaml 
deployment.apps/payara-config-service configured
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;YAML を適用すると、ローリング・アップグレードで新しい Pod が起動されます。新しく起動した Pod 名を取得し port-foward コマンドを実行し、ローカルからアクセスできるようにしてください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Pod の一覧を取得
$ kubectl get po
NAME                                    READY   STATUS    RESTARTS   AGE
payara-config-service-58cdfd6c7-gfvcl   1/1     Running   0          37s
payara-config-service-58cdfd6c7-hdm6c   1/1     Running   0          48s

# Port Forawrd で k8s 上で動作する Pod の Port をローカルにフォワード
$ kubectl port-forward payara-config-service-58cdfd6c7-gfvcl 8080:8080
Forwarding from 127.0.0.1:8080 -&amp;gt; 8080
Forwarding from [::1]:8080 -&amp;gt; 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;新しい Pod をローカルにフォワードした後、curl コマンドもしくはブラウザからエンドポイントにアクセスしてください。  &lt;/p&gt;

&lt;p&gt;すると、YAML ファイル中に定義した環境変数が表示されるようになります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI ENVIRONMENT VALUE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.15. Kubernetes の Config Map からの設定情報の取得
&lt;/h4&gt;

&lt;p&gt;Kubernetes では、コンテナーの管理 (deployment.yaml) から設定を切り離して、一元管理できる &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/"&gt;Config Map&lt;/a&gt; という仕組みが用意されています。そこで、Deployment YAML 中に設定した環境変数の設定を Config Map に外だしして Config Map 内で設定情報を管理するようにします。&lt;/p&gt;

&lt;p&gt;下記の Config Map の YAML ファイルを作成し configmap.yaml  として保存してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: microprofile-service-config
data:
  injected_value: "CONFIG MAP VALUE"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;次に、Config Map の設定を適用します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Config Map を適用
$ kubectl apply -f configmap.yaml 
configmap/microprofile-service-config createds

# Config Map の設定が追加されている事の確認
$ kubectl get cm
NAME                          DATA   AGE
microprofile-service-config   1      37m
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;次に、Kubernetes の Pod から Config Map の値を参照するように Deployment YAML ファイルの内容を修正します。  &lt;/p&gt;

&lt;p&gt;修正箇所は下記になります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        env:
          - name: injected_value
            valueFrom:
              configMapKeyRef:
                name: microprofile-service-config
                key: injected_value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;修正した Deployment YAML は下記になります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: payara-config-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: payara-config-service
  template:
    metadata:
      labels:
        app: payara-config-service
        version: v1
        stage: develop
    spec:
      securityContext:
        runAsUser: 1000 
      containers:
      - name: payara-config-service
        image: containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0
        env:
          - name: injected_value
            valueFrom:
              configMapKeyRef:
                name: microprofile-service-config
                key: injected_value
        resources:
          requests:
            cpu: 100m
            memory: 1Gi
          limits:
            cpu: 200m
            memory: 1Gi

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Deployment YAML を修正した後適用してください。&lt;br&gt;&lt;br&gt;
適用した後 STATUS が Running になっていることを確認してください。&lt;br&gt;&lt;br&gt;
再起動した Pod をローカルからアクセスできるように Port Forward してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 修正した Deployment YAML の適用
$ kubectl apply -f  deployment.yaml 
deployment.apps/payara-config-service configured

# 再起動した Pod の一覧を取得
$ kubectl get po
NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-68bb7c8dfb-8tcbx   1/1     Running   0          22s
payara-config-service-68bb7c8dfb-f67x6   1/1     Running   0          20s

# ローカルからアクセスするためにポート・フォワードを実行
$ kubectl port-forward payara-config-service-68bb7c8dfb-8tcbx 8080:8080
Forwarding from 127.0.0.1:8080 -&amp;gt; 8080
Forwarding from [::1]:8080 -&amp;gt; 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ポート・フォワードを実行した後、アプリケーションのエンドポイントにアクセスしてください。すると Config Map で指定した値 (CONFIG MAP VALUE) が表示されていることを確認できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI CONFIG MAP VALUE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記で、Config Map から設定値を取り出しアプリケーションから参照できるようになりました。  &lt;/p&gt;

&lt;h4&gt;
  
  
  4.16. Config Map 値の更新と Pod の再起動
&lt;/h4&gt;

&lt;p&gt;最後に、設定値を変更する方法について確認します。  &lt;/p&gt;

&lt;p&gt;4.15 で設定した Config Map の値を更新 (CONFIG MAP VALUE NEW") します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: microprofile-service-config
data:
  injected_value: "CONFIG MAP VALUE NEW"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ファイルを保存した後、更新した Config Map を再度適用します。&lt;br&gt;&lt;br&gt;
適用した後 describe コマンドで正しく修正されているかを確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 修正した Config Map を適用
$ kubectl apply -f configmap.yaml 
configmap/microprofile-service-config configured

# Config Map の値が変わっているか否かの確認
$ kubectl describe cm microprofile-service-config
Name:         microprofile-service-config
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":{"injected_value":"CONFIG MAP VALUE NEW"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"microprofile-...

Data
====
injected_value:
----
CONFIG MAP VALUE NEW
Events:  &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Config Map の設定を反映した直後、アプリケーションのエンドポイントにアクセスしてみてください。&lt;br&gt;&lt;br&gt;
すると、新しい設定は反映されていない事が確認できます。&lt;br&gt;&lt;br&gt;
これは、Kubernetes の Pod は Config Map に設定した値を起動時にのみ読みにいくためです。Config Map の変更をチェックし自動的に再読み込みは行われないため、すでに起動している Pod にアクセスすると古い設定情報が表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI CONFIG MAP VALUE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;つまり、設定情報を反映するためには Pod の再起動が必要になります。　　&lt;br&gt;
Deployment で Pod をインストールしている場合、Pod の再起動を行うためには対象の Pod を削除すれば自動的に新しい Pod が起動されます。(Deployment YAML 中の replicas の数分だけ Pod は起動することが保証されるため)  &lt;/p&gt;

&lt;p&gt;そこで、Pod の一覧を取得した後、Pod を delete して新しい Pod が再起動されるのを待ちます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Pod の一覧を取得
$ kubectl get po
NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-68bb7c8dfb-8tcbx   1/1     Running   0          4m24s
payara-config-service-68bb7c8dfb-f67x6   1/1     Running   0          4m22s

# 特定の Pod を削除
$ kubectl delete po payara-config-service-68bb7c8dfb-8tcbx
pod "payara-config-service-68bb7c8dfb-8tcbx" deleted

# Pod の一覧を取得（payara-config-service-68bb7c8dfb-dx7sg が新しい Pod）
$ kubectl get po
NAME                                     READY   STATUS    RESTARTS   AGE
payara-config-service-68bb7c8dfb-dx7sg   1/1     Running   0          26s
payara-config-service-68bb7c8dfb-f67x6   1/1     Running   0          5m27s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;再起動した Pod を Port Forwad してローカルからアクセスできるようにします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl port-forward payara-config-service-68bb7c8dfb-dx7sg 8080:8080
Forwarding from 127.0.0.1:8080 -&amp;gt; 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Port Foward 後にアプリケーションのエンドポイントにアクセスすると Config Map で更新した値 (CONFIG MAP VALUE NEW) が表示されていることを確認できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI CONFIG MAP VALUE NEW
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;以上で、AKS 環境での MicroProfile Config の動作確認ができました。  &lt;/p&gt;

&lt;p&gt;設定を外部に出して管理する事で、ソースコードの修正なしに外部の接続先などを動的に変更することができます。これによりアプリケーションのテストや管理などコストが大幅に削減され、クラウド・ネィティブのアプリに一歩近づきます。ぜひ、ご適用ください。&lt;/p&gt;

</description>
      <category>java</category>
      <category>microprofile</category>
      <category>azure</category>
    </item>
    <item>
      <title>Azure Web App for Containers 環境で MicroProfile Config 動作検証</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Thu, 12 Mar 2020 05:51:39 +0000</pubDate>
      <link>https://dev.to/azure/azure-web-app-for-containers-microprofile-config-2a23</link>
      <guid>https://dev.to/azure/azure-web-app-for-containers-microprofile-config-2a23</guid>
      <description>&lt;h2&gt;
  
  
  1. Azure Web App for Containers 環境で MicroProfile Config 動作検証
&lt;/h2&gt;

&lt;p&gt;アプリケーションは、外部システムとの連携のための接続情報 (DB や、外部の HTTP エンドポイント)や、開発環境、テスト環境、本番環境などの環境設定の差を、プログラム・ソースコードから切り離し、外部の設定ファイル等に書き出すことで容易に接続先や設定を切り替えることができます。&lt;br&gt;
また、外部の設定ファイルなどに書き出しておくことで、接続先を切り替えるためにアプリケーションのソースコードの編集やビルドは不要で、同一のソースコードや実行ライブラリを利用できます。&lt;/p&gt;

&lt;p&gt;クラウド・ネィティブなアプリケーションを構築していくために、設定情報の外だしはとても重要です。&lt;br&gt;
「&lt;a href="https://12factor.net/ja/"&gt;参照：The Twelve Factors&lt;/a&gt;  の&lt;a href="https://12factor.net/ja/config"&gt;III. 設定&lt;/a&gt; : 設定を環境変数に格納する」&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Twelve-Factorは 設定をコードから厳密に分離すること を要求する。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;MicroProfile Config を利用すると、設定情報を下記のようなさまざまな場所から取得できます。&lt;br&gt;
これらの設定場所を ConfigSources と呼び、 同じプロパティが複数の ConfigSource で定義されている場合、ポリシーを適用しどの値が有効かを指定します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java VM のシステム ・プロパティから&lt;/li&gt;
&lt;li&gt;OS の環境変数&lt;/li&gt;
&lt;li&gt;外部構成ファイル (.properties, .xml)から&lt;/li&gt;
&lt;li&gt;LDAP, DB, Key-Value ストア などの外部データそ＝す&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;また状況によっては、一部のデータソースを動的に切り替えたい場合があります。そして変更した値は、アプリケーションを再起動することなく、プログラム上から更新した内容を利用する必要があります。こうしたニーズに応えるため、MicroProfile Config では、構成した値を変更直後から利用できるようになっています。&lt;/p&gt;
&lt;h2&gt;
  
  
  MicroProfile Config の実装について
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/index.html"&gt;Microprofile Config は API&lt;/a&gt; のみを規定しており実装は含まれていません。&lt;br&gt;
MicroProfile Config の実装は、各 MicroProfile の実装プロバイダから個別に提供されています。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://svn.apache.org/repos/asf/geronimo/components/config/trunk"&gt;Apache Geronimo Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.ibm.com/wasdev/"&gt;WebSphere Liberty 2017 March-June Beta so far&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.payara.fish/documentation/microprofile/config.html"&gt;Payara Server 173 and Payara Micro 173&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/smallrye/smallrye-config"&gt;WildFly &amp;amp; Thorntail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microbean.github.io/microbean-microprofile-config/"&gt;microBean™ MicroProfile Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  MicroProfile Config の概要
&lt;/h2&gt;

&lt;p&gt;MicroProfile Config は数少ない API から構成されています。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/index.html"&gt;MicroProfile Config API 1.4 の一覧&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/Config.html"&gt;Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigBuilder.html"&gt;ConfigBuilder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/inject/ConfigProperty.html"&gt;ConfigProperty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/ConfigProvider.html"&gt;ConfigProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigProviderResolver.html"&gt;ConfigProviderResolver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigSource.html"&gt;ConfigSource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/ConfigSourceProvider.html"&gt;ConfigSourceProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/spi/Converter.html"&gt;Converter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  ConfigSource の優先順位
&lt;/h2&gt;

&lt;p&gt;Configは、登録されたorg.eclipse.microprofile.config.spi.ConfigSourceから収集された情報で構成されます。 これらのConfigSourceは、順序に従ってソートされます。 これにより、外部から重要度の低い設定を上書きできます。&lt;/p&gt;

&lt;p&gt;デフォルトでは、3つのデフォルトConfigSourceがあります。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System.getProperties()（優先順位 = 400）&lt;/li&gt;
&lt;li&gt;System.getenv()（優先順位= 300）&lt;/li&gt;
&lt;li&gt;ClassPath上の META-INF/microprofile-config.properties ファイル（デフォルト優先順位 = 100、各ファイル中に config_ordinal プロパティを設定して個別に優先順位を設定可能）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;デフォルト値は、アプリケーションのパッケージ時にファイル内で指定でき、値はデプロイメントごとに後から上書きできます。 &lt;strong&gt;&lt;em&gt;「優先順位は値が大きいほど優先されます。」&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  設定情報の取得例
&lt;/h2&gt;

&lt;p&gt;MicroProfile Config 仕様では、設定値を読み取るために 2種類の方法を用意しています。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;プログラム的な設定情報の取得&lt;/li&gt;
&lt;li&gt;アノテーションを利用した設定情報の取得&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1. プログラム的な設定情報の取得
&lt;/h3&gt;

&lt;p&gt;プログラム的に Config インスタンスを取得し設定情報を取得するサンプルを下記に示します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class  MyAppWithGetConfigFromProgram {

    public Response invokeMicroserviceWithConfig() {
        // Config インスタンスの取得
        Config config = ConfigProvider.getConfig();
        // マイクロサービス A の URL を取得
        String microserviceA = config.getValue("URL_OF_MICROSERVICE_A", String.class);
        // マイクロサービス A の呼び出し
        return invokeMicroservice(microserviceA);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;設定情報を取得するためには、最初に &lt;a href="https://javadoc.io/doc/org.eclipse.microprofile.config/microprofile-config-api/latest/org/eclipse/microprofile/config/Config.html"&gt;Config&lt;/a&gt; インスタンスを取得しなければなりません。&lt;br&gt;
プログラム的に Config インスタンスを取得するためには、&lt;a href="https://javadoc.io/static/org.eclipse.microprofile.config/microprofile-config-api/1.4/org/eclipse/microprofile/config/ConfigProvider.html#getConfig--"&gt;ConfigProvider#getConfig()&lt;/a&gt; を呼び出して取得できます。&lt;br&gt;&lt;br&gt;
（Config クラスのインスタンスは、生成されたのちコンテキストクラスローダーに登録されます。）&lt;/p&gt;
&lt;h3&gt;
  
  
  2. アノテーションを利用した設定情報の取得 (推奨)
&lt;/h3&gt;

&lt;p&gt;アノテーションを利用し Config インスタンスを取得し、@ConfigProperty で設定情報を取得するサンプルを下記に示します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApplicationScoped
public class MyAppWithGetConfigFromAnnotation {

    @Inject
    private Config config;

    //The property myprj.some.url must exist in one of the configsources, otherwise a
    //DeploymentException will be thrown.
    @Inject
    @ConfigProperty(name="myprj.some.url")
    private String someUrl;

    //The following code injects an Optional value of myprj.some.port property.
    //Contrary to natively injecting the configured value, this will not lead to a
    //DeploymentException if the value is missing.
    @Inject
    @ConfigProperty(name="myprj.some.port")
    private Optional&amp;lt;Integer&amp;gt; somePort;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  MicroProfile Config サンプル・アプリケーション
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. MicroProfile Config サンプル・プロジェクトの作成
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://start.microprofile.io/"&gt;MicroProfile Starter&lt;/a&gt; にアクセスし、MicroProfile のプロジェクトを作成します。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z_reu7bS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://live.staticflickr.com/65535/49650925377_1310626472_z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z_reu7bS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://live.staticflickr.com/65535/49650925377_1310626472_z.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(DOWNLOAD) のリンクを押下すると MPConfigSample.zip ファイルがダウンロードできます。ファイルを展開すると下記のようなファイル・ディレクトリ構成が自動的に生成されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── pom.xml
├── readme.md
└── src
    └── main
        ├── java
        │   └── com
        │       └── yoshio3
        │           └── MPConfigSample
        │               ├── HelloController.java
        │               ├── MPConfigSampleRestApplication.java
        │               └── config
        │                   └── ConfigTestController.java
        ├── resources
        │   └── META-INF
        │       └── microprofile-config.properties
        └── webapp
            ├── WEB-INF
            │   └── beans.xml
            └── index.html
11 directories, 8 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;そして、MicroProfile Config のサンプルコードが ConfigTestController.java に下記のように記載されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.yoshio3.MPConfigSample.config;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/config")
@RequestScoped
public class ConfigTestController {

    @Inject
    @ConfigProperty(name = "injected.value")
    private String injectedValue;

    @Path("/injected")
    @GET
    public String getInjectedConfigValue() {
        return "Config value as Injected by CDI " + injectedValue;
    }

    @Path("/lookup")
    @GET
    public String getLookupConfigValue() {
        Config config = ConfigProvider.getConfig();
        String value = config.getValue("value", String.class);
        return "Config value from ConfigProvider " + value;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記のコードでは、プロパティに記載された値を HTTP のレスポンスとして返す簡単なコードです。&lt;br&gt;&lt;br&gt;
下記のように HTTP の GET メソッドで呼び出すと return 文で記載される文字列が返ってきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -X GET http://localhost:8080/data/config/injected
$ curl -X GET http://localhost:8080/data/config/lookup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;実際の設定内容は、META_INF ディレクトリ配下の microprofile-config.properties ファイルに記載されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# プロパティ・ファイルの場所
└── src
    └── main
        ├── resources
        │   └── META-INF
        │       └── microprofile-config.properties
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;デフォルトで下記のプロパティが設定されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# プロパティ・ファイルに設定された値
injected.value=Injected value
value=lookup value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2. サンプル・プロジェクトのビルドと実行
&lt;/h3&gt;

&lt;p&gt;MicroProfile Config の動作確認を行うため、プロジェクトをビルドし、アプリケーションを起動します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# プロジェクトのビルド
$ mvn clean package

# アプリケーションの実行
$ java -jar target/MPConfigSample-microbundle.jar 

......
Payara Micro URLs:
http://192.168.100.7:8080/

'ROOT' REST Endpoints:
GET     /data/application.wadl
GET     /data/config/injected
GET     /data/config/lookup
GET     /data/hello
GET     /openapi/
GET     /openapi/application.wadl
]]
[2020-03-10T22:19:06.610+0900] [] [情報] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583846346610] [levelValue: 800] Payara Micro  5.194 #badassmicrofish (build 327) ready in 32,755 (ms)
[2020-03-10T22:19:33.646+0900] [] [情報] [] [javax.enterprise.system.container.web.com.sun.web.security] [tid: _ThreadID=29 _ThreadName=http-thread-pool::http-listener(1)] [timeMillis: 1583846373646] [levelValue: 800] Context path from ServletContext:  differs from path from bundle: /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記のようにアプリケーションが起動したのち、curl コマンドを実行し動作確認を行います。&lt;br&gt;
正しく動作している場合、下記のようにプロパティ・ファイルから取得した設定 (Injected value, value) の文字列が表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# アノテーションで実装されたエンドポイントへの呼び出し
$ curl localhost:8080/data/config/injected
Config value as Injected by CDI Injected value

# プログラムで実装されたエンドポイントへの呼び出し
$ curl localhost:8080/data/config/lookup
Config value from ConfigProvider lookup value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;MicroProfile ではプロパティ・ファイルの設定値をシステム・プロパティで上書き設定することができます。そこで環境変数を設定し、環境変数の値を Java のシステム・プロパティに代入して実行します。すると "microprofile-config.properties" ファイルに設定した値を上書きし、環境変数に設定した値が表示されている事を確認できます。&lt;br&gt;
&lt;br&gt;
　&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 環境変数の設定 [.(ドット）を _(アンダーバー）に置き換えて設定]
$ export injected_value="Environment Value"

# 環境変数を Java のシステム・プロパティに設定してアプリを実行
$ java -D"$injected_value" -jar target/MPConfigSample-microbundle.jar

# アプリケーションの動作確認
$ curl http://localhost:8080/data/config/injected
Config value as Injected by CDI Environment Value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;ご注意：　properties ファイル中では . (ドット）表記で記載していますが、環境変数は OS によっては . (ドット）表記が使えません。そこで、環境変数の設定では . (ドット）表記箇所を _ (アンダーバー）に置き換えて設定してください。実装内部で自動的に変換をしています。&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. ローカルの Docker 環境での実行
&lt;/h3&gt;

&lt;p&gt;ローカルの環境でアプリケーションの動作確認ができたので、次にローカルの Docker 環境で MicroProfile を動作させます。Payara Micro の Docker コンテナのイメージを作成するため、下記のような Dockerfile を作成してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM payara/micro:5.201

USER payara
WORKDIR ${PAYARA_HOME}

# Deploy Artifact
COPY ./target/MPConfigSample.war $DEPLOY_DIR

CMD ["--nocluster","--deploymentDir", "/opt/payara/deployments", "--contextroot", "app"]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;次に、この Dockerfile を利用してコンテナのイメージを作成します。docker build コマンドを実行しコンテナのイメージを作成してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t tyoshio2002/payara-config-sample:1.0 .

# コマンド実行時のコンソール出力例
Sending build context to Docker daemon  151.2MB
Step 1/5 : FROM payara/micro:5.201
5.201: Pulling from payara/micro
050382585609: Already exists 
59f5185426ac: Already exists 
4d95208cd9c0: Pull complete 
c1409397cf71: Pull complete 
Digest: sha256:3ff92627d0d9b67454ee241cc7d5f2e485e46db81a886c87cf16035df7c80cc8
Status: Downloaded newer image for payara/micro:5.201
 ---&amp;gt; a11a548b0a25
Step 2/5 : USER payara
 ---&amp;gt; Running in cb755e484e79
Removing intermediate container cb755e484e79
 ---&amp;gt; 564283252ae4
Step 3/5 : WORKDIR ${PAYARA_HOME}
 ---&amp;gt; Running in f26dd5cd172c
Removing intermediate container f26dd5cd172c
 ---&amp;gt; f2bf88b18a77
Step 4/5 : COPY ./target/MPConfigSample.war $DEPLOY_DIR
 ---&amp;gt; 1b54373fe95a
Step 5/5 : CMD ["--nocluster","--deploymentDir", "/opt/payara/deployments", "--contextroot", "app"]
 ---&amp;gt; Running in 3eb731eb77c3
Removing intermediate container 3eb731eb77c3
 ---&amp;gt; 1d11549e99b8
Successfully built 1d11549e99b8
Successfully tagged tyoshio2002/payara-config-sample:1.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;コンテナのイメージが作成できたのち、コンテナを起動します。下記のコマンドを実行してコンテナを起動してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -p 8080:8080 -e injected_value=hogehoge -it tyoshio2002/payara-config-sample:1.0

# コマンド実行時のコンソール出力例
..... (中略)
[2020-03-11T07:46:59.119+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819119] [levelValue: 800] [[ 
{
    "Instance Configuration": {
        "Host": "3877abb54d57",
        "Http Port(s)": "8080",
        "Https Port(s)": "",
        "Instance Name": "payara-micro",
        "Instance Group": "no-cluster",
        "Deployed": [
            {
                "Name": "MPConfigSample",
                "Type": "war",
                "Context Root": "/app"
            }
        ]
    }
}]]
[2020-03-11T07:46:59.131+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819131] [levelValue: 800] [[
Payara Micro URLs:
http://3877abb54d57:8080/app
'MPConfigSample' REST Endpoints:
GET /app/data/application.wadl
GET /app/data/config/injected
GET /app/data/config/lookup
GET /app/data/hello
]]
[2020-03-11T07:46:59.131+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1583912819131] [levelValue: 800] Payara Micro  5.201 #badassmicrofish (build 512) ready in 31,286 (ms)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;作成したコンテナの起動が完了したので、コンテナ上で動作するアプリケーションに対して接続をします。&lt;br&gt;&lt;br&gt;
今回は、起動時にコンテナ内部の 8080番ポートを、ローカルの 8080番ポートにマッピングしていますので、ローカル環境の 8080 番ポートにアクセスすることで、コンテナのアプリケーションに接続できます。 &lt;br&gt;
下記のコマンドを実行してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/app/data/config/injected
Config value as Injected by CDI hogehoge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;コンテナの起動時に引数として環境変数 (&lt;strong&gt;&lt;em&gt;-e injected_value=hogehoge&lt;/em&gt;&lt;/strong&gt;) を与えているため、起動時に入力した文字列が表示されます。&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Azure Web App for Containers 環境での実行
&lt;/h3&gt;

&lt;p&gt;ローカルの Docker 環境で動作確認ができたので、&lt;a href="https://aka.ms/docs-webapp-for-containers"&gt;Web App for Containers&lt;/a&gt; 環境で動作確認を行います。下記の手順に従い動作確認を行います。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; 用のリソース・グループを作成&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; を作成&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; のパスワードの確認&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; にログインしイメージを Push&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; に Push したイメージの確認&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-webapp-for-containers"&gt;Web App for Containers&lt;/a&gt; 用のリソース・グループを作成&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-webapp-for-containers"&gt;Web App for Containers&lt;/a&gt; 用の AppService プランの作成&lt;/li&gt;
&lt;li&gt;コンテナ・イメージを指定し &lt;a href="https://aka.ms/docs-webapp-for-containers"&gt;Web App for Containers&lt;/a&gt; を作成&lt;/li&gt;
&lt;li&gt;デプロイしたアプリケーションの動作確認&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/docs-webapp-for-containers"&gt;Web App for Containers&lt;/a&gt; のアプリケーション設定の追加&lt;/li&gt;
&lt;li&gt;設定変更後のアプリケーションの動作確認&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  4.1. Azure Container Registry 用のリソース・グループを作成
&lt;/h4&gt;

&lt;p&gt;まずは、&lt;a href="https://aka.ms/docs-container-registry"&gt;Azure Container Registry&lt;/a&gt; を作成し、ローカルで作成した Docker コンテナのイメージをアップロードします。そこで、Azure Container Registry を作成するためのリソース・グループを作成します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az group create --name WebApp-Containers --location "Japan East"
{
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers",
  "location": "japaneast",
  "managedBy": null,
  "name": "WebApp-Containers",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2. Azure Container Registry を作成
&lt;/h4&gt;

&lt;p&gt;次に、Azure Container Registry を作成します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name にコンテナ・レジストリ名を指定します
&lt;/li&gt;
&lt;li&gt;--resource-group に上記で作成したリソース・グループ名を指定します
&lt;/li&gt;
&lt;li&gt;--sku は "Basic", "Standard", "Premium" の何れかを指定します
&lt;/li&gt;
&lt;li&gt;--admin-enabled true に設定する事で、コンテナ・レジストリに docker コマンドでアクセスできるようにします
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr create --name containerreg4yoshio --resource-group WebApp-Containers --sku Basic --admin-enabled true
{
  "adminUserEnabled": true,
  "creationDate": "2020-03-12T02:27:59.357654+00:00",
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp-Containers/providers/Microsoft.ContainerRegistry/registries/containerreg4yoshio",
  "location": "japaneast",
  "loginServer": "containerreg4yoshio.azurecr.io",
  "name": "containerreg4yoshio",
  "networkRuleSet": null,
  "policies": {
    "quarantinePolicy": {
      "status": "disabled"
    },
    "retentionPolicy": {
      "days": 7,
      "lastUpdatedTime": "2020-03-12T02:28:01.654662+00:00",
      "status": "disabled"
    },
    "trustPolicy": {
      "status": "disabled",
      "type": "Notary"
    }
  },
  "provisioningState": "Succeeded",
  "resourceGroup": "WebApp-Containers",
  "sku": {
    "name": "Basic",
    "tier": "Basic"
  },
  "status": null,
  "storageAccount": null,
  "tags": {},
  "type": "Microsoft.ContainerRegistry/registries"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.3. Azure Container Registry のパスワードの確認
&lt;/h4&gt;

&lt;p&gt;次に、Azure Container Registry に接続するためのパスワードを確認します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name にコンテナ・レジストリ名を指定します
&lt;/li&gt;
&lt;li&gt;--resource-group に上記で作成したリソース・グループ名を指定します
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr credential show --name containerreg4yoshio --resource-group WebApp-Containers
{
  "passwords": [
    {
      "name": "password",
      "value": "4zaIiLk*************+H1XO4AlYFvN"
    },
    {
      "name": "password2",
      "value": "fT03XPs*************Oq2cAZiVHV+L"
    }
  ],
  "username": "containerreg4yoshio"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.4. Azure Container Registry にログインしイメージを Push
&lt;/h4&gt;

&lt;p&gt;次に、docker login コマンドを実行し Azure Container Registry に接続します。&lt;br&gt;&lt;br&gt;
(パスワードは上記で取得したパスワードを入力してください。)  &lt;/p&gt;

&lt;p&gt;ログインが完了すると、docker tag コマンドでイメージのタグ付けを行います。ローカルで作成した Docker コンテナのイメージ名に、コンテナ・レジストリの   "loginServer" 名 ( 例："containerreg4yoshio.azurecr.io") を付け加えた名前でタグ付けします。  &lt;/p&gt;

&lt;p&gt;最後に、docker push コマンドを実行し、Azure Container Registry にイメージを Push します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Azure Container Registry にログイン
$ docker login containerreg4yoshio.azurecr.io -u containerreg4yoshio
Password: 
Login Succeeded

# Docker コンテナのタグ付け
$ docker tag tyoshio2002/payara-config-sample:1.0 containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0

# Azure Container Registry にタグ付けしたイメージを Push
$ docker push containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0

The push refers to repository [containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample]
bbd197848553: Pushed 
ec40a5d738cc: Pushed 
f95fe3528c56: Pushed 
bded2364df91: Pushed 
1bfeebd65323: Pushed 
1.0: digest: sha256:689dbacc212d37afe09c43417bc79d8e241c3fa7b5cf71c27097ef535cf77f76 size: 1368
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.5. Azure Container Registry に Push したイメージの確認
&lt;/h4&gt;

&lt;p&gt;Azure Container Registry に正しくイメージが Push されていることを確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az acr repository list -n containerreg4yoshio -g WebApp-Containers
Argument 'resource_group_name' has been deprecated and will be removed in a future release.
[
  "tyoshio2002/payara-config-sample"
]

$ az acr repository show-tags --name containerreg4yoshio  --repository tyoshio2002/payara-config-sample
[
  "1.0"
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.6. Web App for Containers 用のリソース・グループを作成
&lt;/h4&gt;

&lt;p&gt;Azure Conginer Registry を作成したので、次に Web App for Containers を作成します。まず、Web App for Containers を作成するリソース・グループを作成します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az group create --name WebApp --location "Japan East"
{
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp",
  "location": "japaneast",
  "managedBy": null,
  "name": "WebApp",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.7. Web App for Containers 用の AppService プランの作成
&lt;/h4&gt;

&lt;p&gt;次に、Linux 用の AppService プランを作成します。今回は検証環境での動作確認のため、SKU は B1 を利用していますが、環境に応じて適宜、ご選択ください。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name にAppService プラン名を指定します
&lt;/li&gt;
&lt;li&gt;--resource-group に上記で作成したリソース・グループ名を指定します
&lt;/li&gt;
&lt;li&gt;--sku に F1, B1, P1V2, P2V2, P3V2, I1, I2, I3 など稼働させるマシン・価格など適切な SKU (Stock Keeping Unit)を指定します&lt;/li&gt;
&lt;li&gt;--is-linux は Linux 環境での構築を指定します。
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az appservice plan create --name webapp4container --resource-group WebApp --sku B1 --is-linux
{
  "freeOfferExpirationTime": "2020-04-11T02:38:56.873333",
  "geoRegion": "Japan East",
  "hostingEnvironmentProfile": null,
  "hyperV": false,
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp/providers/Microsoft.Web/serverfarms/webapp4container",
  "isSpot": false,
  "isXenon": false,
  "kind": "linux",
  "location": "Japan East",
  "maximumElasticWorkerCount": 1,
  "maximumNumberOfWorkers": 3,
  "name": "webapp4container",
  "numberOfSites": 0,
  "perSiteScaling": false,
  "provisioningState": "Succeeded",
  "reserved": true,
  "resourceGroup": "WebApp",
  "sku": {
    "capabilities": null,
    "capacity": 1,
    "family": "B",
    "locations": null,
    "name": "B1",
    "size": "B1",
    "skuCapacity": null,
    "tier": "Basic"
  },
  "spotExpirationTime": null,
  "status": "Ready",
  "subscription": "f77aafe8-****-****-****-d0c37687ef70",
  "tags": null,
  "targetWorkerCount": 0,
  "targetWorkerSizeId": 0,
  "type": "Microsoft.Web/serverfarms",
  "workerTierName": null
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.8. コンテナ・イメージを指定し Web App for Containers を作成
&lt;/h4&gt;

&lt;p&gt;次に、Azure Container Registry に Push したイメージを利用して Web App for Containers を作成します。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--name に Web App for Containers の名前を指定します
&lt;/li&gt;
&lt;li&gt;--resource-group に上記で作成したリソース・グループ名を指定します
&lt;/li&gt;
&lt;li&gt;--plan に上記で作成した AppService プラン名を指定します&lt;/li&gt;
&lt;li&gt;--deployment-container-image-name に Azure Container Registry に Push したイメージ名を指定します。
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az webapp create --resource-group WebApp \ 
                               --plan webapp4container \
                               --name yoshiowebapp \
                               --deployment-container-image-name containerreg4yoshio.azurecr.io/tyoshio2002/payara-config-sample:1.0

No credential was provided to access Azure Container Registry. Trying to look up...
{
  "availabilityState": "Normal",
  "clientAffinityEnabled": true,
  "clientCertEnabled": false,
  "clientCertExclusionPaths": null,
  "cloningInfo": null,
  "containerSize": 0,
  "dailyMemoryTimeQuota": 0,
  "defaultHostName": "yoshiowebapp.azurewebsites.net",
  "enabled": true,
  "enabledHostNames": [
    "yoshiowebapp.azurewebsites.net",
    "yoshiowebapp.scm.azurewebsites.net"
  ],
  "ftpPublishingUrl": "ftp://waws-prod-ty1-***.ftp.azurewebsites.windows.net/site/wwwroot",
  "geoDistributions": null,
  "hostNameSslStates": [
    {
      "hostType": "Standard",
      "ipBasedSslResult": null,
      "ipBasedSslState": "NotConfigured",
      "name": "yoshiowebapp.azurewebsites.net",
      "sslState": "Disabled",
      "thumbprint": null,
      "toUpdate": null,
      "toUpdateIpBasedSsl": null,
      "virtualIp": null
    },
    {
      "hostType": "Repository",
      "ipBasedSslResult": null,
      "ipBasedSslState": "NotConfigured",
      "name": "yoshiowebapp.scm.azurewebsites.net",
      "sslState": "Disabled",
      "thumbprint": null,
      "toUpdate": null,
      "toUpdateIpBasedSsl": null,
      "virtualIp": null
    }
  ],
  "hostNames": [
    "yoshiowebapp.azurewebsites.net"
  ],
  "hostNamesDisabled": false,
  "hostingEnvironmentProfile": null,
  "httpsOnly": false,
  "hyperV": false,
  "id": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp/providers/Microsoft.Web/sites/yoshiowebapp",
  "identity": null,
  "inProgressOperationId": null,
  "isDefaultContainer": null,
  "isXenon": false,
  "kind": "app,linux,container",
  "lastModifiedTimeUtc": "2020-03-12T02:39:50.356666",
  "location": "Japan East",
  "maxNumberOfWorkers": null,
  "name": "yoshiowebapp",
  "outboundIpAddresses": "13.**.***.96,13.**.**.49,13.**.**.66,13.**.**.140,13.**.**.186",
  "possibleOutboundIpAddresses": "13.**.**.96,13.**.**.49,13.**.**.66,13.**.**.140,13.**.**.186,13.**.**.30,13.**.**.70,13.**.**.101,13.**.**.163,13.**.**.200",
  "redundancyMode": "None",
  "repositorySiteName": "yoshiowebapp",
  "reserved": true,
  "resourceGroup": "WebApp",
  "scmSiteAlsoStopped": false,
  "serverFarmId": "/subscriptions/f77aafe8-****-****-****-d0c37687ef70/resourceGroups/WebApp/providers/Microsoft.Web/serverfarms/webapp4container",
  "siteConfig": null,
  "slotSwapStatus": null,
  "state": "Running",
  "suspendedTill": null,
  "tags": null,
  "targetSwapSlot": null,
  "trafficManagerHostNames": null,
  "type": "Microsoft.Web/sites",
  "usageState": "Normal"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.9. デプロイしたアプリケーションの動作確認
&lt;/h4&gt;

&lt;p&gt;Web App for Containers を作成したのち、Web App for Containers のエンドポイントにアクセスし、正しくアプリケーションが動作しているか否かを確認します。&lt;br&gt;&lt;br&gt;
ここでは、環境変数を設定していないため、プロパティで設定した値 (Injected value) が表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl https://yoshiowebapp.azurewebsites.net/app/data/config/injected
Config value as Injected by CDI Injected value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.10. Web App for Containers のアプリケーション設定の追加
&lt;/h4&gt;

&lt;p&gt;次に、Web App Config のアプリケーション設定を追加し、injected_value に "Value from Server App Setting" という文字列を設定します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ az webapp config appsettings set --resource-group WebApp --name yoshiowebapp --settings injected_value="Value from Server App Setting"
[
  {
    "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
    "slotSetting": false,
    "value": "false"
  },
  {
    "name": "DOCKER_REGISTRY_SERVER_URL",
    "slotSetting": false,
    "value": "containerreg4yoshio.azurecr.io/tyoshio2002"
  },
  {
    "name": "DOCKER_REGISTRY_SERVER_USERNAME",
    "slotSetting": false,
    "value": "containerreg4yoshio"
  },
  {
    "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
    "slotSetting": false,
    "value": null
  },
  {
    "name": "WEBSITES_PORT",
    "slotSetting": false,
    "value": "8080"
  },
  {
    "name": "injected_value",
    "slotSetting": false,
    "value": "Value from Server App Setting"
  }
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  4.11. 設定変更後のアプリケーションの動作確認
&lt;/h4&gt;

&lt;p&gt;最後に、アプリケーション設定で追加した設定が反映されているかを確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl https://yoshiowebapp.azurewebsites.net/app/data/config/injected
Config value as Injected by CDI Value from Server App Setting
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;上記 4.10 の設定後は、明示的にコンテナを再起動しなくても内部的に再起動が行われ設定が反映されます&lt;/p&gt;

&lt;p&gt;以上で、MicroProfile Config を使用したアプリケーションを Azure Web App for Containers 環境で動作させることができました。また Web App for Containers のアプリケーション設定（外部の設定値）をアプリケーションで読み取ることができました。&lt;/p&gt;

</description>
      <category>java</category>
      <category>microprofile</category>
      <category>azure</category>
    </item>
    <item>
      <title>Use DaemonSet as a cache when referencing large files from each pod</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Tue, 21 Jan 2020 09:31:52 +0000</pubDate>
      <link>https://dev.to/azure/use-daemonset-as-a-cache-when-referencing-large-files-from-each-pod-11lb</link>
      <guid>https://dev.to/azure/use-daemonset-as-a-cache-when-referencing-large-files-from-each-pod-11lb</guid>
      <description>&lt;p&gt;Assuming that the problem that came up when I met a certain customer this time and conducted a hackfest and the solution that I proposed to the customer might be effective if there were similar requirements elsewhere, Share that way here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Following Use Case will be fit for this approach&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is necessary to read the same huge file (GB class file) from each pod&lt;/li&gt;
&lt;li&gt;File is read only, no write
(If writing is required, another method is available.) &lt;/li&gt;
&lt;li&gt;I want to read a huge file as soon as possible&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: Please consider the appropriate way by yourself depends on your requirements.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you encounter the above scenario ,please consider to use the DaemonSet as a cache? Use the DaemonSet to launch one pod on each Node, and each pod in the DaemonSet have a copy of the file. Pods who want to refer to and acquire files is possible for not only reduce the communication across networks by acquiring and referencing copy files from the pod of the DaemonSet, but also can get files in a short time because the file is transfered by local network. (explaining the obvious things and evaluated it).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F49397387046_95f736b451.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F49397387046_95f736b451.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;General Kubernetes volume mounting method&lt;/h2&gt;

&lt;p&gt;When dealing with persistent volumes in each pods, there is some way to mount the volume on each pods. And many cloud providers provide plugins to handle Persistence Volume on each cloud storage, and there are methods to mount disks in storage from each pod (3 way: ReadWriteOnce, ReadOnlyMany) , ReadWriteMany).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Please refer to the Kubernetes documentation&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/" rel="noopener noreferrer"&gt; Volumes &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/" rel="noopener noreferrer"&gt; Persistent Volumes &lt;/a&gt;
 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to mount a disk one-to-one from each pod in Azure (ReadWriteOnce),you can use the Azure Disk. If you want to share the same Disk from multiple pods (ReadOnlyMany, ReadWriteMany), you can use the Azure Files. In this use case, we want to refer to large files from multiple pods, so I selected Azure Files (ReadOnlyMany).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F49396908163_efd141c26a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F49396908163_efd141c26a.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specifically, you can create Azure Files by following procedure and use Azure Files as a Kubernetes Persistence Volume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export AKS_PERS_STORAGE_ACCOUNT_NAME=myfilestorageaccount
$ export AKS_PERS_RESOURCE_GROUP=Yoshio-Storage
$ export AKS_PERS_LOCATION=japaneast
$ export AKS_PERS_SHARE_NAME=aksshare

$ az storage account create -n $AKS_PERS_STORAGE_ACCOUNT_NAME -g $AKS_PERS_RESOURCE_GROUP -l $AKS_PERS_LOCATION --sku Standard_LRS

$ export AZURE_STORAGE_CONNECTION_STRING=`az storage account show-connection-string -n $AKS_PERS_STORAGE_ACCOUNT_NAME -g $AKS_PERS_RESOURCE_GROUP -o tsv`

$ az storage share create -n $AKS_PERS_SHARE_NAME

$ STORAGE_KEY=$(az storage account keys list --resource-group $AKS_PERS_RESOURCE_GROUP --account-name $AKS_PERS_STORAGE_ACCOUNT_NAME --query "[0].value" -o tsv)

$ kubectl create secret generic azure-secret --from-literal=azurestorageaccountname=$AKS_PERS_STORAGE_ACCOUNT_NAME --from-literal=azurestorageaccountkey=$STORAGE_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, please create the Deployment artifact for mounting the volumes in each pods?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: ubuntu
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ubuntu
  template:
    metadata:
      labels:
        app: ubuntu
        version: v1
    spec:
      containers:
      - name: ubuntu
        image: ubuntu
        command:
          - sleep
          - infinity
        volumeMounts:
          - mountPath: "/mnt/azure"
            name: volume
        resources:
          limits:
            memory: 4000Mi
          requests:
            cpu: 1000m
            memory: 4000Mi
        env:
          - name: NODE_IP
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
      volumes:
        - name: volume
          azureFile:
            secretName: azure-secret
            shareName: aksshare
            readOnly: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this time, I configured the memory as 4GB because it copy large files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please save the above file as deployment.yaml and execute the following command?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the pod launches successfully, you can execute the following command to confirm the mount status. And you can see the Azure Files is mounted at /mnt/azure on individual pods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl exec -it ubuntu-884df4bfc-7zgkz mount |grep azure
//**********.file.core.windows.net/aksshare on /mnt/azure 
type cifs (rw,relatime,vers=3.0,cache=strict,username=********,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=40.***.***.76,file_mode=0777,dir_mode=0777,soft,persistenthandles,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the above result, the actual file exists on Files Share (***************.file.core.windows.net/aksshare) of Azure Storage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://live.staticflickr.com/65535/49397635697_071627f88d_c.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F49397635697_071627f88d_w.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to download or refer to the files from the /aksshare, it will use the the Samba Protocol.&lt;br&gt;
You can confirm it by using following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# date
Wed Jan 15 16:29:03 UTC 2020
# cp /mnt/azure/Kuberenetes-Operation-Demo.mov ~/mount.mov
# date
Wed Jan 15 16:29:54 UTC 2020 (51 Seconds)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the above, you can see that it took about 51 seconds to copy about 3 Gb video file into the pod. If multiple pods start up and refer to the same file, the file copy will be repeated over the network. It is inefficiency but normal usage.&lt;/p&gt;

&lt;p&gt;In this time, we will use DaemonSet to improve the number of network transfers and the speed of this file sharing.&lt;/p&gt;

&lt;h2&gt; How to create the DaemonSet as a cache&lt;/h2&gt;

&lt;p&gt;In this time, I used the Nginx Server for container which running on DaemonSet. I copy the file to under the context root (/ app) of Nginx from Azure Blog Storage so that you can retrieve the file by HTTP Protocol.&lt;br&gt;
I configured the below so that the contents in /app can be obtained via &lt;a href="http://podIP/" rel="noopener noreferrer"&gt;http://podIP/&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM alpine:3.6

RUN apk update &amp;amp;&amp;amp; \
    apk add --no-cache nginx

RUN apk add curl

ADD default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
RUN mkdir /app
RUN mkdir -p /run/nginx

WORKDIR /app
CMD nginx -g "daemon off;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please Save the above as a Dockerfile?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 80 default_server;
  listen [::]:80 default_server;

  root /app;

  location / {
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please Save the above as default.conf?&lt;/p&gt;

&lt;p&gt;After that, Please Build this image and push it to the Azure Container Registry?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t tyoshio2002/nginxdatamng:1.1 .
$ docker tag tyoshio2002/nginxdatamng:1.1 yoshio.azurecr.io/tyoshio2002/nginxdatamng:1.1
$ docker login -u yoshio yoshio.azurecr.io 
Password: 
$ docker push yoshio.azurecr.io/tyoshio2002/nginxdatamng:1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, Please create a secret to connect to Azure Container Registry from Kubernetes Cluster?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create secret docker-registry docker-reg-credential --docker-server=yoshio.azurecr.io --docker-username=yoshio  --docker-password="***********************" --docker-email=foo-bar@microsoft.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have pushed the image to the Azure Container Registry, we will write a manifest for the Daemonset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: mydaemonset
  labels:
    app: mydaemonset
spec:
  selector:
    matchLabels:
      name: mydaemonset
  template:
    metadata:
      labels:
        name: mydaemonset
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      imagePullSecrets:
        - name: docker-reg-credential
      containers:
      - name: nginx
        image: yoshio.azurecr.io/tyoshio2002/nginxdatamng:1.1
        resources:
          limits:
            memory: 4000Mi
          requests:
            cpu: 1000m
            memory: 4000Mi
        lifecycle:
          postStart:
            exec:
              command:
                - sh
                - -c
                - "curl https://myfilestorageaccount.blob.core.windows.net/fileshare/Kuberenetes-Operation-Demo.mov -o /app/aaa.mov"
      terminationGracePeriodSeconds: 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this case, a single file (Kuberenetes-Operation-Demo.mov) is downloaded under /app in the postStart phase to simplify verification. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you need to use the multiple files, you need to implement the mechanism separately to download multiple files in the container image. &lt;/p&gt;

&lt;p&gt;It is also assumed that it is possible to customize Nginx or use other web servers and App servers to improve the efficiency such as enabling content caching.&lt;/p&gt;

&lt;p&gt;Please Save the above manifest file as daemonset.yaml and execute the following command?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f daemonset.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating a DaemonSet, Please create a Service for the DaemonSet? By creating a Service, you can access port 30001 of each node and access Nginx with the Node IP address with port number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  labels:
    app: daemonset-service
  name: daemonset-service
spec:
  ports:
  - port: 80
    name: http
    targetPort: 80
    nodePort: 30001
  selector:
    name: mydaemonset
  sessionAffinity: None
  type: NodePort
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please Save the above file as service.yaml and execute the following command?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After deploying Nginx DaemonSet and Ubuntu Deployment respectively, execute the following command to check which pod is running on which node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get no -o wide
NAME                                STATUS   ROLES   AGE    VERSION                         INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
aks-agentpool-41616757-vmss000000   Ready    agent   176m   v1.15.7                         10.240.0.4            Ubuntu 16.04.6 LTS   4.15.0-1064-azure   docker://3.0.8
aks-agentpool-41616757-vmss000001   Ready    agent   176m   v1.15.7                         10.240.0.35           Ubuntu 16.04.6 LTS   4.15.0-1064-azure   docker://3.0.8
aks-agentpool-41616757-vmss000002   Ready    agent   176m   v1.15.7                         10.240.0.66           Ubuntu 16.04.6 LTS   4.15.0-1064-azure   docker://3.0.8
virtual-node-aci-linux              Ready    agent   175m   v1.14.3-vk-azure-aci-v1.1.0.1   10.240.0.48                                  
$ kubectl get po -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE                                NOMINATED NODE   READINESS GATES
mydaemonset-gqlrw        1/1     Running   0          72m   10.240.0.24   aks-agentpool-41616757-vmss000000              
mydaemonset-nnn5l        1/1     Running   0          72m   10.240.0.50   aks-agentpool-41616757-vmss000001              
mydaemonset-pzvzx        1/1     Running   0          72m   10.240.0.82   aks-agentpool-41616757-vmss000002              
ubuntu-884df4bfc-7zgkz   1/1     Running   0          64m   10.240.0.69   aks-agentpool-41616757-vmss000002              
ubuntu-884df4bfc-gd26h   1/1     Running   0          63m   10.240.0.33   aks-agentpool-41616757-vmss000000              
ubuntu-884df4bfc-vh7rg   1/1     Running   0          63m   10.240.0.49   aks-agentpool-41616757-vmss000001              
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the above, ubuntu-884df4bfc-vh7rg is running on the node aks-agentpool-41616757-vmss000001, and on the node aks-agentpool-41616757-vmss000001 the DaemonSet Pod of mydaemonset-nnn5l is running.&lt;br&gt;
And you can see that the node IP address of aks-agentpool-41616757-vmss000001 is 10.240.0.35. &lt;/p&gt;

&lt;p&gt;Inside of the Ubuntu pod, the IP address of the Node where the pod is running is got by the environment variable $ NODE_IP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl exec -it ubuntu-884df4bfc-vh7rg env|grep NODE_IP
NODE_IP=10.240.0.35
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt; &lt;b&gt;In Addition&lt;/b&gt; &lt;/u&gt;&lt;br&gt;
Lastly, we will skip the detailed explanation of how to create each of Standard and Premium (high speed) Azure Blob Storage.&lt;/p&gt;

&lt;p&gt;After you created both of them, please copy the same video file in each storage?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Premium Storage of Azure Blob is connected to AKS VNET and files are obtained via VNET.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Other Reference information&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/azure/virtual-machines/windows/premium-storage-performance?WT.mc_id=docs-blog-yoterada" rel="noopener noreferrer"&gt;Azure premium storage: design for high performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-troubleshoot-linux-file-connection-problems?WT.mc_id=docs-blog-yoterada" rel="noopener noreferrer"&gt;Troubleshoot Azure Files problems in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-troubleshooting-files-performance?WT.mc_id=docs-blog-yoterada" rel="noopener noreferrer"&gt;Troubleshoot Azure Files performance issues&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt; Verification Details &lt;/h2&gt;

&lt;p&gt;In this time, I evaluated the following four points.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Time required to copy files in the directory where Azure Files is mounted to the pod&lt;/li&gt;
&lt;li&gt;Time required to retrieve files existing in Azure Blob (Standard) by pod&lt;/li&gt;
&lt;li&gt;Time required to retrieve files existing in Azure Blob (Premium) by pod&lt;/li&gt;
&lt;li&gt;Time required to get from files copied in DaemonSet&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First Try (The video of actual verification contents)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=fe4QSfe9n-A" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2Ffe4QSfe9n-A%2Fmq2.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=fe4QSfe9n-A" rel="noopener noreferrer"&gt;Video: https://www.youtube.com/watch?v=fe4QSfe9n-A&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Confirmed by executing the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl exec -it ubuntu-884df4bfc-vh7rg

## File Put on Azure Files (File shares : Samba)
$ date
$ cp /mnt/azure/Kuberenetes-Operation-Demo.mov ~/mount.mov
$ date

## File Put on Azure Blob (Containers)
$ curl https://myfilestorageaccount.blob.core.windows.net/fileshare/Kuberenetes-Operation-Demo.mov -o ~/direct.mov
$ curl https://mypremiumstorageaccount.blob.core.windows.net/fileshare/Kuberenetes-Operation-Demo.mov -o ~/premium2.mov
$ curl http://$NODE_IP:30001/aaa.mov -o ~/fromNodeIP.mov
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result of Third Try:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Copy from PV(Samba)&lt;/td&gt;
&lt;td&gt;Get file from Standard Storage&lt;/td&gt;
&lt;td&gt;Get file from Premium Storage&lt;/td&gt;
&lt;td&gt;Get file from DaemonSet Cache&lt;/td&gt;
&lt;/tr&gt;



&lt;tr&gt;
&lt;td&gt;１&lt;/td&gt;
&lt;td&gt;51 Sec&lt;/td&gt;
&lt;td&gt;69 Sec&lt;/td&gt;
&lt;td&gt;27 Sec&lt;/td&gt;
&lt;td&gt;20 Sec&lt;/td&gt;


&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;２&lt;/td&gt;
&lt;td&gt;60 Sec&lt;/td&gt;
&lt;td&gt;60 Sec&lt;/td&gt;
&lt;td&gt;23 Sec&lt;/td&gt;
&lt;td&gt;11 Sec&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;td&gt;３&lt;/td&gt;
&lt;td&gt;53 Sec&lt;/td&gt;
&lt;td&gt;57 Sec&lt;/td&gt;
&lt;td&gt;20 Sec&lt;/td&gt;
&lt;td&gt;8 Sec&lt;/td&gt;
&lt;/tr&gt;

&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;By the way, even when using Nginx of DaemonSet, it takes time for the first access. This assumes that it is taking a long time to get, probably because it is not in Nginx memory. In other environments, it is faster after the second access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt; Result Summary of verification &lt;/h2&gt;

&lt;p&gt;From the results of the above three executions, it was found that it is the fastest to get the file into the DaemonSet and *** get the file from the DaemonSet's cache***.&lt;br&gt;
By using Premium storage, you can transfer files faster than Standard storage, but Premium costs more than Standard. Also, in the case of acquisition from Storage, it is necessary to download files via the network each time. Therefore, considering that, it is most efficient to first get the file on the same node (VM) and get it from there. It is natural to be quick and quick.&lt;br&gt;
 &lt;br&gt;
&lt;u&gt; &lt;b&gt; Advantages of using DaemonSet &lt;/b&gt; &lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce network traffic&lt;/li&gt;
&lt;li&gt;Faster file acquisition speed&lt;/li&gt;
&lt;li&gt;If the implementation of the container in the DaemonSet is made richer, it can be used for other purposes (for example, writing support).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt; &lt;b&gt; Concerns &lt;/b&gt; &lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Currently, a specific single file is acquired, but when handling multiple files or when there is an update of the file, a mechanism to periodically check for updates inside the DaemonSet and download the updated part Need to implement&lt;/li&gt;
&lt;li&gt;The file size in the DaemonSet pod may be bloated and needs to be cleaned up&lt;/li&gt;
&lt;li&gt;Regarding file writing, it is difficult to respond if this verification method is used as it is, but it is assumed that it will be supported if you implement a function like the In Memory Grid product in the container inside the DaemonSet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt; &lt;b&gt; Finally: &lt;/b&gt; &lt;/u&gt;&lt;br&gt;
In addition, I conducted some other internal verifications, but because the explanation contents increased and the viewpoint was likely to be blurred, we focused on only the points that were particularly effective. Also, in order to make it as simple as possible, I used Nginx for DaemonSet, but I think that further performance improvement is needed, you can tune up the Nginx configuration or changing another implementation. &lt;/p&gt;

&lt;p&gt;I would be very grateful if you could give further tuning based on this information.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>daemonset</category>
    </item>
    <item>
      <title>Please don't move from Monolithic Application to Monolithic Kubernetes Cluster? </title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Tue, 04 Jun 2019 18:34:13 +0000</pubDate>
      <link>https://dev.to/azure/important-points-of-kubernetes-cluster-design-4b2h</link>
      <guid>https://dev.to/azure/important-points-of-kubernetes-cluster-design-4b2h</guid>
      <description>&lt;p&gt;This is my proposal message from experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;I recommend you to not create the huge size of node on one Kubernetes Cluster.&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;According to the following document, If you use the Azure Kubernetes Service(AKS), the number of max node is 100. &lt;br&gt;
&lt;a href="https://docs.microsoft.com/azure/aks/quotas-skus-regions?WT.mc_id=devto-blog-yoterada"&gt;Quotas, virtual machine size restrictions, and region availability in Azure Kubernetes Service (AKS)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, I don't recommend you to create the cluster with max node size.&lt;br&gt;
Because it is same as creating a new Monolith in Container　Environment(Kubernetes) again.&lt;/p&gt;

&lt;p&gt;As you can imagine, if you created it, you may face the following issue.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Increase in Impact&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
If you created 150 microservices on 100 nodes and there are system failures or other performance impacts, all 150 services may be affected.&lt;br&gt;
The scope of this impact compared to a monolithic application(10-20 services) is a much worse situation with a monolithic kubernetes cluster(150 services).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Increased time to upgrade&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
There is a kubernetes release every 3-4 months.&lt;br&gt;
And AKS(Kubernetes) has an end of life policy that requires updating or reinstalling the kubernetes cluster approximately every 1 or 2 year at minimum.&lt;br&gt;
&lt;a href="https://azure.microsoft.com/en-us/updates/azure-kubernetes-service-kubernetes-1-9-end-of-life-notice/?WT.mc_id=devto-blog-yoterada"&gt;Exam: Azure Kubernetes Service: Kubernetes 1.9 end-of-life notice&lt;/a&gt;&lt;br&gt;
In order to update or create the new Kubernetes Cluster very quickly, the number of node size is very important.For example, if you created 100 nodes of cluster, it will take a long time than 30 nodes create.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Difficult to maintain&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
I would recommend you to create very simple structure and configuration (simple is the Best!!).&lt;br&gt;
If you created the simple structure and configuration, it is easy for you to create the same environment.However if you created the complex structure, sometimes it may be difficult to create the same environment even though you created the Infrastructure as Code.&lt;br&gt;
I recommend that you should be easy to create or destroy the environment at any time.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Finaly&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
I recommend you to create the Kubernetes Cluster for Mini Service level like 20-30 node. However, in fact, sizing depends on your system. For example, you need create a chunk of relevant microservices and deploy it to the the cluster.&lt;/p&gt;

</description>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Experience of Kubernetes Hackathon with Customers</title>
      <dc:creator>Yoshio Terada</dc:creator>
      <pubDate>Fri, 10 May 2019 09:27:25 +0000</pubDate>
      <link>https://dev.to/azure/experience-of-kubernetes-hackathon-with-customers-4oem</link>
      <guid>https://dev.to/azure/experience-of-kubernetes-hackathon-with-customers-4oem</guid>
      <description>&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;h2&gt;
  
  
  History :
&lt;/h2&gt;

&lt;p&gt;At first, I would like to explain why I had been opening the k8s Hackathon many times since last year. &lt;/p&gt;

&lt;p&gt;In fact, k8s is not only for Infrastructure engineer but also for Developer engineer. In order to use the k8s appropriately, both technical knowledge is needed.&lt;br&gt;&lt;br&gt;
For me, I took few month to understand the k8s of all. However it is too long for everyone and they would like to catch up it more smoothly.&lt;/p&gt;

&lt;p&gt;In the past, as an ex-Evangelist and now Developer Advocate, of course I had done many presentation about k8s. However I thought that it is very difficult for me to explain the important topic of k8s for only one hour in one presentation.&lt;br&gt;&lt;br&gt;
Because sometimes I need to explain 12 Factor App, CI/CD, Microservices depends on the audience level. &lt;/p&gt;

&lt;p&gt;And in tha past, I created so many Technical Hands on Lab(HoL) contents. Yes, the HoL is very useful for first contact. However if the user face the trouble, they can't solve the issue from the HoL contents. Thus, I thought that the attendee should consider more during the HoL or Hackathon.&lt;/p&gt;

&lt;p&gt;Since last year, I started the k8s Hackathon in Japan(Tokyo, Sapporo, actual customer) and Australia. During the Hackathon, I will gather the requirements of the attendee at first. And depends on the requirements, I will help and advise the attendee to achieve the requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Hackathon Event
&lt;/h2&gt;

&lt;p&gt;In general, every times the technical skill of the attendee is so difference. Sometimes members doesn't have an experience of Azure even though they had an experience of AWS. Some of the engineer is not developer. Some of the engineer is not familiar with the Infrastructure.&lt;/p&gt;

&lt;p&gt;In this situation, I will inform them since the basic concept of Container, Microservices, k8s and Azure at first.&lt;br&gt;&lt;br&gt;
For Community Event, it is very difficult to create production ready contents. Because almost of the community event is planning as only 2days. So almost of the attendee may only catch up how to use, troubleshoot and consider the architecture in the day.  &lt;/p&gt;

&lt;p&gt;For Customer Event, of course depends on the customer and their requirements, they will be able to do more things.&lt;br&gt;&lt;br&gt;
For Example, if they can prepare the one-week Hackathon and they would like to migrate their application to k8s, it is possible in the week.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31biwe6bflamnx5ylte8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31biwe6bflamnx5ylte8.jpg" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Date:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Community Event : 2 Day is needed (Saturday, Sunday AM:10:00-18:00)
&lt;/li&gt;
&lt;li&gt;Customer Event  : 3-5 Day is needed (Monday to Friday:AM 10:00-18:00)
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Activity
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.Presentation (Introduction) of Basic Concept (1.5 Hour)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The Change the World of the IT Industry&lt;/li&gt;
&lt;li&gt;Improve the Development Work Flow by using Value Stream Mapping&lt;/li&gt;
&lt;li&gt;Importance of Cloud Native Application&lt;/li&gt;
&lt;li&gt;12 Factor App&lt;/li&gt;
&lt;li&gt;Microservices&lt;/li&gt;
&lt;li&gt;Why the container and k8s is trend and important&lt;/li&gt;
&lt;li&gt;Suitable and Not Suitable application/system/architecture of k8s&lt;/li&gt;
&lt;li&gt;Basic of Container (Docker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, I will explain why Container and k8s is important now. And what kind of the situation the Container or k8s is useful. Also I inform them what kind of the situation you shouldn't use the Container and k8s. &lt;br&gt;
Because Container and k8s is not the Silver Bullet. If the user use them in the wrong spaces, they may distress their management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmhl30to87x5nahh06n3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmhl30to87x5nahh06n3.jpg" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.Hackathon (1.5 Days)
&lt;/h3&gt;

&lt;p&gt;This is not the  HoL but Hackathon. So I will gather the information of what kind of work they would like to do or solve in this two days.&lt;br&gt;&lt;br&gt;
After that I created the group and proceeded as Mob Programing Style.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyosdqpop46ropekir2jx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyosdqpop46ropekir2jx.jpg" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basic operation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Linux VM on Azure
&lt;/li&gt;
&lt;li&gt;Install docker client on Linux VM
&lt;/li&gt;
&lt;li&gt;Create Sample Application  (Java/PHP/Python/.Net Core)&lt;/li&gt;
&lt;li&gt;Install Azure Container Registry
&lt;/li&gt;
&lt;li&gt;Create Docker Image and push it to Registry
&lt;/li&gt;
&lt;li&gt;Install az command
&lt;/li&gt;
&lt;li&gt;Install AKS on Azure
&lt;/li&gt;
&lt;li&gt;Create Deployment YAML
&lt;/li&gt;
&lt;li&gt;Create Service YAML
&lt;/li&gt;
&lt;li&gt;Create Ingress YAML
&lt;/li&gt;
&lt;li&gt;Evaluate the Self-healing by Readiness/Liveness Probe
&lt;/li&gt;
&lt;li&gt;Evaluate the Rolling Upgrade
&lt;/li&gt;
&lt;li&gt;Create the Virtual Node
&lt;/li&gt;
&lt;li&gt;Create CI/CD environment by Azure DevOps
&lt;/li&gt;
&lt;li&gt;Create Monitoring&lt;/li&gt;
&lt;li&gt;Istio&lt;/li&gt;
&lt;li&gt;.... Depends on the Attendee ...&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Venue:
&lt;/h3&gt;

&lt;p&gt;By the way, Venue and Facility is very important to open the Hackathon. Every times, I'm opening the Hackathon by using Mob Programing Style. In order to do it, Big screen(monitor) is needed for every teams. Also we need high band wide network to connect to Azure.   &lt;/p&gt;

&lt;p&gt;Fortunately, Every Meeting room in Microsoft Office has big screen monitor, so it is easy too open the Hacakathon. However outside of the office, sometimes we need to take care of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result of Hackahon:
&lt;/h2&gt;

&lt;p&gt;According to the feedback from the attendee, almost of the attendee satisfied the k8s Hackathon. In fact, they could learn and operate the k8s for only two days even though they were beginners.&lt;br&gt;
And even though, they were not familiar with the Azure, they felt that the good parts of Azure like AKS, Azure DevOps, Virtual Node and Azure Dev Spaces.&lt;/p&gt;

&lt;p&gt;Refer to following Blogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  FeedBack &amp;amp; Blog Post from the Attendees
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Following contents is directly I engaged and it was wrote by attendee by Japanese language, if you refer to the following blog entry, please use the Translator like &lt;a href="https://www.bing.com/translator" rel="noopener noreferrer"&gt;Bing Translator&lt;/a&gt;  or &lt;a href="https://translate.google.com/" rel="noopener noreferrer"&gt;Google Translator&lt;/a&gt;?&lt;/p&gt;




&lt;p&gt;2018/05/15 &lt;a href="https://www.oisixradaichi.co.jp/en/" rel="noopener noreferrer"&gt;Oisix ra Daichi&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://customers.microsoft.com/ja-jp/story/oisix-manufacturing-azure-api-monitor-mysql-jp-japan" rel="noopener noreferrer"&gt;Microsoft Official Customer Story&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oisixradaichi.co.jp/wp/wp-content/uploads/2019/03/11d7d37d7306a49881a19f4062fa5876.pdf" rel="noopener noreferrer"&gt;Press Release : Oisix ra Daichi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://creators.oisix.co.jp/entry/2018/05/15/180000" rel="noopener noreferrer"&gt;Microsoft Hackfest Microservice Platform Built with Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.itmedia.co.jp/enterprise/articles/1903/18/news016.html" rel="noopener noreferrer"&gt;Online Media : Promoted the Use of Monolithic Services that Oisix has been operating for 19 years into Microservices, and why can Kubernetes be put into production operation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.slideshare.net/hiroakikobayashi1806/oisix" rel="noopener noreferrer"&gt;Presentation: Oisix's Microservices deliver Safe and Secure Food&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2018/7/7日 - 7/8 : &lt;a href="http://www.java-users.jp/?p=2979" rel="noopener noreferrer"&gt;Japan Java Users Group 2 day k8s Hack&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/presentation/d/1lQJIj-Ge8os6bUUiGbpF4MiaWkXd4Aqo6u1I5vTTafY/edit#slide=id.gc6f80d1ff_0_50" rel="noopener noreferrer"&gt;Team 1 Log5j : Presentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/presentation/d/1nlJXMBl7g8m9qZYl7NzLqiHA2TnZLyKh5v4ND_gA73U/edit#slide=id.p" rel="noopener noreferrer"&gt;Team 2 CI/CD with GitLab : Presentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.google.com/presentation/d/10dLs40lqd9djQwPj6yDaYzIIlBhPXK9u4lG7aS5k1WU/edit#slide=id.p" rel="noopener noreferrer"&gt;Team 3 Istio (Like Sailboat): Presentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://qiita.com/solaris1000/items/37742ec2731cf8730ded" rel="noopener noreferrer"&gt;Blog: An experience of Mob Programming with Hackathon&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2018/8/7-8/10: &lt;a href="https://www.pnop.co.jp/" rel="noopener noreferrer"&gt;Pnop : Partner Company (and MVPs)&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.azure.moe/2018/08/12/azure-kubernetes-service-aks-tips-1/" rel="noopener noreferrer"&gt;Azure Kubernetes Service (AKS) Tips 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.azure.moe/2018/08/15/azure-kubernetes-service-aks-tips-2-rbac/" rel="noopener noreferrer"&gt;Azure Kubernetes Service (AKS) Tips 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2018/11/17(土)～18(日) &lt;a href="https://javado.connpass.com/event/107627/" rel="noopener noreferrer"&gt;Sapporo JavaDo (Java Users Group for Sapporo)&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bitstar.jp/blog/2018/12/19/23659/" rel="noopener noreferrer"&gt;I tried a Hackahon of Kubernetes in Java Do Community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2019/01/21-1/25 &lt;a href="https://heartbeats.jp/" rel="noopener noreferrer"&gt;Customer: HeartBeat&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://kaz29.hatenablog.com/entry/2019/01/28/101016" rel="noopener noreferrer"&gt;Construction of Azure Kubernetes Service (AKS) and creation of CI / CD pipeline using Azure DevOps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://heartbeats.jp/hbblog/2019/02/ms-aks-azure-devops-workshop.html" rel="noopener noreferrer"&gt;I participated in the Microsoft Kubernetes (AKS) DevOps workshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://heartbeats.jp/hbblog/2019/04/azmon.html" rel="noopener noreferrer"&gt;Released  "azmon" the Monitoring Pluginfor for Azure Monitor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2019/02/23-/2/24 : &lt;a href="https://kanjava.connpass.com/event/118967/" rel="noopener noreferrer"&gt;Kubernetes Hackathon at KanJava(Java Community in West side of Japan Area)&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://qiita.com/manta35/items/2b7059e506ce83df8a11" rel="noopener noreferrer"&gt;"Azure" What is For Kubernetes? I went to hackathon, so let's go over and review&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2019/03/19 : &lt;a href="https://oi-study.connpass.com/event/122427/" rel="noopener noreferrer"&gt;OiStudy #1 Azure &amp;amp; AKS: Community Event&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2019/04/13-4/14 &lt;a href="https://jazug.connpass.com/event/123302/" rel="noopener noreferrer"&gt;KitaAzu: JAZUG Sapporo 22nd Study&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nagumo.co/azure/857" rel="noopener noreferrer"&gt;22nd of JAZUG Sapporo (kita azu)  ~ Azure Kubernetes Service (AKS) by Takayuki Fuwa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vnext-y-blog.azurewebsites.net/archives/6278" rel="noopener noreferrer"&gt;22nd of JAZUG Sapporo (kita azu)  ~ Azure Kubernetes Service (AKS) by Yasuaki Matsuda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://katsuyuzu.hatenablog.jp/entry/2019/04/15/003742" rel="noopener noreferrer"&gt;I have been studying Kubernetes for two days #JAZUG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spyke.hatenablog.com/entry/2019/04/15/234932" rel="noopener noreferrer"&gt;I     participated in "JAZUG Sapporo Branch (Kitaazu) The 22nd Study Meeting Azure Kubernetes Service (AKS) Hackathon"&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2019/04/2-4/4 &lt;a href="https://www.mercari.com/" rel="noopener noreferrer"&gt;Customer Mercari: Selling App&lt;/a&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tech.mercari.com/entry/2019/04/16/060000" rel="noopener noreferrer"&gt;Automation UI Test (Selenium Grid/Zalenium) of Mercari Web by using Azure Kubernetes Service (AKS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm very glad that there is a lot of AKS related Technical Contents outside of Microsoft. AKS usage and Japan community is growing up now !!&lt;/p&gt;

&lt;h3&gt;
  
  
  Others:
&lt;/h3&gt;

&lt;p&gt;I got many direct feedback both products and events from Slack Channel which is used during the Hackathon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwdl3nd193cib13tiins.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwdl3nd193cib13tiins.jpg" width="800" height="486"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zk7z8q0wmxmf0hdaovw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zk7z8q0wmxmf0hdaovw.jpg" width="800" height="486"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frca9451zrv6xzo83no78.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frca9451zrv6xzo83no78.jpg" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;If you would like to open the Hackathon with me, if you can accept one of following rule, depends on my schedule, I can engage with you. Even though it is outside of Japan, it is OK for me.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your company can open the Microsof Customer Story like Oisix&lt;/li&gt;
&lt;li&gt;You are considering to use the AKS for production like Oisix/HeartBeats&lt;/li&gt;
&lt;li&gt;Provide us the Products FeedBack to us during the Hackathon&lt;/li&gt;
&lt;li&gt;Some of engineer can write the blog about your experiences in Community Event&lt;/li&gt;
&lt;li&gt;For Community: You need to activate the Azure&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aks</category>
      <category>kubernetes</category>
      <category>hackathon</category>
      <category>azure</category>
    </item>
  </channel>
</rss>
