Tutorial: Connect to a managed Eureka Server for Spring in Azure Container Apps

Eureka Server for Spring is a service registry that allows microservices to register themselves and discover other services. Eureka Server for Spring is available as an Azure Container Apps component. You can bind your container app to Eureka Server for Spring for automatic registration with the Eureka server.

In this tutorial, you learn how to:

  • Create a Eureka Server for Spring Java component.
  • Bind your container app to the Eureka Server for Spring Java component.

Important

This tutorial uses services that can affect your Azure bill. If you decide to follow along, make sure that you delete the resources featured in this article to avoid unexpected billing.

Prerequisites

Considerations

When you run Eureka Server for Spring in Container Apps, be aware of the following details:

Item Explanation
Scope The Eureka Server for Spring component runs in the same environment as the connected container app.
Scaling The Eureka Server for Spring conponent can't scale. The scaling properties minReplicas and maxReplicas are both set to 1. To achieve high availability, see Create a highly available Eureka Service in Container Apps.
Resources The container resource allocation for Eureka Server for Spring is fixed. The number of the CPU cores is 0.5, and the memory size is 1 Gi.
Pricing The Eureka Server for Spring billing falls under consumption-based pricing. Resources consumed by managed Java components are billed at the active/idle rates. You can delete components that are no longer in use to stop billing.
Binding Container apps connect to a Eureka Server for Spring component via a binding. The bindings inject configurations into container app environment variables. After a binding is established, the container app can read the configuration values from environment variables and connect to the Eureka Server for Spring component.

Setup

Before you begin to work with the Eureka Server for Spring component, you first need to create the required resources.

Run the following commands to create your resource group in a container app environment.

  1. Create variables to support your application configuration. These values are provided for you for the purposes of this lesson.

    export LOCATION=eastus
    export RESOURCE_GROUP=my-services-resource-group
    export ENVIRONMENT=my-environment
    export EUREKA_COMPONENT_NAME=eureka
    export APP_NAME=my-eureka-client
    export IMAGE="mcr.microsoft.com/javacomponents/samples/sample-service-eureka-client:latest"
    
    Variable Description
    LOCATION The Azure region location where you create your container app and Java component.
    ENVIRONMENT The container app environment name for your demo application.
    RESOURCE_GROUP The Azure resource group name for your demo application.
    EUREKA_COMPONENT_NAME The name of the Java component created for your container app. In this case, you create a Eureka Server for Spring Java component.
    IMAGE The container image used in your container app.
  2. Sign in to Azure with the Azure CLI.

    az login
    
  3. Create a resource group.

    az group create --name $RESOURCE_GROUP --location $LOCATION
    
  4. Create your container app environment.

    az containerapp env create \
      --name $ENVIRONMENT \
      --resource-group $RESOURCE_GROUP \
      --location $LOCATION
    

Create the Eureka Server for Spring Java component

Now that you have an existing environment, you can create your container app and bind it to a Java component instance of Eureka Server for Spring.

  1. Create the Eureka Server for Spring Java component.

    az containerapp env java-component eureka-server-for-spring create \
        --environment $ENVIRONMENT \
        --resource-group $RESOURCE_GROUP \
        --name $EUREKA_COMPONENT_NAME
    
  2. Optional: Update the Eureka Server for Spring Java component configuration.

    az containerapp env java-component eureka-server-for-spring update \
        --environment $ENVIRONMENT \
        --resource-group $RESOURCE_GROUP \
        --name $EUREKA_COMPONENT_NAME
        --configuration eureka.server.renewal-percent-threshold=0.85 eureka.server.eviction-interval-timer-in-ms=10000
    

Bind your container app to the Eureka Server for Spring Java component

  1. Create the container app and bind it to the Eureka Server for Spring component.

    az containerapp create \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --environment $ENVIRONMENT \
        --image $IMAGE \
        --min-replicas 1 \
        --max-replicas 1 \
        --ingress external \
        --target-port 8080 \
        --bind $EUREKA_COMPONENT_NAME \
        --query properties.configuration.ingress.fqdn
    
  2. Copy the URL of your app to a text editor so that you can use it in an upcoming step.

Return to the container app in the portal. Copy the URL of your app to a text editor so that you can use it in an upcoming step.

Go to the /allRegistrationStatus route to view all applications that are registered with the Eureka Server for Spring component.

The binding injects several configurations into the application as environment variables, primarily the eureka.client.service-url.defaultZone property. This property indicates the internal endpoint of the Eureka Server Java component.

The binding also injects the following properties:

"eureka.client.register-with-eureka":    "true"
"eureka.client.fetch-registry":          "true"
"eureka.instance.prefer-ip-address":     "true"

