3

tl;dr One RestController answers properly, the other doesn't, if run inside a Docker container.

The service has two APIs alive

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
public class AliveController {
    @RequestMapping(value = "/alive", method = RequestMethod.GET)
    public ResponseEntity<?> alive() {
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

and callcount.

@CrossOrigin
@RestController
public class CallController {

    private static int callCount = 0;

    @RequestMapping(value = "/callcount", method = RequestMethod.GET)
    public ResponseEntity<?> callCount() {
        return new ResponseEntity<>(++callCount, HttpStatus.OK);
    }
}

They are both run through docker-compose.

version: '2'

services:
  service:
    image: my/service
    ports:
      - "4000:4000"

docker-machine ip returns 192.168.99.100.

alive returns an empty 200 response. As expected.

$ curl -i http://192.168.99.100:4000/alive
HTTP/1.1 200
Content-Length: 0
Date: Mon, 22 Aug 2016 17:33:58 GMT

callcount should return a 200 response and a number that increases every time the API is called. Sadly it does not.

$ curl -i http://192.168.99.100:4000/callcount
HTTP/1.1 404
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 22 Aug 2016 17:37:26 GMT

{"timestamp":1471887446871,"status":404,"error":"Not Found","message":"No message available","path":"/callcount"}

Running the service locally provides the expected result.

$ curl -i http://localhost:4000/callcount
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 22 Aug 2016 17:43:40 GMT

1

The maven-spotify plugin is used to create an image from the following Dockerfile.

FROM java:8

EXPOSE 4000

VOLUME /tmp
ADD service*.jar app.jar

# http://stackoverflow.com/a/33882286/1309035
# Without this, Java uses /dev/random to seed its SecureRandom class, which can cause Java code to block unexpectedly.
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"]

I am using the latest Docker and Docker-Compose versions (downloaded them 22. August 2016).

Solved! See updates section below. Will finalize question when final answer ist found. - Question: Why is callcount not accessible from outside the Docker container?

Further attempts:

  • @CrossOrigin(origins = "*", maxAge = 3600) - same result
  • Global CORS configurations from the spring docs.
  • Merging the two methods into the AliveController.
  • Deleted every container and image and docker built again from scratch.

Udates:

The callcount API is not registered by Spring. I added another test API to verify this which is also not accessible through curl. alive still works fine and shows up in the logs.

bash-3.2$ docker logs asmstack_service_1 | grep callcount
bash-3.2$ docker logs asmstack_service_1 | grep test
bash-3.2$ docker logs asmstack_service_1 | grep alive
2016-08-23 08:42:06.530  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/alive],methods=[GET]}" onto public org.springframework.http.ResponseEntity<?> de.bahr.asmstack.AliveController.alive()

I use JDK 1.8 locally (java.vm.vendor = Oracle Corporation).

$ java -version
java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

Differences between startup methods

The callcount is properly registered when running the app out of IntelliJ and with mvn spring-boot:run. It does not get registered if run with

java -Djava.security.egd=file:/dev/./urandom -jar my-service.jar or

java -jar my-service.jar. This should be the cause why it is not accessible from within the Docker container.

Any idea why this is the case? It worked like that in another project from late 2015.

michaelbahr
  • 4,837
  • 2
  • 39
  • 75
  • When Spring starts up the logs will include all request mappings that are being exposed. Do you see the mapping for the `/callcount` when running it in Docker? – Shawn Clark Aug 23 '16 at 01:18
  • I do assume your app works fine. The issue is most likely the image being created. I suggest you run a fresh `mvn clean package` to create a new image and check with `docker images` if it was really freshly created. In general I didn't made good experiences with the spotify maven plugin, so usually just put a Dockerfile and call docker build after the mvn run. – daniel.eichten Aug 23 '16 at 05:34
  • @daniel.eichten I deleted every image and container and rebuilt docker from scratch. The issue persists. – michaelbahr Aug 23 '16 at 08:47
  • How are you running the service locally where it works? Through Eclipse/IntelliJ or `mvn spring-boot:run`? There must be any difference causing the Controller not to be added or registered to your container. You can also try to `docker exec` a shell in your container and unzip the `jar` to double check that the class is in there. I also saw that you are using `java:8` image which is based on openjdk. Which JDK you are using locally? – daniel.eichten Aug 23 '16 at 09:41
  • @daniel.eichten there is indeed a difference between the IDE, `mvn` and `java`. Updated the question accordingly. – michaelbahr Aug 23 '16 at 11:18
  • Did you also checked the container if the class is in the jar file in the container image? – daniel.eichten Aug 23 '16 at 13:52
  • @daniel.eichten I did not check that, as I already moved all APIs into one class. Problem is fixed, thanks to you two! Maybe someone know why this is the case? – michaelbahr Aug 23 '16 at 16:36

1 Answers1

2

I was able to solve the problem with help from @daniel.eichten and @ShawnClark, but I don't understand why this fails/works. T

It was not a Docker problem, but with Spring.

As seen here (question might be unrelated), I changed the Spring-Application from

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

to

@EnableAutoConfiguration
@EnableWebMvc
@Configuration
@ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Now all APIs are accessible as expected, also when running inside a Docker container.

Community
  • 1
  • 1
michaelbahr
  • 4,837
  • 2
  • 39
  • 75