Discovery service healthcheck fails. Service unhealthy

Hi everyone.
I am new here and also new to Docker

I am working on a Spring boot microservices project with Docker. I have deployed my docker-compose.yml to my Ubuntu VPS server. When I run my docker compose file on the VPS, the Discovery service (Eureka) health check fails.

Other microservices depends on the Discovery service (Eureka) to be healthy before they can run. Here is my discovery service health configuration in my docker-compose.yml file.

services:
  discovery:
    container_name: discovery-service
    build: ./discovery
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://vps-ip-address:8761/actuator/health" ]
      interval: 15s
      timeout: 5s
      retries: 6
      start_period: 30s
    ports:
      - "8761:8761"
    environment:
      PROFILE: test
    networks:
      - microservices-net

  ...other services

I need help in addressing this issue. Thanks


Please, format your post according to the following guide: How to format your forum posts
In short: please, use </> button to share codes, terminal outputs, error messages or anything that can contain special characters which would be interpreted by the MarkDown filter. Use the preview feature to make sure your text is formatted as you would expect it and check your post after you have sent it so you can still fix it.

Example code block:

```
echo "I am a code."
echo "An athletic one, and I wanna run."
```

After fixing your post, please send a new comment so people are notified about the fixed content.


Post content well-formated now. Find included a snippet of my docker-compose.yml file highlighting the discovery service health check config

Hi

If you jump in a shell inside your container, can you run the curl statement ? Is this working from the console ?

Your yml is showing your service is running on network microservices-net. So my first question will be : can you reach that url from that network ?

In container health checks you should not use the host IP. You can use a loopback IP (127.0.0.1) to see if that container works. Otherwise you can mark a containr unhealthy just because it is not accessible on an external IP while internal communication could still work. Do you actually need to access the Discovery service on the VPS IP?

Local firewalls like ufw or firewalld could block requests to the host IP when sent from a container. I think it happeneed to me once long time ago, so I don’t have a lot of experience with it and I don’t exactly remember it, but you should really separate your container healthchecks from any external factor. Host IP access could be tested by another service either running on the host or on a remote machine if that is where you want to access it from. The healthceck you define in a compose service should test how that specific container works, not depending on how port forward works or how firewall blocks requests on host IP. Otherwise it will be harder do find an issue when you don’t know where the actual problem is.

When I exec into the container (docker exec -it discovery-service /bin/sh), curl isn’t installed. After installing it, curl http://localhost:8761/actuator/health works.

But my discovery service is still unhealthy

Then execute it in the container interactively and check the return code of the curl command.

echo $?

0 and 1 should be used:

The command’s exit status indicates the health status of the container. The possible values are:

  • 0: success - the container is healthy and ready for use
  • 1: unhealthy - the container isn’t working correctly
  • 2: reserved - don’t use this exit code

I know it is the Dockerfile reference but the codes should be the same.

services:
  discovery:
    container_name: discovery-service
    build: ./discovery
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://127.0.0.1:8761/actuator/health" ]
      interval: 15s
      timeout: 5s
      retries: 6
      start_period: 90s
    ports:
      - "8761:8761"
    environment:
      PROFILE: test
    networks:
      - microservices-net

Still not working.
I ran health check log for discovery-service to see the reason why the service health check is always failing and below is what I got

$ sudo docker inspect --format='{{json .State.Health}}' discovery-service
{"Status":"unhealthy","FailingStreak":20,"Log":[{"Start":"2025-06-20T22:04:51.755963045Z","End":"2025-06-20T22:04:51.841926311Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:06.844269369Z","End":"2025-06-20T22:05:06.962293958Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:21.963429388Z","End":"2025-06-20T22:05:22.07001817Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:37.071322094Z","End":"2025-06-20T22:05:37.152606104Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:52.153877974Z","End":"2025-06-20T22:05:52.237502094Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"}]}

I have tried everything I could all to no aail. Can someone help me fix this problem pls?

Let me drop my files so I know if there’s anything wrong with my config

Discovery Service
application.test.yml(Test Environment)

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

application.yml

spring:
  cloud:
    config:
      enabled: false
  main:
    allow-circular-references: true
    allow-bean-definition-overriding: true
  application:
    name: discovery-service
  jpa:
    show-sql: true
    properties:
      hibernate:
        bytecode:
          use_agent: false
  profiles:
    active: test

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always
    restart:
      enabled: true
    info:
        enabled: true

Dockerfile (Discovery service)

FROM eclipse-temurin:21-jre-jammy

LABEL authors="Stanley Nyekpeye"

RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

WORKDIR /app/discovery

COPY target/discovery-0.0.2-SNAPSHOT.jar discovery.jar

HEALTHCHECK --interval=15s --timeout=5s --retries=10 --start-period=60s \
    CMD curl -f http://localhost:8761/actuator/health || exit 1

EXPOSE 8761

ENTRYPOINT ["java", "-jar", "discovery.jar", "--spring.profiles.active=${PROFILE}"]

docker-compose-test.yml file (Test Enviironment)

