Reputation: 2518
I'm trying to automatize the process of deploying tomcat webapps' .war on docker containers. To this goal, I devleoped a sample spring boot application to use as a test. Since my final goal is to apply the process to old existing war applications, I configured the application to produce a war file instead of a jar with tomcat embedded.
The sample application is just a sample Spring MVC application with a /greeting?id=<id>
endpoint that just returns a page with a "Hello " message, where is a string read from a table on a mysql db. The application is deployed on a Docker container based on the base tomcat image, while the database is deployed on a separate mysql container.
When launching the two containers via a docker-compose
script, the deployment seems to have success: The two containers are running, the tomcat instance is active, no error message is visible in cotainer logs, and I can see the webapp deployed and marked as running in the tomcat manager interface at http://<IP>:8082/manager/html
. The problem is that at http://<IP>:8082/myapp-sample-webapp/greeting?id=<id>
I get a 404 error. I tested putting a test.html
static file inside the web app, and this is visible at http://<IP>:8082/myapp-sample-webapp/test.html
.
Note also that if I configure the application as a tomcat-embedded jar application (of course changing also Dockerfile configuration accordingly) I can access the /greeting?id=<id>
endpoint without problems.
A side problem is that I cannot see any application generated log (neither on the docker container's log with docker logs ...
, nor in the /usr/local/tomcat/logs/myapp-sample-webapp.log
log file that I configure for the app logging (see application.properties
below), and this is preventing me to check whether the problems are somehow related to failing the connection to the mysql database.
This is the pom.xml file for the application is the following:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.myapp</groupId>
<artifactId>myapp-sample-webapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>myapp-sample-webapp</name>
<description>Project created for testing Docker packaging of a .war web application</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<docker.image.prefix>myapp-h2020</docker.image.prefix>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>${main.class}</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.2.3</version>
<configuration>
<imageName>${docker.image.prefix}/${project.artifactId}:${project.version}</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.war</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
This is the main controller class:
@Controller
public class GreetingController {
@Autowired
private RecordRepository repository;
@RequestMapping("/greeting")
public String greeting(@RequestParam(value="id", required=true ) Integer id, Model model) {
Record record = repository.findById(id);
String name = ( record == null ? "World" : record.getName() );
model.addAttribute("name", name);
return "greeting" ;
}
}
This is the main application (the commandline runner was written when initially testing the application in tomcat embedded mode):
edit: I updated the class as suggested by Alex's comment
@SpringBootApplication
public class MyAppSampleWebappApplication extends SpringBootServletInitializer {
private static final Logger log = LoggerFactory.getLogger(MyAppSampleWebappApplication.class);
// JAR
public static void main(String[] args) {
System.out.println("Starting MyAppSampleWebappApplication (JAR)...");
log.debug("Starting MyAppSampleWebappApplication (JAR)...");
SpringApplication.run(MyAppSampleWebappApplication.class, args);
}
//WAR
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.out.println("Starting MyAppSampleWebappApplication (WAR)...");
log.debug("Starting MyAppSampleWebappApplication (WAR)...");
return application.sources(MyAppSampleWebappApplication.class);
}
}
This is the application.properties for my file:
# datasource
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.driverClassName=com.mysql.jdbc.Driver
# for the moment I hardcoded references to mysql database, to replace with info from
# environment variable on "real" version
spring.datasource.url=jdbc:mysql://<IP OF HOST MACHINE>:3306/myapp-demo
spring.datasource.username=myapp
spring.datasource.password=myapp
spring.jpa.hibernate.ddl-auto=update
spring.data.jpa.repositories.enabled=true
spring.jpa.show-sql=true
logging.level.=DEBUG
logging.file=/usr/local/tomcat/logs/myapp-sample-webapp.log
This is the Dockerfile used through mvn build:docker
to generate the image for my application:
FROM tomcat
ADD tomcat-users.xml /usr/local/tomcat/conf
ADD myapp-sample-webapp.war /usr/local/tomcat/webapps/
CMD ["catalina.sh", "run"]
And finally, the docker-compose
file launching the two containers:
# container for an external mysql service
sample-mysql:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: p4SSW0rd
MYSQL_DATABASE: myapp-demo
MYSQL_USER: myapp
MYSQL_PASSWORD: myapp
ports:
- 3306:3306
# myapp-sample-webapp web application container:
myapp-sample-webapp:
image: myapp-h2020/myapp-sample-webapp:0.0.1-SNAPSHOT
ports:
- 8082:8080
Upvotes: 2
Views: 7242
Reputation: 2518
I think I've found the solution:
In my Dockerfile, I built my application's image on the tomcat
base image ( "FROM tomcat
" )
I found out that this image is based on JRE 7, while in my pom.xml, I had version 1.8 as Java version (<java.version>1.8</java.version>
)
By replacing the first line of the Dockerfile with a more specific version "FROM tomcat:7-jre8
", I can now see the page generated by my controller.
Upvotes: 4
Reputation: 306
I'm not 100% sure without looking into log file.
How your MVC's view layer is configured? I guess that Spring cannot find view's representation for "greeting". Do you have any JSP, Velocity, etc template?
Alternatively try to tamper with @ResponseBody on the method.
Upvotes: -2