The eureka.client.register-with-eureka property is set to true to enforce registration with the Eureka server. This registration overwrites the local setting in application.properties, from the configuration server and so on. If you want to set it to false, you can overwrite it by setting an environment variable in your container app.

The eureka.instance.prefer-ip-address property is set to true because of the specific domain name system resolution rule in the container app environment. Don't modify this value so that you don't break the binding.

Optional: Unbind your container app from the Eureka Server for Spring Java component

To remove a binding from a container app, use the --unbind option.

az containerapp update \
    --name $APP_NAME \
    --unbind $JAVA_COMPONENT_NAME \
    --resource-group $RESOURCE_GROUP

View the application through a dashboard

Important

To view the dashboard, you need to have at least the Microsoft.App/managedEnvironments/write role assigned to your account on the managed environment resource. You can explicitly assign the Owner or Contributor role on the resource. You can also follow the steps to create a custom role definition and assign it to your account.

  1. Create a custom role definition.

    az role definition create --role-definition '{
        "Name": "<YOUR_ROLE_NAME>",
        "IsCustom": true,
        "Description": "Can access managed Java Component dashboards in managed environments",
        "Actions": [
            "Microsoft.App/managedEnvironments/write"
        ],
        "AssignableScopes": ["/subscriptions/<SUBSCRIPTION_ID>"]
    }'
    

    Make sure to replace the <SUBSCRIPTION_ID> placeholder in the AssignableScopes value with your subscription ID.

  2. Assign the custom role to your account on a managed environment resource.

    Get the resource ID of the managed environment:

    export ENVIRONMENT_ID=$(az containerapp env show \
        --name $ENVIRONMENT --resource-group $RESOURCE_GROUP \
        --query id \
        --output tsv)
    
  3. Assign the role to your account.

    Before you run this command, replace the placeholders - indicated by the <> brackets - with your user or service principal ID and your role name.

    az role assignment create \
        --assignee <USER_OR_SERVICE_PRINCIPAL_ID> \
        --role "<ROLE_NAME>" \
        --scope $ENVIRONMENT_ID
    

    Note

    The <USER_OR_SERVICE_PRINCIPAL_ID> value usually should be the identity that you use to access the Azure portal. The <ROLE_NAME> value is the name that you assigned in step 1.

  4. Get the URL of the Eureka Server for Spring dashboard.

    az containerapp env java-component eureka-server-for-spring show \
        --environment $ENVIRONMENT \
        --resource-group $RESOURCE_GROUP \
        --name $EUREKA_COMPONENT_NAME \
        --query properties.ingress.fqdn \
        --output tsv
    

    This command returns the URL that you can use to access the Eureka Server for Spring dashboard. With the dashboard, you can also see your container app, as shown in the following screenshot.

    Screenshot that shows the Eureka Server for Spring dashboard.

Optional: Integrate the Eureka Server for Spring and Admin for Spring Java components

If you want to integrate the Eureka Server for Spring and the Admin for Spring Java components, see Integrate the managed Admin for Spring with Eureka Server for Spring.

Clean up resources

The resources created in this tutorial have an effect on your Azure bill. If you aren't going to use these services long term, run the following command to remove everything you created in this tutorial.

az group delete --resource-group $RESOURCE_GROUP

Allowed configuration list for your Eureka Server for Spring

The following sections describe the supported configurations. For more information, see Spring Cloud Eureka Server.

Note

Please submit support tickets for new feature requests.

Configuration options

The az containerapp update command uses the --configuration parameter to control how the Eureka Server for Spring is configured. You can use multiple parameters at once as long as they're separated by a space. For more information, see Spring Cloud Eureka Server.

The following configuration settings are available on the eureka.server configuration property:

