Monday, 14 January 2019

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Deploy our docker container on Amazon EC2 Elastic Container Service

In previous post, we discuss about how to run SpringBoot API as a Docker.

I am going to use Amazons fargate for Amazon EC2 Elastic Container Service. 

"AWS Fargate is a compute engine for Amazon ECS that allows you to run containers without having to manage servers or clusters. With AWS Fargate, you no longer have to provision, configure, and scale clusters of virtual machines to run containers. This removes the need to choose server types, decide when to scale your clusters, or optimize cluster packing. AWS Fargate removes the need for you to interact with or think about servers or clusters. Fargate lets you focus on designing and building your applications instead of managing the infrastructure that runs them"

For more information you can go to https://aws.amazon.com/fargate/

Step 1: Log into Amazon and go to the console. Select Elastic container service and click let's get started.

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Step 2: Click the Configure button under Container Configuration and specify the basics.

  • container name: EmployeesAPIContainer
  • Image: niteshkumar/employeesapi-docker:1.0.1
How to Deploy your docker container on Amazon EC2 Elastic Container Service
          keep the Advanced features on default and click Update.


Step 3: Service configuration

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Step 4: Cluster configuration

Just accept the default values and click next

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Step 5: Review

Check to see if all the configuration are correct and click create.

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Step 6: Click view service

In the logs we can see container was successfully started.

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Step 7: Check Public IP

Click Tasks and then on the task id, we can get public IP in the overview. By using this IP we can check if our API is available or not.

Step 8: Use Postman or RestClient to connect API's using these public IP address.


References: 


Related post:

Implementation of swagger in SpringBoot API

How to run SpringBoot API as a Docker container




How to run SpringBoot API as a Docker container

How to run SpringBoot API as a Docker container

We have created SpringBoot API in our previous post and you can download.

Docker is a container management service that eases building and deployment.The keywords of Docker are develop, ship and run anywhere. The whole idea of Docker is for developers to easily develop applications, ship them into containers which can then be deployed anywhere.

The official site for Docker is https://www.docker.com/ The site has all information and documentation about the Docker software. It also has the download links for various operating systems.

Prerequisite:

We will need these files to run SpringBoot API as a Docker container.
  • pom.xml
  • Dockerfile
How to run SpringBoot API as a Docker container
pom.xml: We are going to use a Maven plugin from Spotify to make a docker container from the springboot app. We can see the plugin in the pom.xml:

<!-- dockerfile plugin -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.3.6</version>
                <configuration>
                    <repository>${docker.image.prefix}/${project.artifactId}</repository>
                    <tag>${project.version}</tag>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
            </plugin>
Dockerfile: Next we need a Dockerfile which tells how the image should be build up.

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
This just says to use openjdk version 8 and to add the springboot jar.

Step 1: Go to where project is placed using CMD and run 


mvn package

How to run SpringBoot API as a Docker container

Step 2: Now run

mvn dockerfile:build
to make a docker image which we can run. As you can see we have successfully build the niteshkumar/employeesapi-docker:1.0.0 image
How to run SpringBoot API as a Docker container

Step 3: If we want to be able to push the image to DockerHub where we can store it in a repository, we first have to login.
docker login
How to run SpringBoot API as a Docker container

Step 4: Now, we should be able to push the image.
mvn dockerfile:push
How to run SpringBoot API as a Docker container

After success you can go to DockerHub and you can see your image in Repositories.

Now, we can pull this image from DockerHub and run it. To achieve this we will execute below commands.

docker images
docker rmi -f XXXXXXXXXXX
docker pull niteshkumar/employeesapi-docker:1.0.1
docker run -p 8080:8080 -t niteshkumar/employeesapi-docker:1.0.1

you should be able to connect API with Postman or RestClient.


Next Post: How to Deploy your docker container on Amazon EC2 Elastic Container Service



Related Post: 

How to build simple microservice using Spring Boot

Implementation of swagger in SpringBoot API

How to Deploy your docker container on Amazon EC2 Elastic Container Service

Implementation of swagger in SpringBoot API

Implementation of swagger in SpringBoot API

