Docker on AWS – Part 4 – Simple Spring Boot app

In this post, I’ll use the knowledge I gained from earlier posts to deploy the Docker image for my Spring Boot “Hello World” app into AWS.

RELATED POSTS:

Why another “Hello World” Docker image?

The Docker image from the AWS Elastic Container Service (ECS) is far too simple to build on. It was essentially a Linux image that runs Apache web server, and hosts a web site that consists of a single text file containing the string “Hello, JTOUGH!”.

I’d like to get a basic Spring Boot app in a Docker image running on AWS. I have experience with Spring Boot and Java. Also, AWS provides a Java API library that I can use with my Spring Boot app to interact with AWS programmatically. Before I can do anything fun, I need to get the basics working.

In my post “Simple Spring Boot app with Docker“, I followed a tutorial from the nice people who provide the Spring framework. I took the code that I ended the tutorial with, and checked it in to Github. I’ll probably just export that code, make a copy, and use it as my starting point for a Spring Boot/Docker app that does something more than say “Hello World”. Before I do that, I’d like to find out if there are any tricks to getting the simple Spring Boot/Docker example running on AWS without any changes.

Getting the source code and building the app

I’ll start by exporting the source code from Github. I don’t want to clone the Git repository, because I’m planning to just build this app rather than make any changes that will need to be committed back to Git. I’ll use the “Download ZIP” option.

SBDA-screenshot-001

I unpack the contents of the ZIP into a temporary folder on my PC.

SBDA-screenshot-002

Next I’ll use PowerShell to build the app with the “mvn package” command.

SBDA-screenshot-003

Looks good.

Test running the app locally

Running without Docker

Now I’ll run the Spring Boot app locally without Docker, to confirm that the app itself is working correctly.

java -jar target/gs-spring-boot-docker-0.1.0.jar

SBDA-screenshot-004

SBDA-screenshot-005
Working as expected in a browser

NOTE: Remember to shut down the Spring Boot app before proceeding to the next step. You can press CTRL+C in PowerShell to send the terminate signal, or just close the PowerShell window.

Running with Docker

The “mvn build” command above built both the Spring Boot application and the Docker image, so now I’ll use a Docker command to run the image locally.

docker run --rm -p 8080:8080 -t jtough/gs-spring-boot-docker

SBDA-screenshot-006

Looks like a clean startup. Now I’ll open a browser again and confirm that I can connect.

SBDA-screenshot-007

Looks good. I don’t need to keep the app running locally in Docker, so I’ll issue the following commands to stop the Docker container.

docker ps
docker stop 

SBDA-screenshot-008

Docker will assigned random names to container instances by default. It assigned mine the name “gifted_darwin” this time. So my command to stop the container was:

docker stop gifted_darwin

Publishing and running the Docker image on AWS

I have my locally tested Docker image, and I’d now like to deploy it to the AWS Elastic Container Service (ECS). How do I do this?

Tagging the Docker image and pushing it to AWS

In my previous post, Docker on AWS – Part 1 – Creating the Docker Image, I learned how to use the AWS Command Line Interface (CLI) to create a new private Docker repository in my AWS account, and then push my Docker image to that repository.

Let’s start with a test AWS CLI command that lists all the repositories that currently exist in my AWS account. If this command doesn’t work, then the setup of AWS CLI on my workstation is incorrect.

aws ecr describe-repositories

REFERENCE

http://docs.aws.amazon.com/cli/latest/reference/ecr/index.html

SBDA-screenshot-009
Listing my AWS Docker repositories (personal details obscured)

I can see from the response that I currently have one repository in my AWS account. It is named “aws-hello-world”. I’m going to create a new repository for my Spring Boot application image.

aws ecr create-repository --repository-name spring-boot

SBDA-screenshot-010

AWS responds with the details of my new repository.

Now I need to “tag” my existing Docker image with the AWS repository name.

docker tag jtough/gs-spring-boot-docker .dkr.ecr.ca-central-1.amazonaws.com/spring-boot

My opinion of the “docker tag” command

REFERENCE: https://docs.docker.com/engine/reference/commandline/tag/

I personally find the “docker tag” command confusing. First off, it seems as if I’m just creating an alias for my existing image, but with a different target repository name. The “tag” isn’t specified in my command, so it defaults to “latest”. Perhaps it isn’t the “docker tag” command that bothers me, but rather the fact that Docker images don’t have names. Each image has a hexadecimal IMAGE ID, but no human-readable name. Is it standard practice for each image (and all its versions) to have its own repository? If so, then I suppose the repository name would describe the contents. Hopefully this will make more sense as I become more familiar with Docker.

The “docker tag” command also gives special treatment to images whose target repository is Docker Hub. If you don’t specify a private repository server (as I’m doing above), then it assumes you are using Docker Hub. I don’t like that.

Next, I need to push the tagged image to my AWS repository. This is a multi-step process, that goes something like this:

  1. Use the “aws ecr get-login” command to request temporary credentials for my private AWS Docker repository
  2. Use those temporary credentials on the command line (for me, in PowerShell)
  3. Execute the “docker push” command to push my image to AWS

So first, I’ll use the following command to request my temporary Docker credentials.

aws ecr get-login --no-include-email

SBDA-screenshot-011

The response is a “docker login” command for my private AWS repository. The password is really long, and is only valid for 12 hours. All I need to do is copy-and-paste the entire command and run it in PowerShell.