Name Description Default value
eureka.server.enable-self-preservation When enabled, the server keeps track of the number of renewals it should receive from the server. Any time the number of renewals drops below the threshold percentage as defined by eureka.server.renewal-percent-threshold. The default value is set to true in the original Eureka server, but in the Eureka Server Java component, the default value is set to false. See Limitations of Eureka Server for Spring Java component. false
eureka.server.renewal-percent-threshold The minimum percentage of renewals that is expected from the clients in the period specified by eureka.server.renewal-threshold-update-interval-ms. If the renewals drop below the threshold, the expirations are disabled if eureka.server.enable-self-preservation is enabled. 0.85
eureka.server.renewal-threshold-update-interval-ms The interval with which the threshold - as specified in eureka.server.renewal-percent-threshold - needs to be updated. 0
eureka.server.expected-client-renewal-interval-seconds The interval with which clients are expected to send their heartbeats. Defaults to 30 seconds. If clients send heartbeats with different frequency, say, every 15 seconds, then this parameter should be tuned accordingly, otherwise, self-preservation won't work as expected. 30
eureka.server.response-cache-auto-expiration-in-seconds Gets the time for which the registry payload should be kept in the cache if it is not invalidated by change events. 180
eureka.server.response-cache-update-interval-ms Gets the time interval with which the payload cache of the client should be updated. 0
eureka.server.use-read-only-response-cache The com.netflix.eureka.registry.ResponseCache currently uses a two level caching strategy to responses. A readWrite cache with an expiration policy, and a readonly cache that caches without expiry. true
eureka.server.disable-delta Checks to see if the delta information can be served to client or not. false
eureka.server.retention-time-in-m-s-in-delta-queue Get the time for which the delta information should be cached for the clients to retrieve the value without missing it. 0
eureka.server.delta-retention-timer-interval-in-ms Get the time interval with which the clean up task should wake up and check for expired delta information. 0
eureka.server.eviction-interval-timer-in-ms Get the time interval with which the task that expires instances should wake up and run. 60000
eureka.server.sync-when-timestamp-differs Checks whether to synchronize instances when timestamp differs. true
eureka.server.rate-limiter-enabled Indicates whether the rate limiter should be enabled or disabled. false
eureka.server.rate-limiter-burst-size Rate limiter, token bucket algorithm property. 10
eureka.server.rate-limiter-registry-fetch-average-rate Rate limiter, token bucket algorithm property. Specifies the average enforced request rate. 500
eureka.server.rate-limiter-privileged-clients A list of certified clients. This is in addition to standard eureka Java clients. N/A
eureka.server.rate-limiter-throttle-standard-clients Indicate if rate limit standard clients. If set to false, only nonstandard clients are rate limited. false
eureka.server.rate-limiter-full-fetch-average-rate Rate limiter, token bucket algorithm property. Specifies the average enforced request rate. 100

Common configurations

  • Logging related configurations:
    • logging.level.*
    • logging.group.*
    • Any other configurations under the logging.* namespace should be forbidden - for example, writing log files by using logging.file should be forbidden.

Call between applications

This example shows you how to write Java code to call between applications registered with the Eureka Server for Spring component. When container apps are bound with Eureka, they communicate with each other through the Eureka server.

The example creates two applications, a caller and a callee. Both applications communicate among each other using the Eureka Server for Spring component. The callee application exposes an endpoint that is called by the caller application.

  1. Create the callee application. Enable the Eureka client in your Spring Boot application by adding the @EnableDiscoveryClient annotation to your main class.

    @SpringBootApplication
    @EnableDiscoveryClient
    public class CalleeApplication {
      public static void main(String[] args) {
        SpringApplication.run(CalleeApplication.class, args);
      }
    }
    
  2. Create an endpoint in the callee application that is called by the caller application.

    @RestController
    public class CalleeController {
    
        @GetMapping("/call")
        public String calledByCaller() {
            return "Hello from Application callee!";
        }
    }
    
  3. Set the callee application's name in the application configuration file - for example, in application.yml.

    spring.application.name=callee
    
  4. Create the caller application.

    Add the @EnableDiscoveryClient annotation to enable Eureka client functionality. Also, create a WebClient.Builder bean with the @LoadBalanced annotation to perform load-balanced calls to other services.

    @SpringBootApplication
    @EnableDiscoveryClient
    public class CallerApplication {
      public static void main(String[] args) {
        SpringApplication.run(CallerApplication.class, args);
      }
    
      @Bean
      @LoadBalanced
      public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
      }
    }
    
  5. Create a controller in the caller application that uses the WebClient.Builder to call the callee application using its application name, callee.

    @RestController
    public class CallerController {
        @Autowired
        private WebClient.Builder webClientBuilder;
    
        @GetMapping("/call-callee")
        public Mono<String> callCallee() {
            return webClientBuilder.build()
                .get()
                .uri("http://callee/call")
                .retrieve()
                .bodyToMono(String.class);
        }
    }
    

Now you have a caller and callee application that communicate with each other using Eureka Server for Spring Java components. Make sure both applications are running and bind with the Eureka server before testing the /call-callee endpoint in the caller application.

Limitations

The Eureka Server Java component comes with a default configuration, eureka.server.enable-self-preservation, set to false. This default configuration helps avoid times when instances aren't deleted after self-preservation is enabled. If instances are deleted too early, some requests might be directed to nonexistent instances. If you want to change this setting to true, you can overwrite it by setting your own configurations in the Java component.

Next steps

Integrate the managed Admin for Spring with Eureka Server for Spring