In this post I describe how to deploy a simple dockerized Spring Boot service to AWS. The example service provides a RESTful API to manage schools and leverages mongodb for storage.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Document(collection = "schools")
class School {
@Id
private String id;
private final String name;
private final String city;
@JsonCreator
public School(@JsonProperty("name") String name, @JsonProperty("city") String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
}
@RepositoryRestResource(collectionResourceRel = "schools", path = "/schools")
interface SchoolRepository extends MongoRepository<School, String> {
List<School> findByCityIgnoreCase(@Param("city") String city);
}
The following Dockerfile
is used to create the image:
FROM java:8
MAINTAINER [email protected]
VOLUME /tmp
ADD spring-boot-docker-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
Using Docker Compose and the following docker-compose.yml
configuration you can easily test the application.
version: '2'
services:
mongodb:
container_name: schools-datastore
image: mongo:3.2
command: mongod --smallfiles
web:
container_name: schools-service
build: build/libs
image: school-service-image
depends_on: # schools-datastore will be started before the schools-service
- mongodb
ports:
- "8080:8080"
links:
- mongodb
environment:
SPRING_DATA_MONGODB_URI: mongodb://mongodb/test
by running
$ docker-compose up
This command will create and start two containers one for mongodb and one for the school service.
$ docker ps -a
CONTAINER ID IMAGE COMMAND PORTS NAMES
f49bdf199461 school-service-image "java -Djava.security" 0.0.0.0:8080->8080/tcp schools-service
573f330dc378 mongo:3.2 "/entrypoint.sh mongo" 27017/tcp schools-datastore
Let’s test it. Note, your docker host might have a different IP, check it with echo $DOCKER_HOST
command.
$ echo '{"name":"St. Bonifatiuscollege ", "city":"Utrecht"}' | http post http://192.168.99.100:8080/schools
HTTP/1.1 201 Created
Content-Type: application/json;charset=UTF-8
Date: Sat, 12 Mar 2016 12:09:20 GMT
Location: http://192.168.99.100:8080/schools/56e406f0e4b0e760889f4559
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application
{
"_links": {
"school": {
"href": "http://192.168.99.100:8080/schools/56e406f0e4b0e760889f4559"
},
"self": {
"href": "http://192.168.99.100:8080/schools/56e406f0e4b0e760889f4559"
}
},
"city": "Utrecht",
"name": "St. Bonifatiuscollege "
}
I am using httpie which is more user friendly curl
and comes with syntax highlighting.
And searching:
$ http get http://192.168.99.100:8080/schools/search/findByCityIgnoreCase\?city\=utrecht
HTTP/1.1 200 OK
Content-Type: application/hal+json;charset=UTF-8
Date: Sat, 12 Mar 2016 12:17:35 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application
{
"_embedded": {
"schools": [
{
"_links": {
"school": {
"href": "http://192.168.99.100:8080/schools/56e406f0e4b0e760889f4559"
},
"self": {
"href": "http://192.168.99.100:8080/schools/56e406f0e4b0e760889f4559"
}
},
"city": "Utrecht",
"name": "St. Bonifatiuscollege "
}
]
},
"_links": {
"self": {
"href": "http://192.168.99.100:8080/schools/search/findByCityIgnoreCase?city=utrecht"
}
}
}
Now let’s deploy this simple service to AWS.
First I need to push the image to a registry. For this example I am using DockerHub but AWS ECR would have been also a good choice.
$ cd spring-boot-docker
$ ./gradlew clean build
$ docker build -t altfatterz/spring-boot-docker-demo:0.0.1 build/libs
$ docker push altfatterz/spring-boot-docker-demo:0.0.1
I start a t2.micro
instance of Amazon Linux AMI
image with a security group allowing incomming SSH and HTTP requests from any source (0.0.0.0/0).
After successfully connecting to the instance I install Docker on it.
$ sudo yum update -y
$ sudo yum install -y docker
$ sudo service docker start
For convenience I add the ec2-user
to the docker
group in order to execute Docker commands without sudo
.
$ sudo usermod -a -G docker ec2-user
$ exit
I need to logout and login again in order for the settings to take effect. With docker info
I verify that the information about the Docker installation is returned successfully without using sudo
.
Now I am ready to start my altfatterz/spring-boot-docker-demo:0.0.1
image.
$ docker run -d -p 80:8080 \
-e SPRING_DATA_MONGODB_URI=mongodb://test:[email protected]:19478/zoltan \
altfatterz/spring-boot-docker-demo:0.0.1 --name schools-service
I link the 8080 port on the Docker container to the 80 port on the EC2 instance with the -p
option.
Using the -e
option I create an environment variable connecting a mongodb service provided by mLab. mLab lets me to create a free sandbox mongodb service up to 500 MB which is great for prototyping.
After making sure the docker container starts successfully by checking the logs via docker logs -f <container-id>
I can finally test it:
$ curl http://localhost // from the EC2 instance
$ http get http://<ec2-instance-public-ip> // from my host
I have now a running Docker container on AWS using my example image. The problem is though that it is really a manual process and does not scale well if I need to deploy many containers, routing the traffic to the containers (load balancing), making sure the containers are running (monitoring). I need more automation. In another blog post I will describe how you can deploy this simple service using AWS ECS
The example service can be found on my github account.