TIP: You may need to remove any linefeeds before you paste it back into PowerShell

SBDA-screenshot-012

I’m now authenticated to interact with my private AWS Docker repository. Now I need to issue the “docker push” command to upload my Docker image.

docker push .dkr.ecr.ca-central-1.amazonaws.com/spring-boot
SBDA-screenshot-014
“docker push” in progress
SBDA-screenshot-015
“docker push” completed

Now I’ll take a look inside my AWS Management Console.

SBDA-screenshot-016
List of private Docker repositories in my AWS account
SBDA-screenshot-017
My Docker image, inside my “spring-boot” repository on AWS

Creating an ECS Task Definition for my image

In a previous post, Docker on AWS – Part 1 – Creating the Docker Image, I blindly followed the instruction from an AWS tutorial to create an ECS task definition. In the tutorial, the task definition parameters were provided in JSON format, and the task was created by submitting the JSON as a text file to an AWS CLI command. This was the JSON from that tutorial:

{
 "family": "aws-hello-world",
 "containerDefinitions": [
 {
 "name": "aws-hello-world",
 "image": ".dkr.ecr.ca-central-1.amazonaws.com/aws-hello-world",
 "cpu": 10,
 "memory": 500,
 "portMappings": [
 {
 "containerPort": 80,
 "hostPort": 80
 }
 ],
 "entryPoint": [
 "/usr/sbin/apache2",
 "-D",
 "FOREGROUND"
 ],
 "essential": true
 }
 ]
}

This time I’m going to try and figure out how to create the task definition myself. Instead of using the JSON-formatted command, I’ll try using the AWS Management Console.

SBDA-screenshot-018
Let’s do this!!

SBDA-screenshot-019.jpg

I’ll name my task “spring-boot-task”. I’m leaving the default values for “Task Role” and “Network Mode”.

SBDA-screenshot-020

I going to leave the “Task size” options empty. I suspect that I’ll be able to specify container-level settings that will make these unnecessary.

SBDA-screenshot-021
Defining a container for the task

I click the “Add container” button, and a dialog with many configuration options appears.

SBDA-screenshot-022

These settings are fairly straightforward. Hovering the mouse over the “i” icon gives a clear description for most. I don’t know how much memory I should set for the “Hard limit” parameter, so I’ll use the same as I did for the Hello World image task: 500 MiB.

SBDA-screenshot-023

The task for my Hello World image had the “Essential” flag enabled, so I’ll also enable it here. The other image used 10 CPU units, but it was a dead-simple example. I’m going to bump that up to 20 CPU units for my Spring Boot image and see if that works.

I don’t think any of the other setting are necessary for my image. The entry point is already defined in my Dockerfile, so the image should have that default (I believe so anyway!).

I’m leaving all the remaining sections empty, and going straight for the “Add” button.

SBDA-screenshot-024

Now on the “Create a Task Definition” page, I’ll click the “Create” button.

SBDA-screenshot-025

I hope this works! I won’t know if my task definition is good until I create a cluster and have it run the task.

Creating an ECS Cluster for the Docker image

I’ll jump right in and click the “Create Cluster” button inside the “Clusters” section of the ECS console page.

SBDA-screenshot-026

SBDA-screenshot-027
Linux, please!

I’ll stick with my simple naming convention for the new cluster.

SBDA-screenshot-028

I want a Spot instance (because they are cheaper), and I’m willing to pay 2 cents an hour, and not a damn penny more! I’ll choose the smallest/cheapest general-purpose EC2 instance type for my container: “t2.micro”.

I’ll leave the default values for the other settings in this section, including the key pair. I’ll want to be able to SSH in eventually, but I can come back and create a key pair later when I’m ready to use that feature.

SBDA-screenshot-029

The Networking section can keep all the default values except for the Port Range setting. The Spring Boot app listens on port 8080, rather than the web page default port 80. Hopefully that won’t cause a problem!

SBDA-screenshot-030
The Spring Boot app listens on port 8080, not port 80

SBDA-screenshot-031

The last two options can keep their default values, so I just click the “Create” button. AWS will launch the EC2 instance for my new cluster immediately.

SBDA-screenshot-032
Cluster launch successful

SBDA-screenshot-033

My cluster is running active now, and its single EC2 instance is running. It isn’t doing anything yet, because I haven’t associated any tasks or services with the cluster. I’ll create a service now.

SBDA-screenshot-034

SBDA-screenshot-035

SBDA-screenshot-036

SBDA-screenshot-037

SBDA-screenshot-038

And a few seconds after I click “Create Service”…

SBDA-screenshot-039
Up and running!

Testing connectivity to the app

My ECS cluster is running, and the service for the Docker image is also running. Now I need to test that I’m actually able to connect to my app with a browser. In order to do that, I’ll need the IP address of the EC2 instance that is hosting the Docker container. I can get that from the “EC2 Instances” tab on the Cluster details page.

SBDA-screenshot-040
Finding the link for my cluster’s EC2 instance details

I’ll just click on the EC2 instance link…

SBDA-screenshot-041
Details for the EC2 instance that hosts my Docker container

The Public IP address is what I’ll need to do a connection test.

SBDA-screenshot-042

And it works!

Note that I’ve explicitly used port 8080 in the URL. I’ll definitely want to switch to port 80 when I build my next Spring Boot app.

 


 

Leave a Reply