We have created SpringBoot API in our previous post and you can download.

We could have lot of API's and if people don't know how to use it than it rather useless.There are a few tools which can help us document our API. We can use Swagger, Apiary or RAML. For spring-boot, there is a set of libraries which can help document our API in a very easy manner using Swagger.

Swagger: 

Swagger is an open-source software framework backed by a large ecosystem of tools that helps developers design, build, document, and consume RESTful Web services. While most users identify Swagger by the Swagger UI tool, the Swagger toolset includes support for automated documentation, code generation, and test-case generation.

For more information you can go to their official website.

In previous post we exposed 4 REST endpoints which is:
  • get all employees names: GET /api/employee
  • get a specific employee: GET /api/employee/{id}
  • add an employee: POST /api/employee
  • delete an employee: DELETE /api/employee/{id}
Now, we will do swagger documentation for these API's.

We have already these files:
  • pom.xml
  • EmployeesApplication.java
  • Employee.java
  • EmployeeRepository.java
  • EmployeesDataController.java
  • application.properties
  • data.sql
In addition, we will add these files:
  • BasicAuthenticationPoint.java
  • SecurityConfiguration.java
  • SwaggerConfig.java

Implementation of swagger in SpringBoot API

pom.xml: we have to do is add 2 dependencies into our POM to enable Swagger2.

<!--springfox dependency -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
SwaggerConfig.java: we will create a bean which creates a Docket. This is the starting point of the configuration for your Swagger documentation.

package com.engineeernitesh.employeesapi.swagger;

import java.util.ArrayList;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static springfox.documentation.builders.PathSelectors.regex;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.VendorExtension;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket employeeApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(regex("/api/employee.*"))
                .build()
                .apiInfo(metaData());
    }

    private ApiInfo metaData() {
        ApiInfo apiInfo = new ApiInfo(
                "Employee API",
                "This is test",
                "1.0",
                "Terms of service",
                new Contact("", "", "nitesh04singh@gmail.com"),
                "Apache License Version 2.0",
                "https://www.apache.org/licenses/LICENSE-2.0", new ArrayList<VendorExtension>()
        );
        return apiInfo;
    }


}

@EnableSwagger2 annotation is used to enable the Swagger2 for our Spring Boot application.

By setting the basePackage to the right location, it will look for RestController classes and generate documentation items based on annotations.

Using ApiInfo we can add some basic information of the API.

EmployeesDataController: We can add @ApiOperation annotation to set a description of the operation and what kind of response you expect.


@ApiOperation(value = "View a list of employees", response = Iterable.class)
    List<Employee> getEmployees() {}
Now, start the application and go to http://localhost:8080/swagger-ui.html. You will be able to see all API's definition and now you can use these API's.

Implementation of swagger in SpringBoot API


How to build simple microservice using Spring Boot

How to run SpringBoot API as a Docker container

How to build simple microservice using Spring Boot

How to build simple microservice using Spring Boot

Nowadays many organizations prefer building their enterprise applications using MicroService architecture. In java community, SpringBoot is the most widely used framework for building MicroServices.

Why MicroServices?

Monolithic applications are large enterprise applications which builds in modularised fashion but finally deploy them together as a single deployment unit(EAR or WAR). These kind of applications have some issues like:
  • Large codebases become mess over the time
  • Multiple teams working on single codebase become tedious
  • It is not possible to scale up only certain parts of the application
  • Technology updates/rewrites become complex and expensive tasks
But, A MicroService is a service built around a specific business capability which can be independently deployed. So, to build large enterprise applications we can identify the sub-domains of our main business domain and build each sub-domain as a MicroService using Domain Driven Design (DDD) techniques. But in the end, we need to make all these microservices work together to serve the end user as if it is a single application tasks.

Advantages of MicroServices

  • Comprehending smaller codebase is easy
  • Can independently scale up highly used services
  • Each team can focus on one (or few) MicroService(s)
  • Technology updates/rewrites become simpler
For an explanation about microservices, read this article of Martin Fowler.

Build a simple MicroService using SpringBoot:

You can download this example code from here.

I am going to build a simple EmployeesAPI which can be accessed through REST. For this example I am going to use in-memory database H2 to store and retrieve employees.I have exposed 4 REST endpoints with which we can:
  • get all employees names: GET /api/employee
  • get a specific employee: GET /api/employee/{id}
  • add an employee: POST /api/employee
  • delete an employee: DELETE /api/employee/{id}
We need to create all these files:

  • pom.xml
  • EmployeesApplication.java
  • Employee.java
  • EmployeeRepository.java
  • EmployeesDataController.java
  • application.properties
  • data.sql
How to build simple microservice using Spring Boot

Let us look at pom.xml:

<?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>com.engineeernitesh</groupId>
    <artifactId>employeesapi-docker</artifactId>
    <version>1.0.1</version>
    <packaging>jar</packaging>
    <name>Employees database</name>
    <description>A simple application in which you can store and retrieve employees</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath />
    </parent>

    <properties>
        <docker.image.prefix>niteshkumar</docker.image.prefix>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- h2 db -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.194</version>
        </dependency>
        <!--springfox dependency -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- dockerfile plugin -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.3.6</version>
                <configuration>
                    <repository>${docker.image.prefix}/${project.artifactId}</repository>
                    <tag>${project.version}</tag>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

You can see I added docker related properties and springfox dependencies in pom.xml but I will discuss these 2 in detail in my next post.

We have 1.5.9.RELEASE as a basis. We then have 5 dependencies:
spring-boot-starter-web for libraries to creating the rest service. 
spring-boot-starter-data-jpa for the jpa capability.
spring-boot-starter-security for spring security
h2 for in-memory database.
springfox for swagger implementation.

I am also adding the spring-boot-maven-plugin to be able to run it from maven using Tomcat.

EmployeesApplication.javaThis is the starting point of our simple service. It will look like this:

package com.engineeernitesh.employeesapi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories
public class EmployeesApplication {

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

}
@SpringBootApplicationThe entry point of the Spring Boot Application is the class contains @SpringBootApplication annotation. This class should have the main method to run the 
Spring Boot application. @SpringBootApplication annotation includes Auto- Configuration, Component Scan, and Spring Boot Configuration
@EnableJpaRepositories - @EnableJpaRepositories is to use spring and JPA for database access.

Employee.java: This is a POJO class and this looks like:

package com.engineeernitesh.employeesapi;

import io.swagger.annotations.ApiModelProperty;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "employee")
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @ApiModelProperty(notes = "The generated employee id", hidden = true)
    private long id;
    @ApiModelProperty(notes = "The employees firstname", required = true)
    private String firstname;
    @ApiModelProperty(notes = "The employees lastname", required = true)
    private String lastname;
    
    
    public Employee(){
    }
    
    public Employee(String firstname, String lastname){
        this.firstname = firstname;
        this.lastname = lastname;
    }
    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * @return the firstname
     */
    public String getFirstname() {
        return firstname;
    }

    /**
     * @param firstname the firstname to set
     */
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    /**
     * @return the lastname
     */
    public String getLastname() {
        return lastname;
    }

    /**
     * @param lastname the lastname to set
     */
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
    
 @Override
    public String toString() {
        return String.format("Employee[id=%d, code='%s', name='%s']",
                id, firstname, lastname);
    }

    
}
This POJO class have 3 attributes mapping to the 3 columns with getter and setters. The annotation which does all the magic here is @Entity. This tells spring that it can be used for Object Relational Mapping. 

EmployeeRepository.java: This class is used to fetch, save and delete data.

package com.engineeernitesh.employeesapi;

import javax.transaction.Transactional;
import org.springframework.data.repository.CrudRepository;

@Transactional
public interface  EmployeeRepository extends CrudRepository<Employee, Long> {

    Employee findById(long id);
    
    Employee findByLastname(String Lastname);

}
Here extended spring's CrudRepository and defined 2 extra interface for retrieving an employee based on id and last name.
EmployeesDataController.javaNow for the service part. Spring also has easy ways to accommodate this using the @RestController annotation.