services:
  discovery:
    container_name: discovery-service
    build: ./discovery
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://127.0.0.1:8761/actuator/health" ]
      interval: 15s
      timeout: 5s
      retries: 6
      start_period: 90s
    ports:
      - "8761:8761"
    environment:
      PROFILE: test
    networks:
      - microservices-net

  auth:
    container_name: auth-service
    build: ./auth
    ports:
      - "8008:8008"
    environment:
      PROFILE: test
      AUTH_SERVICE_PORT: 8008
    depends_on:
      discovery:
        condition: service_healthy  # Wait for Eureka to be ready
    networks:
      - microservices-net

  gateway:
    container_name: gateway-service
    build: ./gateway
    ports:
      - "8222:8222"
    environment:
      PROFILE: test
      GATEWAY_PORT: 8222
    depends_on:
      discovery:
        condition: service_healthy  # Wait for Eureka to be ready
    networks:
      - microservices-net

  user:
    container_name: user-service
    build: ./users
    ports:
      - "8010:8010"
    environment:
      PROFILE: test
      USER_SERVICE_PORT: 8010
    depends_on:
      discovery:
        condition: service_healthy  # Wait for Eureka to be ready
    networks:
      - microservices-net

  merchant:
    container_name: merchant-service
    build: ./merchants
    ports:
      - "8090:8090"
    environment:
      PROFILE: test
      MERCHANT_SERVICE_PORT: 8090
    depends_on:
      discovery:
        condition: service_healthy  # Wait for Eureka to be ready
    networks:
      - microservices-net

  voucher:
    container_name: voucher-service
    build: ./vouchers
    ports:
      - "8050:8050"
    environment:
      PROFILE: test
      VOUCHER_SERVICE_PORT: 8050
    depends_on:
      discovery:
        condition: service_healthy  # Wait for Eureka to be ready
    networks:
      - microservices-net

  zipkin:
    container_name: zipkin
    image: openzipkin/zipkin
    ports:
      - "9411:9411"
    networks:
      - microservices-net

  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    container_name: zookeeper
    environment:
      ZOOKEEPER_SERVER_ID: 1
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - "22181:2181"
    networks:
      - microservices-net

  broker:
    image: confluentinc/cp-kafka:latest
    container_name: broker
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
    ports:
      - "9092:9092"
    networks:
      - microservices-net

  mail-dev:
    container_name: ms_mail_dev
    image: maildev/maildev
    ports:
      - "1080:1080"
      - "1025:1025"
    networks:
      - microservices-net

  smtp-server:
    container_name: smtp_server
    image: namshi/smtp
    environment:
      MAILNAME: server273.web-hosting.com
      SMTP_USER: noreply@*****.com:*******
    ports:
      - "25:25"
      - "465:465"
      - "587:587"
    networks:
      - microservices-net

networks:
  microservices-net:
    name: microservices-net
    driver: bridge

pom.xml (Discovery Service)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.afrikunet</groupId>
	<artifactId>discovery</artifactId>
	<version>0.0.2-SNAPSHOT</version>
	<name>discovery</name>
	<description>discovery</description>
	<properties>
		<java.version>17</java.version>
		<spring-cloud.version>2023.0.2</spring-cloud.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

On my Ubuntu VPS server environment

$ sudo docker compose -f docker-compose-test.yml up -d
[+] Running 13/13
 ✔ Network microservices-net    Created                                    0.1s
 ✔ Container ms_mail_dev        Started                                    1.8s
 ✔ Container zipkin             Started                                    1.6s
 ✘ Container discovery-service  Error                                    170.0s
 ✔ Container zookeeper          Started                                    1.5s
 ✔ Container ms_postgres        Started                                    1.3s
 ✔ Container smtp_server        Started                                    2.0s
 ✔ Container user-service       Created                                    0.3s
 ✔ Container voucher-service    Created                                    0.3s
 ✔ Container merchant-service   Created                                    0.3s
 ✔ Container auth-service       Created                                    0.3s
 ✔ Container gateway-service    Created                                    0.3s
 ✔ Container broker             Started                                    1.7s
dependency failed to start: container discovery-service is unhealthy

Discovery service Health Inspect

$ sudo docker inspect --format='{{json .State.Health}}' discovery-service
{"Status":"unhealthy","FailingStreak":20,"Log":[{"Start":"2025-06-20T22:04:51.755963045Z","End":"2025-06-20T22:04:51.841926311Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:06.844269369Z","End":"2025-06-20T22:05:06.962293958Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:21.963429388Z","End":"2025-06-20T22:05:22.07001817Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:37.071322094Z","End":"2025-06-20T22:05:37.152606104Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"},{"Start":"2025-06-20T22:05:52.153877974Z","End":"2025-06-20T22:05:52.237502094Z","ExitCode":-1,"Output":"OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"}]}

The health check command is executed inside the container. The error message clearly states that the health check is not able to execute the curl command, because it can not find curl in the path. This usually indicates that it’s not baked into the image.

You either need to bake curl into the image, use wget instead if it already exists in the image, or even better implement something specific in java that can only perform the health check and nothing else, package it as jar, and use it with java -jar in your health check test.

Thanks for the insight. I had to implement something specific in java that does not rely on thrid parties like curl or wget. Discovery service (eureka) is healthy now.

Did you accidentally marked your post as solution? A solution is is something that new readers can see at the top of the topic after the first post as the one that helps to solve the issue. I believe @meyay gave you the final and best answer.

Yes I accidentally marked my post as the solution