package com.engineeernitesh.employeesapi;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api/employee")
@Api(value="employees-home")
public class EmployeesDataController {

    private final static Logger LOGGER = Logger.getLogger(EmployeesDataController.class.getName());

    @Autowired
    EmployeeRepository employeeRepository;
    
    //-------------------Retrieve all employees--------------------------------------------------------
    @RequestMapping(value = "", method= RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "View a list of employees", response = Iterable.class)
    List<Employee> getEmployees() {
        List<Employee> result;
        LOGGER.log(Level.INFO, "Getting all employees");
        result = new ArrayList();
        Iterable<Employee> employeeList = employeeRepository.findAll();
        for (Employee employee : employeeList) {
            result.add(employee);
        }
        return result;
    }
    
    //-------------------Retrieve a employee by id--------------------------------------------------------
    @RequestMapping(value = "/{id}", method= RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "Get an employee by id", response = Employee.class)
    public Employee getEmployee(@PathVariable long id) {
        Employee result;
        LOGGER.log(Level.INFO, "Getting employee with id " + id);
        result = employeeRepository.findById(id);
        return result;
    }
  
    //-------------------Add an employee--------------------------------------------------------------------
    @PreAuthorize("hasRole('ADMIN')")
    @RequestMapping(method = RequestMethod.POST, produces = "application/text")
    @ApiOperation(value = "Add a new employee")
    public ResponseEntity saveEmployee(@RequestBody Employee input) {
        LOGGER.log(Level.INFO, "Saving employee " + input.getLastname());
        Employee employee = new Employee();
        employee.setFirstname(input.getFirstname());
        employee.setLastname(input.getLastname());    
 employeeRepository.save(employee);
        return new ResponseEntity("Employee saved successfully", HttpStatus.OK);
    }
    
    //-------------------Delete a employee by id------------------------------------------------------------
    @PreAuthorize("hasRole('ADMIN')")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "application/text")
    @ApiOperation(value = "Delete an employee by id")
    public ResponseEntity deleteEmployee(@PathVariable long id) {
        LOGGER.log(Level.INFO, "Deleting employee " + id);
 employeeRepository.delete(id);
        return new ResponseEntity("Employee deleted successfully", HttpStatus.OK);
    }
}

The @RestController annotation is used to define the RESTful web services. It serves JSON, XML and custom response.

The @RequestMapping annotation is used to define the Request URI to access the REST Endpoints. We can define Request method to consume and produce object.

The @RequestBody annotation is used to define the request body content type.

The @PathVariable annotation is used to define the custom or dynamic request URI. The Path variable in request URI is defined as curly braces {}.

@ApiOperation, @PreAuthorize annotation will discuss on swagger post.

application.properties: This properties file is used to database, H2 and hibernate settings.

###
#   Database Settings
###
spring.datasource.url=jdbc:h2:mem:climbers-db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.platform=h2
spring.datasource.username = sa
spring.datasource.password =
spring.datasource.driverClassName = org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

###
#   H2 Settings
###
spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false

###
#   Hibernate Settings
###
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.format_sql=false


#set sql level to debug to see all the sql statements
logging.level.org.hibernate.SQL=debug
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n

data.sql: We will add some data into employee table.

INSERT INTO employee (id, firstname, lastname) VALUES (1, 'Nitesh', 'Kumar')
INSERT INTO employee (id, firstname, lastname) VALUES (2, 'Debarshi', 'Da')
INSERT INTO employee (id, firstname, lastname) VALUES (3, 'Sumantra', 'Pal')
Now run the application using maven or simply go to EmployeesApplication class and run as java application. Application deployed into tomcat and run on default port 8080.

How to build simple microservice using Spring Boot

Now go to postman or RestClient and try to run http://localhost:8080/api/employee. You should have employees list.

How to build simple microservice using Spring Boot

Similarly, we can run http://localhost:8080/api/employee/1 and other URL's.


Next post:

Implementation of swagger in SpringBoot API

How to run SpringBoot API as a Docker container

How to Deploy your docker container on Amazon EC2 Elastic Container Service