├── .gitignore ├── 01-hello-world-rest-api ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── rest │ │ │ └── webservices │ │ │ └── restfulwebservices │ │ │ ├── HelloWorldBean.java │ │ │ ├── HelloWorldController.java │ │ │ └── RestfulWebServicesApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── in28minutes │ └── rest │ └── webservices │ └── restfulwebservices │ └── RestfulWebServicesApplicationTests.java ├── 02-spring-boot-simple-task ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── spring │ │ │ └── simple │ │ │ └── task │ │ │ ├── EnvironmentConfigurationLogger.java │ │ │ ├── SpringSimpleTaskApplication.java │ │ │ └── TaskImpl.java │ └── resources │ │ ├── application.properties │ │ └── log.txt │ └── test │ └── java │ └── com │ └── in28minutes │ └── spring │ └── simple │ └── task │ └── SpringIn5StepsApplicationTests.java ├── 03-currency-exchange-service-h2 ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── microservices │ │ │ └── currencyexchangeservice │ │ │ ├── CurrencyExchangeServiceApplicationH2.java │ │ │ ├── resource │ │ │ ├── CurrencyExchangeController.java │ │ │ ├── ExchangeValue.java │ │ │ └── ExchangeValueRepository.java │ │ │ └── util │ │ │ ├── containerservice │ │ │ └── ContainerMetaDataService.java │ │ │ └── logging │ │ │ └── EnvironmentConfigurationLogger.java │ └── resources │ │ ├── application.properties │ │ └── data.sql │ └── test │ └── java │ └── com │ └── in28minutes │ └── microservices │ └── currencyexchangeservice │ └── CurrencyExchangeServiceApplicationTests.java ├── 04-currency-exchange-service-mysql ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── microservices │ │ │ └── currencyexchangeservice │ │ │ ├── CurrencyExchangeServiceApplicationMySql.java │ │ │ ├── resource │ │ │ ├── CurrencyExchangeController.java │ │ │ ├── ExchangeValue.java │ │ │ └── ExchangeValueRepository.java │ │ │ └── util │ │ │ ├── containerservice │ │ │ └── ContainerMetaDataService.java │ │ │ └── logging │ │ │ └── EnvironmentConfigurationLogger.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── currencyexchangeservice │ │ └── CurrencyExchangeServiceApplicationTests.java │ └── resources │ └── application.properties ├── 05-currency-conversion-service ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── microservices │ │ │ └── currencyconversionservice │ │ │ ├── CurrencyConversionServiceApplication.java │ │ │ ├── resource │ │ │ ├── CurrencyConversionBean.java │ │ │ └── CurrencyConversionController.java │ │ │ └── util │ │ │ ├── containerservice │ │ │ └── ContainerMetaDataService.java │ │ │ └── logging │ │ │ └── EnvironmentConfigurationLogger.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── in28minutes │ └── microservices │ └── currencyconversionservice │ └── CurrencyConversionServiceApplicationTests.java ├── 06-currency-exchange-service-h2-xray ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── microservices │ │ │ └── currencyexchangeservice │ │ │ ├── CurrencyExchangeServiceApplicationH2.java │ │ │ ├── resource │ │ │ ├── CurrencyExchangeController.java │ │ │ ├── ExchangeValue.java │ │ │ └── ExchangeValueRepository.java │ │ │ ├── util │ │ │ ├── containerservice │ │ │ │ └── ContainerMetaDataService.java │ │ │ └── logging │ │ │ │ └── EnvironmentConfigurationLogger.java │ │ │ └── xray │ │ │ ├── AwsXrayConfig.java │ │ │ └── XRayInspector.java │ └── resources │ │ ├── application.properties │ │ └── data.sql │ └── test │ └── java │ └── com │ └── in28minutes │ └── microservices │ └── currencyexchangeservice │ └── CurrencyExchangeServiceApplicationTests.java ├── 07-currency-conversion-service-xray ├── Dockerfile ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── microservices │ │ │ └── currencyconversionservice │ │ │ ├── CurrencyConversionServiceApplication.java │ │ │ ├── resource │ │ │ ├── CurrencyConversionBean.java │ │ │ └── CurrencyConversionController.java │ │ │ ├── util │ │ │ ├── containerservice │ │ │ │ └── ContainerMetaDataService.java │ │ │ └── logging │ │ │ │ └── EnvironmentConfigurationLogger.java │ │ │ └── xray │ │ │ ├── AwsXrayConfig.java │ │ │ └── XRayInspector.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── in28minutes │ └── microservices │ └── currencyconversionservice │ └── CurrencyConversionServiceApplicationTests.java ├── 08-hello-world-rest-api-code-pipeline ├── Dockerfile ├── appspec.yaml ├── buildspec.yaml ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── rest │ │ │ └── webservices │ │ │ └── restfulwebservices │ │ │ ├── HelloWorldBean.java │ │ │ ├── HelloWorldController.java │ │ │ └── RestfulWebServicesApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── in28minutes │ └── rest │ └── webservices │ └── restfulwebservices │ └── RestfulWebServicesApplicationTests.java └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | # Compiled class file 42 | *.class 43 | 44 | # Log file 45 | *.log 46 | 47 | # BlueJ files 48 | *.ctxt 49 | 50 | # Mobile Tools for Java (J2ME) 51 | .mtj.tmp/ 52 | 53 | # Package Files # 54 | *.jar 55 | *.war 56 | *.ear 57 | *.tar.gz 58 | *.rar 59 | *.cmd 60 | *.classpath 61 | *.settings 62 | *.project 63 | *.mvn 64 | mvnw 65 | target 66 | *.DS_Store 67 | 68 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 69 | hs_err_pid* 70 | -------------------------------------------------------------------------------- /01-hello-world-rest-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 80 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /01-hello-world-rest-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.rest.webservices 8 | 01-aws-hello-world-rest-api 9 | 1.0.0-RELEASE 10 | jar 11 | Demo project for Spring Boot 12 | aws-hello-world-rest-api 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-devtools 37 | runtime 38 | 39 | 40 | 41 | javax.xml.bind 42 | jaxb-api 43 | 44 | 45 | com.sun.xml.bind 46 | jaxb-impl 47 | 2.3.0 48 | 49 | 50 | org.glassfish.jaxb 51 | jaxb-runtime 52 | 53 | 54 | javax.activation 55 | activation 56 | 1.1.1 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter-test 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | com.spotify 75 | dockerfile-maven-plugin 76 | 1.4.10 77 | 78 | 79 | default 80 | 81 | build 82 | 83 | 84 | 85 | 86 | 87 | in28min/${project.name} 88 | ${project.version} 89 | true 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | spring-snapshots 98 | Spring Snapshots 99 | https://repo.spring.io/snapshot 100 | 101 | true 102 | 103 | 104 | 105 | spring-milestones 106 | Spring Milestones 107 | https://repo.spring.io/milestone 108 | 109 | false 110 | 111 | 112 | 113 | 114 | 115 | 116 | spring-snapshots 117 | Spring Snapshots 118 | https://repo.spring.io/snapshot 119 | 120 | true 121 | 122 | 123 | 124 | spring-milestones 125 | Spring Milestones 126 | https://repo.spring.io/milestone 127 | 128 | false 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /01-hello-world-rest-api/readme.md: -------------------------------------------------------------------------------- 1 | # Hello World Rest API 2 | 3 | - Main class com.in28minutes.rest.webservices.restfulwebservices.RestfulWebServicesApplication 4 | - You cannot run this app on local as it is configured to run on port 80 - https://serverfault.com/questions/112795/how-to-run-a-server-on-port-80-as-a-normal-user-on-linux. You can run it as a docker container as shown below 5 | 6 | 7 | ### Creating Containers 8 | 9 | - mvn clean package 10 | - docker run --publish 8200:80 in28min/aws-hello-world-rest-api:0.0.1-SNAPSHOT 11 | 12 | ``` 13 | docker login 14 | docker push @@REPO@@/aws-hello-world-rest-api:0.0.1-SNAPSHOT 15 | ``` 16 | 17 | ## Test URLs 18 | 19 | - http://localhost:8200/hello-world 20 | 21 | ```txt 22 | Hello World 23 | ``` 24 | 25 | - http://localhost:8200/hello-world-bean 26 | 27 | ```json 28 | {"message":"Hello World - Changed"} 29 | ``` 30 | 31 | - http://localhost:8200/hello-world/path-variable/in28minutes 32 | 33 | ```json 34 | {"message":"Hello World, in28minutes"} 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /01-hello-world-rest-api/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | public class HelloWorldBean { 4 | 5 | private String message; 6 | 7 | public HelloWorldBean(String message) { 8 | this.message = message; 9 | } 10 | 11 | public String getMessage() { 12 | return message; 13 | } 14 | 15 | public void setMessage(String message) { 16 | this.message = message; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return String.format("HelloWorldBean [message=%s]", message); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-hello-world-rest-api/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.PathVariable; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class HelloWorldController { 9 | 10 | @GetMapping(path = "/hello-world") 11 | public String helloWorld() { 12 | return "Hello World"; 13 | } 14 | 15 | @GetMapping(path = "/hello-world-bean") 16 | public HelloWorldBean helloWorldBean() { 17 | return new HelloWorldBean("Hello World - Changed"); 18 | } 19 | 20 | @GetMapping(path = "/hello-world/path-variable/{name}") 21 | public HelloWorldBean helloWorldPathVariable(@PathVariable String name) { 22 | return new HelloWorldBean(String.format("Hello World, %s", name)); 23 | } 24 | } -------------------------------------------------------------------------------- /01-hello-world-rest-api/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestfulWebServicesApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestfulWebServicesApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /01-hello-world-rest-api/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=80 -------------------------------------------------------------------------------- /01-hello-world-rest-api/src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestfulWebServicesApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /02-spring-boot-simple-task/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 8000 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /02-spring-boot-simple-task/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.spring.basics 8 | 02-aws-simple-spring-task 9 | 1.0.0-RELEASE 10 | jar 11 | 12 | aws-simple-spring-task 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.0.0.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-test 37 | test 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-maven-plugin 46 | 47 | 48 | 49 | com.spotify 50 | dockerfile-maven-plugin 51 | 1.4.10 52 | 53 | 54 | default 55 | 56 | build 57 | 58 | 59 | 60 | 61 | 62 | in28min/${project.name} 63 | ${project.version} 64 | true 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | spring-snapshots 73 | Spring Snapshots 74 | https://repo.spring.io/snapshot 75 | 76 | true 77 | 78 | 79 | 80 | spring-milestones 81 | Spring Milestones 82 | https://repo.spring.io/milestone 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | 91 | spring-snapshots 92 | Spring Snapshots 93 | https://repo.spring.io/snapshot 94 | 95 | true 96 | 97 | 98 | 99 | spring-milestones 100 | Spring Milestones 101 | https://repo.spring.io/milestone 102 | 103 | false 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /02-spring-boot-simple-task/readme.md: -------------------------------------------------------------------------------- 1 | # Simple Spring Task 2 | 3 | Run `com.in28minutes.spring.simple.task.SpringSimpleTaskApplication` as a Java Application. 4 | 5 | Runs `com.in28minutes.spring.simple.task.TaskImpl.performTask()` at launch 6 | 7 | ### Creating Containers 8 | 9 | - mvn clean package 10 | - docker run in28min/aws-simple-spring-task:0.0.1-SNAPSHOT 11 | 12 | ``` 13 | docker login 14 | docker push @@REPO@@/aws-simple-spring-task:0.0.1-SNAPSHOT 15 | ``` -------------------------------------------------------------------------------- /02-spring-boot-simple-task/src/main/java/com/in28minutes/spring/simple/task/EnvironmentConfigurationLogger.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.spring.simple.task; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.StreamSupport; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.context.event.EventListener; 10 | import org.springframework.core.env.AbstractEnvironment; 11 | import org.springframework.core.env.EnumerablePropertySource; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.env.MutablePropertySources; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EnvironmentConfigurationLogger { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class); 20 | 21 | @SuppressWarnings("rawtypes") 22 | @EventListener 23 | public void handleContextRefresh(ContextRefreshedEvent event) { 24 | final Environment environment = event.getApplicationContext().getEnvironment(); 25 | LOGGER.info("====== Environment and configuration ======"); 26 | LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles())); 27 | final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources(); 28 | StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource) 29 | .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct() 30 | .forEach(prop -> LOGGER.info("{}", prop));// environment.getProperty(prop) 31 | LOGGER.info("==========================================="); 32 | 33 | // LOGGER.info(retrieveContainerMetadataInfo()); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /02-spring-boot-simple-task/src/main/java/com/in28minutes/spring/simple/task/SpringSimpleTaskApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.spring.simple.task; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.ApplicationContext; 6 | 7 | @SpringBootApplication 8 | public class SpringSimpleTaskApplication { 9 | public static void main(String[] args) { 10 | ApplicationContext applicationContext = SpringApplication.run(SpringSimpleTaskApplication.class, args); 11 | TaskImpl task = applicationContext.getBean(TaskImpl.class); 12 | task.performTask(); 13 | } 14 | } -------------------------------------------------------------------------------- /02-spring-boot-simple-task/src/main/java/com/in28minutes/spring/simple/task/TaskImpl.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.spring.simple.task; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class TaskImpl { 9 | 10 | private static final Logger LOGGER = LoggerFactory.getLogger(TaskImpl.class); 11 | 12 | public void performTask() { 13 | LOGGER.info("DO THE ONE TIME TASK HERE!"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /02-spring-boot-simple-task/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/deploy-spring-microservices-to-aws-ecs-fargate/2d6d655aeee2f237688387fe9d3f069fdaacd332/02-spring-boot-simple-task/src/main/resources/application.properties -------------------------------------------------------------------------------- /02-spring-boot-simple-task/src/main/resources/log.txt: -------------------------------------------------------------------------------- 1 | Searching directory [/in28Minutes/git/getting-started-in-5-steps/spring-in-5-steps/target/classes/com/in28minutes/spring/basics/springin5steps] for files matching pattern [/in28Minutes/git/getting-started-in-5-steps/spring-in-5-steps/target/classes/com/in28minutes/spring/basics/springin5steps/**/*.class] 2 | Identified candidate component class: file [/in28Minutes/git/getting-started-in-5-steps/spring-in-5-steps/target/classes/com/in28minutes/spring/basics/springin5steps/BinarySearchImpl.class] 3 | Identified candidate component class: file [/in28Minutes/git/getting-started-in-5-steps/spring-in-5-steps/target/classes/com/in28minutes/spring/basics/springin5steps/BubbleSortAlgorithm.class] 4 | 5 | Creating instance of bean 'binarySearchImpl' 6 | Creating instance of bean 'bubbleSortAlgorithm' 7 | Finished creating instance of bean 'bubbleSortAlgorithm' 8 | 9 | Constuctor - Autowiring by type from bean name 'binarySearchImpl' via constructor 10 | to bean named 'bubbleSortAlgorithm' 11 | Setter - Autowiring by type from bean name 'binarySearchImpl' to bean named 'bubbleSortAlgorithm' 12 | No Setter or Constructor - Autowiring by type from bean name 'binarySearchImpl' to bean named 'bubbleSortAlgorithm' 13 | 14 | 15 | Finished creating instance of bean 'binarySearchImpl' 16 | -------------------------------------------------------------------------------- /02-spring-boot-simple-task/src/test/java/com/in28minutes/spring/simple/task/SpringIn5StepsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.spring.simple.task; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringIn5StepsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 8000 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.microservices 8 | 03-aws-currency-exchange-service-h2 9 | 0.0.1-SNAPSHOT 10 | jar 11 | 12 | aws-currency-exchange-service-h2 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.1.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | Greenwich.RC2 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-sleuth 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-actuator 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-devtools 54 | runtime 55 | 56 | 57 | 58 | com.h2database 59 | h2 60 | runtime 61 | 62 | 63 | 64 | javax.xml.bind 65 | jaxb-api 66 | 67 | 68 | com.sun.xml.bind 69 | jaxb-impl 70 | 2.3.0 71 | 72 | 73 | org.glassfish.jaxb 74 | jaxb-runtime 75 | 76 | 77 | javax.activation 78 | activation 79 | 1.1.1 80 | 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-starter-test 85 | test 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.springframework.cloud 94 | spring-cloud-dependencies 95 | ${spring-cloud.version} 96 | pom 97 | import 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | org.springframework.boot 106 | spring-boot-maven-plugin 107 | 108 | 109 | 110 | com.spotify 111 | dockerfile-maven-plugin 112 | 1.4.10 113 | 114 | 115 | default 116 | 117 | build 118 | 119 | 120 | 121 | 122 | 123 | in28min/${project.name} 124 | ${project.version} 125 | true 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | spring-snapshots 134 | Spring Snapshots 135 | https://repo.spring.io/snapshot 136 | 137 | true 138 | 139 | 140 | 141 | spring-milestones 142 | Spring Milestones 143 | https://repo.spring.io/milestone 144 | 145 | false 146 | 147 | 148 | 149 | 150 | 151 | 152 | spring-snapshots 153 | Spring Snapshots 154 | https://repo.spring.io/snapshot 155 | 156 | true 157 | 158 | 159 | 160 | spring-milestones 161 | Spring Milestones 162 | https://repo.spring.io/milestone 163 | 164 | false 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/readme.md: -------------------------------------------------------------------------------- 1 | # Currency Exchange Micro Service - H2 2 | 3 | Run com.in28minutes.microservices.currencyconversionservice.CurrencyConversionServiceApplicationH2 as a Java Application. 4 | 5 | ## Containerization 6 | 7 | ### Troubleshooting 8 | 9 | - Problem - Caused by: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: java.io.IOException: No such file or directory 10 | - Solution - Check if docker is up and running! 11 | - Problem - Error creating the Docker image on MacOS - java.io.IOException: Cannot run program “docker-credential-osxkeychain”: error=2, No such file or directory 12 | - Solution - https://medium.com/@dakshika/error-creating-the-docker-image-on-macos-wso2-enterprise-integrator-tooling-dfb5b537b44e 13 | 14 | ### Creating Container 15 | 16 | - mvn package 17 | 18 | ### Running Container 19 | 20 | #### Basic 21 | ``` 22 | docker container run --publish 8000:8000 in28min/aws-currency-exchange-service-h2:0.0.1-SNAPSHOT 23 | ``` 24 | #### Custom Network 25 | ``` 26 | docker run --publish 8000:8000 --network currency-network --name=currency-exchange-service in28min/aws-currency-exchange-service-h2:0.0.1-SNAPSHOT 27 | ``` 28 | 29 | Test API 30 | - http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/USD/to/INR 31 | 32 | ``` 33 | docker login 34 | docker push @@@REPO_NAME@@@/aws-currency-exchange-service-h2:0.0.1-SNAPSHOT 35 | ``` 36 | 37 | ## Resources 38 | 39 | - http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/USD/to/INR 40 | 41 | ```json 42 | { 43 | "id": 10001, 44 | "from": "USD", 45 | "to": "INR", 46 | "conversionMultiple": 65.00, 47 | "environmentInfo": "NA" 48 | } 49 | ``` 50 | 51 | ## H2 Console 52 | 53 | - http://localhost:8000/api/currency-exchange-microservice/h2-console 54 | - Use `jdbc:h2:mem:testdb` as JDBC URL 55 | 56 | 57 | ## Tables Created 58 | ``` 59 | create table exchange_value 60 | ( 61 | id bigint not null, 62 | conversion_multiple decimal(19,2), 63 | currency_from varchar(255), 64 | currency_to varchar(255), 65 | primary key (id) 66 | ) 67 | ``` 68 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationH2.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CurrencyExchangeServiceApplicationH2 { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CurrencyExchangeServiceApplicationH2.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/CurrencyExchangeController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import java.util.Map; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestHeader; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.in28minutes.microservices.currencyexchangeservice.util.containerservice.ContainerMetaDataService; 14 | 15 | @RestController 16 | public class CurrencyExchangeController { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrencyExchangeController.class); 19 | 20 | @Autowired 21 | private ExchangeValueRepository repository; 22 | 23 | @Autowired 24 | private ContainerMetaDataService containerMetaDataService; 25 | 26 | @GetMapping("/currency-exchange/from/{from}/to/{to}") 27 | public ExchangeValue retrieveExchangeValue(@PathVariable String from, @PathVariable String to, 28 | @RequestHeader Map headers) { 29 | 30 | printAllHeaders(headers); 31 | 32 | ExchangeValue exchangeValue = repository.findByFromAndTo(from, to); 33 | 34 | LOGGER.info("{} {} {}", from, to, exchangeValue); 35 | 36 | if (exchangeValue == null) { 37 | throw new RuntimeException("Unable to find data to convert " + from + " to " + to); 38 | } 39 | 40 | exchangeValue.setExchangeEnvironmentInfo(containerMetaDataService.retrieveContainerMetadataInfo()); 41 | 42 | return exchangeValue; 43 | } 44 | 45 | private void printAllHeaders(Map headers) { 46 | headers.forEach((key, value) -> { 47 | LOGGER.info(String.format("Header '%s' = %s", key, value)); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/ExchangeValue.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.Id; 8 | import javax.persistence.Transient; 9 | 10 | @Entity 11 | public class ExchangeValue { 12 | 13 | @Id 14 | private Long id; 15 | 16 | @Column(name = "currency_from") 17 | private String from; 18 | 19 | @Column(name = "currency_to") 20 | private String to; 21 | 22 | private BigDecimal conversionMultiple; 23 | 24 | @Transient 25 | private String exchangeEnvironmentInfo; 26 | 27 | public ExchangeValue() { 28 | 29 | } 30 | 31 | public ExchangeValue(Long id, String from, String to, BigDecimal conversionMultiple) { 32 | super(); 33 | this.id = id; 34 | this.from = from; 35 | this.to = to; 36 | this.conversionMultiple = conversionMultiple; 37 | } 38 | 39 | public Long getId() { 40 | return id; 41 | } 42 | 43 | public String getFrom() { 44 | return from; 45 | } 46 | 47 | public String getTo() { 48 | return to; 49 | } 50 | 51 | public BigDecimal getConversionMultiple() { 52 | return conversionMultiple; 53 | } 54 | 55 | public String getExchangeEnvironmentInfo() { 56 | return exchangeEnvironmentInfo; 57 | } 58 | 59 | public void setExchangeEnvironmentInfo(String environmentInfo) { 60 | this.exchangeEnvironmentInfo = environmentInfo; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/ExchangeValueRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface ExchangeValueRepository extends JpaRepository { 6 | ExchangeValue findByFromAndTo(String from, String to); 7 | } 8 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/java/com/in28minutes/microservices/currencyexchangeservice/util/containerservice/ContainerMetaDataService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.util.containerservice; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Service 10 | public class ContainerMetaDataService { 11 | 12 | private static final String ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI = "ECS_CONTAINER_METADATA_URI"; 13 | 14 | private static final String DEFAULT_VALUE = "EMPTY"; 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ContainerMetaDataService.class); 17 | 18 | // @Value(${ENVIRONMENT_VARIABLE_NAME:DEFAULT_VALUE}) 19 | @Value("${" + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI + ":" + DEFAULT_VALUE + "}") 20 | private String containerMetadataUri; 21 | 22 | public String retrieveContainerMetadataInfo() { 23 | 24 | if (containerMetadataUri.contains(DEFAULT_VALUE)) { 25 | LOGGER.info("Environment Variable Not Available - " + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI); 26 | return "NA"; 27 | } 28 | 29 | return new RestTemplate().getForObject(containerMetadataUri, String.class); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/java/com/in28minutes/microservices/currencyexchangeservice/util/logging/EnvironmentConfigurationLogger.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.util.logging; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.StreamSupport; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.context.event.EventListener; 10 | import org.springframework.core.env.AbstractEnvironment; 11 | import org.springframework.core.env.EnumerablePropertySource; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.env.MutablePropertySources; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EnvironmentConfigurationLogger { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class); 20 | 21 | @SuppressWarnings("rawtypes") 22 | @EventListener 23 | public void handleContextRefresh(ContextRefreshedEvent event) { 24 | final Environment environment = event.getApplicationContext().getEnvironment(); 25 | LOGGER.info("====== Environment and configuration ======"); 26 | LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles())); 27 | final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources(); 28 | StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource) 29 | .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct() 30 | .forEach(prop -> LOGGER.info("{}", prop));// environment.getProperty(prop) 31 | LOGGER.info("==========================================="); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-exchange-microservice 2 | server.port=8000 3 | 4 | spring.jpa.show-sql=true 5 | spring.h2.console.enabled=true 6 | 7 | management.endpoints.web.base-path=/manage 8 | server.servlet.context-path=/api/currency-exchange-microservice -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple) 2 | values(10001,'USD','INR',65); 3 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple) 4 | values(10002,'EUR','INR',75); 5 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple) 6 | values(10003,'AUD','INR',25); -------------------------------------------------------------------------------- /03-currency-exchange-service-h2/src/test/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyExchangeServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 8000 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.microservices 8 | 04-aws-currency-exchange-service-mysql 9 | 0.0.1-SNAPSHOT 10 | jar 11 | 12 | aws-currency-exchange-service-mysql 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.1.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | Greenwich.RC2 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-sleuth 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-actuator 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-devtools 54 | runtime 55 | 56 | 57 | 58 | mysql 59 | mysql-connector-java 60 | 61 | 62 | 63 | com.h2database 64 | h2 65 | test 66 | 67 | 68 | 69 | javax.xml.bind 70 | jaxb-api 71 | 72 | 73 | com.sun.xml.bind 74 | jaxb-impl 75 | 2.3.0 76 | 77 | 78 | org.glassfish.jaxb 79 | jaxb-runtime 80 | 81 | 82 | javax.activation 83 | activation 84 | 1.1.1 85 | 86 | 87 | 88 | org.springframework.boot 89 | spring-boot-starter-test 90 | test 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.springframework.cloud 99 | spring-cloud-dependencies 100 | ${spring-cloud.version} 101 | pom 102 | import 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | org.springframework.boot 111 | spring-boot-maven-plugin 112 | 113 | 114 | 115 | com.spotify 116 | dockerfile-maven-plugin 117 | 1.4.10 118 | 119 | 120 | default 121 | 122 | build 123 | 124 | 125 | 126 | 127 | 128 | in28min/${project.name} 129 | ${project.version} 130 | true 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | spring-snapshots 139 | Spring Snapshots 140 | https://repo.spring.io/snapshot 141 | 142 | true 143 | 144 | 145 | 146 | spring-milestones 147 | Spring Milestones 148 | https://repo.spring.io/milestone 149 | 150 | false 151 | 152 | 153 | 154 | 155 | 156 | 157 | spring-snapshots 158 | Spring Snapshots 159 | https://repo.spring.io/snapshot 160 | 161 | true 162 | 163 | 164 | 165 | spring-milestones 166 | Spring Milestones 167 | https://repo.spring.io/milestone 168 | 169 | false 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/readme.md: -------------------------------------------------------------------------------- 1 | # Currency Exchange Micro Service - Mysql 2 | 3 | Run com.in28minutes.microservices.currencyconversionservice.CurrencyConversionServiceApplicationMySql as a Java Application. 4 | 5 | Application uses h2 database to run the tests. 6 | 7 | ## Changes from H2 Application 8 | 9 | #### pom.xml 10 | 11 | ``` 12 | 13 | com.h2database 14 | h2 15 | test 16 | 17 | 18 | 19 | mysql 20 | mysql-connector-java 21 | 22 | ``` 23 | 24 | #### src/main/resources/application.properties 25 | 26 | ``` 27 | #spring.h2.console.enabled=true 28 | #spring.h2.console.settings.web-allow-others=true 29 | 30 | spring.jpa.hibernate.ddl-auto=update 31 | spring.datasource.url=jdbc:mysql://${RDS_HOSTNAME:localhost}:${RDS_PORT:3306}/${RDS_DB_NAME:exchange-db} 32 | spring.datasource.username=${RDS_USERNAME:exchange-db-user} 33 | spring.datasource.password=${RDS_PASSWORD:dummyexchange} 34 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect 35 | ``` 36 | 37 | #### src/test/resources/application.properties 38 | 39 | ``` 40 | spring.jpa.hibernate.ddl-auto=create-drop 41 | spring.datasource.driver-class-name=org.h2.Driver 42 | spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 43 | spring.datasource.username=sa 44 | spring.datasource.password=sa 45 | ``` 46 | 47 | ## Dummy Data 48 | 49 | Removed data.sql 50 | 51 | ``` 52 | long count = repository.count(); 53 | 54 | if(count ==0) { 55 | repository.save(new ExchangeValue(10001L,"USD","INR", BigDecimal.valueOf(65))); 56 | repository.save(new ExchangeValue(10002L,"EUR","INR", BigDecimal.valueOf(75))); 57 | repository.save(new ExchangeValue(10003L,"AUD","INR", BigDecimal.valueOf(25))); 58 | } 59 | ``` 60 | 61 | ## My SQL 62 | 63 | ### Launching MySQL using Docker 64 | 65 | ``` 66 | docker run --detach --env MYSQL_ROOT_PASSWORD=dummypassword --env MYSQL_USER=exchange-db-user --env MYSQL_PASSWORD=dummyexchange --env MYSQL_DATABASE=exchange-db --name mysql --publish 3306:3306 mysql:5.7 67 | ``` 68 | 69 | 70 | ### My SQL Shell Client 71 | 72 | - https://dev.mysql.com/downloads/shell/ 73 | 74 | - Install on mac using `brew install caskroom/cask/mysql-shell`. 75 | 76 | 77 | ``` 78 | Rangas-MacBook-Air:aws-projects in28min$ mysqlsh 79 | MySQL Shell 8.0.15 80 | Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. 81 | Oracle is a registered trademark of Oracle Corporation and/or its affiliates. 82 | Other names may be trademarks of their respective owners. 83 | 84 | Type '\help' or '\?' for help; '\quit' to exit. 85 | 86 | MySQL JS > \connect todos-user@localhost:3306 87 | Creating a session to 'todos-user@localhost:3306' 88 | Please provide the password for 'todos-user@localhost:3306': 89 | Save password for 'todos-user@localhost:3306'? [Y]es/[N]o/Ne[v]er (default No): v 90 | Fetching schema names for autocompletion... Press ^C to stop. 91 | Your MySQL connection id is 37 92 | Server version: 5.7.26 MySQL Community Server (GPL) 93 | No default schema selected; type \use to set one. 94 | 95 | MySQL localhost:3306 ssl JS > \sql 96 | Switching to SQL mode... Commands end with ; 97 | 98 | MySQL localhost:3306 ssl SQL > use todos 99 | Default schema set to `todos`. 100 | Fetching table and column names from `todos` for auto-completion... Press ^C to stop. 101 | 102 | MySQL localhost:3306 ssl todos SQL > select * from todo ; 103 | +----+--------------+---------+----------------------------+-------------+ 104 | | id | description | is_done | target_date | user | 105 | +----+--------------+---------+----------------------------+-------------+ 106 | | 1 | Default Desc | 0 | 2019-06-26 18:30:00.000000 | in28minutes | 107 | +----+--------------+---------+----------------------------+-------------+ 108 | 1 row in set (0.0032 sec) 109 | 110 | ``` 111 | 112 | ## Containerization 113 | 114 | ### Troubleshooting 115 | 116 | - Problem - Caused by: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: java.io.IOException: No such file or directory 117 | - Solution - Check if docker is up and running! 118 | - Problem - Error creating the Docker image on MacOS - java.io.IOException: Cannot run program “docker-credential-osxkeychain”: error=2, No such file or directory 119 | - Solution - https://medium.com/@dakshika/error-creating-the-docker-image-on-macos-wso2-enterprise-integrator-tooling-dfb5b537b44e 120 | 121 | ### Creating Containers 122 | 123 | - mvn package 124 | - docker run --publish 8000:8000 --network MY_BRIDGE --name currency-exchange-microservice in28min/aws-currency-exchange-service-mysql:0.0.1-SNAPSHOT 125 | 126 | Test API 127 | - http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/USD/to/INR 128 | 129 | ``` 130 | docker login 131 | docker push @@@REPO_NAME@@@/aws-currency-exchange-service-mysql:0.0.1-SNAPSHOT 132 | ``` 133 | 134 | ## Environment Variables 135 | 136 | SSM URN - arn:aws:ssm:us-east-1::parameter/ 137 | 138 | - /dev/currency-exchange-service/RDS_DB_NAME - exchange_db 139 | - /dev/currency-exchange-service/RDS_HOSTNAME 140 | - /dev/currency-exchange-service/RDS_PASSWORD 141 | - /dev/currency-exchange-service/RDS_PORT - 3306 142 | - /dev/currency-exchange-service/RDS_USERNAME - exchange_db_user 143 | 144 | 145 | 146 | ## Resources 147 | 148 | - http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/USD/to/INR 149 | 150 | ```json 151 | { 152 | "id": 10001, 153 | "from": "USD", 154 | "to": "INR", 155 | "conversionMultiple": 65.00, 156 | "environmentInfo": "NA" 157 | } 158 | ``` 159 | 160 | ## Tables Created 161 | ``` 162 | create table exchange_value 163 | ( 164 | id bigint not null, 165 | conversion_multiple decimal(19,2), 166 | currency_from varchar(255), 167 | currency_to varchar(255), 168 | primary key (id) 169 | ) 170 | ``` 171 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationMySql.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | 10 | import com.in28minutes.microservices.currencyexchangeservice.resource.ExchangeValue; 11 | import com.in28minutes.microservices.currencyexchangeservice.resource.ExchangeValueRepository; 12 | 13 | @SpringBootApplication 14 | public class CurrencyExchangeServiceApplicationMySql implements CommandLineRunner { 15 | 16 | @Autowired 17 | ExchangeValueRepository repository; 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(CurrencyExchangeServiceApplicationMySql.class, args); 21 | } 22 | 23 | @Override 24 | public void run(String... args) throws Exception { 25 | 26 | long count = repository.count(); 27 | 28 | if (count == 0) { 29 | repository.save(new ExchangeValue(10001L, "USD", "INR", BigDecimal.valueOf(60))); 30 | repository.save(new ExchangeValue(10002L, "EUR", "INR", BigDecimal.valueOf(70))); 31 | repository.save(new ExchangeValue(10003L, "AUD", "INR", BigDecimal.valueOf(20))); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/CurrencyExchangeController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import java.util.Map; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestHeader; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.in28minutes.microservices.currencyexchangeservice.util.containerservice.ContainerMetaDataService; 14 | 15 | @RestController 16 | public class CurrencyExchangeController { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrencyExchangeController.class); 19 | 20 | @Autowired 21 | private ExchangeValueRepository repository; 22 | 23 | @Autowired 24 | private ContainerMetaDataService containerMetaDataService; 25 | 26 | @GetMapping("/currency-exchange/from/{from}/to/{to}") 27 | public ExchangeValue retrieveExchangeValue(@PathVariable String from, @PathVariable String to, 28 | @RequestHeader Map headers) { 29 | 30 | printAllHeaders(headers); 31 | 32 | ExchangeValue exchangeValue = repository.findByFromAndTo(from, to); 33 | 34 | LOGGER.info("{} {} {}", from, to, exchangeValue); 35 | 36 | if (exchangeValue == null) { 37 | throw new RuntimeException("Unable to find data to convert " + from + " to " + to); 38 | } 39 | 40 | exchangeValue.setExchangeEnvironmentInfo(containerMetaDataService.retrieveContainerMetadataInfo()); 41 | 42 | return exchangeValue; 43 | } 44 | 45 | private void printAllHeaders(Map headers) { 46 | headers.forEach((key, value) -> { 47 | LOGGER.info(String.format("Header '%s' = %s", key, value)); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/ExchangeValue.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.Id; 8 | import javax.persistence.Transient; 9 | 10 | @Entity 11 | public class ExchangeValue { 12 | 13 | @Id 14 | private Long id; 15 | 16 | @Column(name = "currency_from") 17 | private String from; 18 | 19 | @Column(name = "currency_to") 20 | private String to; 21 | 22 | private BigDecimal conversionMultiple; 23 | 24 | @Transient 25 | private String exchangeEnvironmentInfo; 26 | 27 | public ExchangeValue() { 28 | 29 | } 30 | 31 | public ExchangeValue(Long id, String from, String to, BigDecimal conversionMultiple) { 32 | super(); 33 | this.id = id; 34 | this.from = from; 35 | this.to = to; 36 | this.conversionMultiple = conversionMultiple; 37 | } 38 | 39 | public Long getId() { 40 | return id; 41 | } 42 | 43 | public String getFrom() { 44 | return from; 45 | } 46 | 47 | public String getTo() { 48 | return to; 49 | } 50 | 51 | public BigDecimal getConversionMultiple() { 52 | return conversionMultiple; 53 | } 54 | 55 | public String getExchangeEnvironmentInfo() { 56 | return exchangeEnvironmentInfo; 57 | } 58 | 59 | public void setExchangeEnvironmentInfo(String environmentInfo) { 60 | this.exchangeEnvironmentInfo = environmentInfo; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/ExchangeValueRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface ExchangeValueRepository extends JpaRepository { 6 | ExchangeValue findByFromAndTo(String from, String to); 7 | } 8 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/java/com/in28minutes/microservices/currencyexchangeservice/util/containerservice/ContainerMetaDataService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.util.containerservice; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Service 10 | public class ContainerMetaDataService { 11 | 12 | private static final String ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI = "ECS_CONTAINER_METADATA_URI"; 13 | 14 | private static final String DEFAULT_VALUE = "EMPTY"; 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ContainerMetaDataService.class); 17 | 18 | // @Value(${ENVIRONMENT_VARIABLE_NAME:DEFAULT_VALUE}) 19 | @Value("${" + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI + ":" + DEFAULT_VALUE + "}") 20 | private String containerMetadataUri; 21 | 22 | public String retrieveContainerMetadataInfo() { 23 | 24 | if (containerMetadataUri.contains(DEFAULT_VALUE)) { 25 | LOGGER.info("Environment Variable Not Available - " + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI); 26 | return "NA"; 27 | } 28 | 29 | return new RestTemplate().getForObject(containerMetadataUri, String.class); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/java/com/in28minutes/microservices/currencyexchangeservice/util/logging/EnvironmentConfigurationLogger.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.util.logging; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.StreamSupport; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.context.event.EventListener; 10 | import org.springframework.core.env.AbstractEnvironment; 11 | import org.springframework.core.env.EnumerablePropertySource; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.env.MutablePropertySources; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EnvironmentConfigurationLogger { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class); 20 | 21 | @SuppressWarnings("rawtypes") 22 | @EventListener 23 | public void handleContextRefresh(ContextRefreshedEvent event) { 24 | final Environment environment = event.getApplicationContext().getEnvironment(); 25 | LOGGER.info("====== Environment and configuration ======"); 26 | LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles())); 27 | final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources(); 28 | StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource) 29 | .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct() 30 | .forEach(prop -> LOGGER.info("{}", prop));// environment.getProperty(prop) 31 | LOGGER.info("==========================================="); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-exchange-microservice 2 | server.port=8000 3 | 4 | spring.jpa.show-sql=true 5 | #spring.h2.console.enabled=true 6 | #spring.h2.console.settings.web-allow-others=true 7 | 8 | management.endpoints.web.base-path=/manage 9 | server.servlet.context-path=/api/currency-exchange-microservice 10 | 11 | spring.jpa.hibernate.ddl-auto=update 12 | spring.datasource.url=jdbc:mysql://${RDS_HOSTNAME:localhost}:${RDS_PORT:3306}/${RDS_DB_NAME:exchange-db} 13 | spring.datasource.username=${RDS_USERNAME:exchange-db-user} 14 | spring.datasource.password=${RDS_PASSWORD:dummyexchange} 15 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/test/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyExchangeServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /04-currency-exchange-service-mysql/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.hibernate.ddl-auto=create-drop 2 | spring.datasource.driver-class-name=org.h2.Driver 3 | spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 4 | spring.datasource.username=sa 5 | spring.datasource.password=sa -------------------------------------------------------------------------------- /05-currency-conversion-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 8100 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /05-currency-conversion-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.microservices 8 | 05-aws-currency-conversion-service 9 | 0.0.1-SNAPSHOT 10 | jar 11 | 12 | aws-currency-conversion-service 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.1.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | Greenwich.RC2 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | com.h2database 42 | h2 43 | runtime 44 | 45 | 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-starter-sleuth 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-actuator 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-devtools 61 | runtime 62 | 63 | 64 | 65 | javax.xml.bind 66 | jaxb-api 67 | 68 | 69 | com.sun.xml.bind 70 | jaxb-impl 71 | 2.3.0 72 | 73 | 74 | org.glassfish.jaxb 75 | jaxb-runtime 76 | 77 | 78 | javax.activation 79 | activation 80 | 1.1.1 81 | 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-starter-test 87 | test 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.springframework.cloud 95 | spring-cloud-dependencies 96 | ${spring-cloud.version} 97 | pom 98 | import 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | org.springframework.boot 107 | spring-boot-maven-plugin 108 | 109 | 110 | 111 | com.spotify 112 | dockerfile-maven-plugin 113 | 1.4.10 114 | 115 | 116 | default 117 | 118 | build 119 | 120 | 121 | 122 | 123 | 124 | in28min/${project.name} 125 | ${project.version} 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | spring-snapshots 135 | Spring Snapshots 136 | https://repo.spring.io/snapshot 137 | 138 | true 139 | 140 | 141 | 142 | spring-milestones 143 | Spring Milestones 144 | https://repo.spring.io/milestone 145 | 146 | false 147 | 148 | 149 | 150 | 151 | 152 | 153 | spring-snapshots 154 | Spring Snapshots 155 | https://repo.spring.io/snapshot 156 | 157 | true 158 | 159 | 160 | 161 | spring-milestones 162 | Spring Milestones 163 | https://repo.spring.io/milestone 164 | 165 | false 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /05-currency-conversion-service/readme.md: -------------------------------------------------------------------------------- 1 | # Currency Conversion Micro Service 2 | 3 | Run com.in28minutes.microservices.currencyconversionservice.CurrencyConversionServiceApplication as a Java Application. 4 | 5 | ## Containerization 6 | 7 | ### Troubleshooting 8 | 9 | - Problem - Caused by: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: java.io.IOException: No such file or directory 10 | - Solution - Check if docker is up and running! 11 | - Problem - Error creating the Docker image on MacOS - java.io.IOException: Cannot run program “docker-credential-osxkeychain”: error=2, No such file or directory 12 | - Solution - https://medium.com/@dakshika/error-creating-the-docker-image-on-macos-wso2-enterprise-integrator-tooling-dfb5b537b44e 13 | 14 | ### Creating Containers 15 | 16 | - mvn package 17 | 18 | ### Running Containers 19 | 20 | ``` 21 | docker run --publish 8100:8100 --network currency-network --env CURRENCY_EXCHANGE_URI=http://currency-exchange-service:8000 in28min/aws-currency-conversion-service:0.0.1-SNAPSHOT 22 | ``` 23 | 24 | #### Test API 25 | - http://localhost:8100/api/currency-conversion-microservice/currency-converter/from/EUR/to/INR/quantity/10 26 | ``` 27 | docker login 28 | docker push @@@REPO_NAME@@@/aws-currency-conversion-service:0.0.1-SNAPSHOT 29 | ``` 30 | 31 | 32 | ## Resources 33 | 34 | - http://localhost:8100/api/currency-conversion-microservice/currency-converter/from/EUR/to/INR/quantity/10 35 | 36 | ```json 37 | { 38 | id: 10002, 39 | from: "EUR", 40 | to: "INR", 41 | conversionMultiple: 75, 42 | quantity: 10, 43 | totalCalculatedAmount: 750, 44 | exchangeEnvironmentInfo: "NA", 45 | conversionEnvironmentInfo: "NA", 46 | } 47 | ``` -------------------------------------------------------------------------------- /05-currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @SpringBootApplication 9 | public class CurrencyConversionServiceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(CurrencyConversionServiceApplication.class, args); 13 | } 14 | 15 | // Spring Cloud Sleuth uses request headers to propagate trace-id & span-id. 16 | // Creating a bean for RestTemplate allows Spring Cloud Sleuth to inject the 17 | // headers into RestTemplate. 18 | 19 | @Bean 20 | public RestTemplate getRestTemplate() { 21 | return new RestTemplate(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /05-currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/resource/CurrencyConversionBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class CurrencyConversionBean { 6 | 7 | private Long id; 8 | 9 | private String from; 10 | 11 | private String to; 12 | 13 | private BigDecimal conversionMultiple; 14 | 15 | private BigDecimal quantity; 16 | 17 | private BigDecimal totalCalculatedAmount; 18 | 19 | private String exchangeEnvironmentInfo; 20 | 21 | private String conversionEnvironmentInfo; 22 | 23 | public CurrencyConversionBean() { 24 | 25 | } 26 | 27 | public CurrencyConversionBean(Long id, String from, String to, BigDecimal conversionMultiple, BigDecimal quantity, 28 | BigDecimal totalCalculatedAmount, String exchangeEnvironmentInfo, String conversionEnvironmentInfo) { 29 | super(); 30 | this.id = id; 31 | this.from = from; 32 | this.to = to; 33 | this.conversionMultiple = conversionMultiple; 34 | this.quantity = quantity; 35 | this.totalCalculatedAmount = totalCalculatedAmount; 36 | this.exchangeEnvironmentInfo = exchangeEnvironmentInfo; 37 | this.conversionEnvironmentInfo = conversionEnvironmentInfo; 38 | } 39 | 40 | public Long getId() { 41 | return id; 42 | } 43 | 44 | public void setId(Long id) { 45 | this.id = id; 46 | } 47 | 48 | public String getFrom() { 49 | return from; 50 | } 51 | 52 | public void setFrom(String from) { 53 | this.from = from; 54 | } 55 | 56 | public String getTo() { 57 | return to; 58 | } 59 | 60 | public void setTo(String to) { 61 | this.to = to; 62 | } 63 | 64 | public BigDecimal getConversionMultiple() { 65 | return conversionMultiple; 66 | } 67 | 68 | public void setConversionMultiple(BigDecimal conversionMultiple) { 69 | this.conversionMultiple = conversionMultiple; 70 | } 71 | 72 | public BigDecimal getQuantity() { 73 | return quantity; 74 | } 75 | 76 | public void setQuantity(BigDecimal quantity) { 77 | this.quantity = quantity; 78 | } 79 | 80 | public BigDecimal getTotalCalculatedAmount() { 81 | return totalCalculatedAmount; 82 | } 83 | 84 | public void setTotalCalculatedAmount(BigDecimal totalCalculatedAmount) { 85 | this.totalCalculatedAmount = totalCalculatedAmount; 86 | } 87 | 88 | public String getExchangeEnvironmentInfo() { 89 | return exchangeEnvironmentInfo; 90 | } 91 | 92 | public void setExchangeEnvironmentInfo(String environmentInfo) { 93 | this.exchangeEnvironmentInfo = environmentInfo; 94 | } 95 | 96 | public String getConversionEnvironmentInfo() { 97 | return conversionEnvironmentInfo; 98 | } 99 | 100 | public void setConversionEnvironmentInfo(String conversionEnvironmentInfo) { 101 | this.conversionEnvironmentInfo = conversionEnvironmentInfo; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /05-currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/resource/CurrencyConversionController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RestController; 15 | import org.springframework.web.client.RestTemplate; 16 | 17 | import com.in28minutes.microservices.currencyconversionservice.util.containerservice.ContainerMetaDataService; 18 | 19 | @RestController 20 | public class CurrencyConversionController { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrencyConversionController.class); 23 | 24 | @Autowired 25 | private ContainerMetaDataService containerMetaDataService; 26 | 27 | @Value("${CURRENCY_EXCHANGE_URI:http://localhost:8000}") 28 | private String currencyExchangeHost; 29 | 30 | @Autowired 31 | private RestTemplate restTemplate; 32 | 33 | @GetMapping("/currency-converter/from/{from}/to/{to}/quantity/{quantity}") 34 | public CurrencyConversionBean convertCurrency(@PathVariable String from, @PathVariable String to, 35 | @PathVariable BigDecimal quantity) { 36 | 37 | LOGGER.info("Received Request to convert from {} {} to {} ", quantity, from, to); 38 | 39 | ResponseEntity responseEntity = restTemplate.getForEntity( 40 | currencyExchangeHost + "/api/currency-exchange-microservice/currency-exchange/from/{from}/to/{to}", 41 | CurrencyConversionBean.class, createUriVariables(from, to)); 42 | 43 | CurrencyConversionBean response = responseEntity.getBody(); 44 | 45 | BigDecimal convertedValue = quantity.multiply(response.getConversionMultiple()); 46 | 47 | String conversionEnvironmentInfo = containerMetaDataService.retrieveContainerMetadataInfo(); 48 | 49 | return new CurrencyConversionBean(response.getId(), from, to, response.getConversionMultiple(), quantity, 50 | convertedValue, response.getExchangeEnvironmentInfo(), conversionEnvironmentInfo); 51 | } 52 | 53 | private Map createUriVariables(String from, String to) { 54 | Map uriVariables = new HashMap<>(); 55 | uriVariables.put("from", from); 56 | uriVariables.put("to", to); 57 | return uriVariables; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /05-currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/util/containerservice/ContainerMetaDataService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.util.containerservice; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Service 10 | public class ContainerMetaDataService { 11 | 12 | private static final String ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI = "ECS_CONTAINER_METADATA_URI"; 13 | 14 | private static final String DEFAULT_VALUE = "EMPTY"; 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ContainerMetaDataService.class); 17 | 18 | // @Value(${ENVIRONMENT_VARIABLE_NAME:DEFAULT_VALUE}) 19 | @Value("${" + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI + ":" + DEFAULT_VALUE + "}") 20 | private String containerMetadataUri; 21 | 22 | public String retrieveContainerMetadataInfo() { 23 | 24 | if (containerMetadataUri.contains(DEFAULT_VALUE)) { 25 | LOGGER.info("Environment Variable Not Available - " + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI); 26 | return "NA"; 27 | } 28 | 29 | return new RestTemplate().getForObject(containerMetadataUri, String.class); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /05-currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/util/logging/EnvironmentConfigurationLogger.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.util.logging; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.StreamSupport; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.context.event.EventListener; 10 | import org.springframework.core.env.AbstractEnvironment; 11 | import org.springframework.core.env.EnumerablePropertySource; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.env.MutablePropertySources; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EnvironmentConfigurationLogger { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class); 20 | 21 | @SuppressWarnings("rawtypes") 22 | @EventListener 23 | public void handleContextRefresh(ContextRefreshedEvent event) { 24 | final Environment environment = event.getApplicationContext().getEnvironment(); 25 | LOGGER.info("====== Environment and configuration ======"); 26 | LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles())); 27 | final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources(); 28 | StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource) 29 | .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct() 30 | .forEach(prop -> LOGGER.info("{}", prop));// environment.getProperty(prop) 31 | LOGGER.info("==========================================="); 32 | } 33 | } -------------------------------------------------------------------------------- /05-currency-conversion-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-conversion-microservice 2 | server.port=8100 3 | 4 | management.endpoints.web.base-path=/manage 5 | server.servlet.context-path=/api/currency-conversion-microservice -------------------------------------------------------------------------------- /05-currency-conversion-service/src/test/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyConversionServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 8000 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.microservices 8 | 06-aws-currency-exchange-service-h2-xray 9 | 0.0.1-SNAPSHOT 10 | jar 11 | 12 | aws-currency-exchange-service-h2-xray 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.1.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | Greenwich.RC2 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-sleuth 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-actuator 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-devtools 54 | runtime 55 | 56 | 57 | 58 | com.h2database 59 | h2 60 | runtime 61 | 62 | 63 | 64 | com.amazonaws 65 | aws-xray-recorder-sdk-spring 66 | 2.3.0 67 | 68 | 69 | 70 | javax.xml.bind 71 | jaxb-api 72 | 73 | 74 | com.sun.xml.bind 75 | jaxb-impl 76 | 2.3.0 77 | 78 | 79 | org.glassfish.jaxb 80 | jaxb-runtime 81 | 82 | 83 | javax.activation 84 | activation 85 | 1.1.1 86 | 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-starter-test 91 | test 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.springframework.cloud 100 | spring-cloud-dependencies 101 | ${spring-cloud.version} 102 | pom 103 | import 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | org.springframework.boot 112 | spring-boot-maven-plugin 113 | 114 | 115 | 116 | com.spotify 117 | dockerfile-maven-plugin 118 | 1.4.10 119 | 120 | 121 | default 122 | 123 | build 124 | 125 | 126 | 127 | 128 | 129 | in28min/${project.name} 130 | ${project.version} 131 | true 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | spring-snapshots 140 | Spring Snapshots 141 | https://repo.spring.io/snapshot 142 | 143 | true 144 | 145 | 146 | 147 | spring-milestones 148 | Spring Milestones 149 | https://repo.spring.io/milestone 150 | 151 | false 152 | 153 | 154 | 155 | 156 | 157 | 158 | spring-snapshots 159 | Spring Snapshots 160 | https://repo.spring.io/snapshot 161 | 162 | true 163 | 164 | 165 | 166 | spring-milestones 167 | Spring Milestones 168 | https://repo.spring.io/milestone 169 | 170 | false 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/readme.md: -------------------------------------------------------------------------------- 1 | # Currency Exchange Micro Service - H2 with XRay 2 | 3 | Run com.in28minutes.microservices.currencyconversionservice.CurrencyConversionServiceApplicationH2 as a Java Application. 4 | 5 | 6 | ## Changes from H2 Application 7 | 8 | - pom.xml - aws-xray-recorder-sdk-spring 9 | - AwsXrayConfig.java 10 | - XRayInspector.java 11 | - CurrencyExchangeController.java 12 | 13 | ``` 14 | @RestController 15 | @XRayEnabled 16 | public class CurrencyExchangeController { 17 | ``` 18 | 19 | ## XRay Daemon 20 | 21 | - amazon/aws-xray-daemon:1 22 | 23 | 24 | ## Containerization 25 | 26 | ### Troubleshooting 27 | 28 | - Problem - Caused by: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: java.io.IOException: No such file or directory 29 | - Solution - Check if docker is up and running! 30 | - Problem - Error creating the Docker image on MacOS - java.io.IOException: Cannot run program “docker-credential-osxkeychain”: error=2, No such file or directory 31 | - Solution - https://medium.com/@dakshika/error-creating-the-docker-image-on-macos-wso2-enterprise-integrator-tooling-dfb5b537b44e 32 | 33 | ### Running Containers 34 | 35 | - mvn package 36 | - docker run --publish 8000:8000 --network MY_BRIDGE --name currency-exchange-microservice in28min/aws-currency-exchange-service-h2-xray:0.0.1-SNAPSHOT 37 | 38 | Test API 39 | - http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/USD/to/INR 40 | 41 | ``` 42 | docker login 43 | docker push @@@REPO_NAME@@@/aws-currency-exchange-service-h2-xray:0.0.1-SNAPSHOT 44 | ``` 45 | 46 | ## Resources 47 | 48 | - http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/USD/to/INR 49 | 50 | ```json 51 | { 52 | "id": 10001, 53 | "from": "USD", 54 | "to": "INR", 55 | "conversionMultiple": 65.00, 56 | "environmentInfo": "NA" 57 | } 58 | ``` 59 | 60 | ## H2 Console 61 | 62 | - http://localhost:8000/h2-console 63 | - Use `jdbc:h2:mem:testdb` as JDBC URL 64 | 65 | 66 | ## Tables Created 67 | ``` 68 | create table exchange_value 69 | ( 70 | id bigint not null, 71 | conversion_multiple decimal(19,2), 72 | currency_from varchar(255), 73 | currency_to varchar(255), 74 | primary key (id) 75 | ) 76 | ``` 77 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationH2.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CurrencyExchangeServiceApplicationH2 { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CurrencyExchangeServiceApplicationH2.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/CurrencyExchangeController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import java.util.Map; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestHeader; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.amazonaws.xray.spring.aop.XRayEnabled; 14 | import com.in28minutes.microservices.currencyexchangeservice.util.containerservice.ContainerMetaDataService; 15 | 16 | @RestController 17 | @XRayEnabled 18 | public class CurrencyExchangeController { 19 | 20 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrencyExchangeController.class); 21 | 22 | @Autowired 23 | private ExchangeValueRepository repository; 24 | 25 | @Autowired 26 | private ContainerMetaDataService containerMetaDataService; 27 | 28 | @GetMapping("/currency-exchange/from/{from}/to/{to}") 29 | public ExchangeValue retrieveExchangeValue(@PathVariable String from, @PathVariable String to, 30 | @RequestHeader Map headers) { 31 | 32 | printAllHeaders(headers); 33 | 34 | ExchangeValue exchangeValue = repository.findByFromAndTo(from, to); 35 | 36 | LOGGER.info("{} {} {}", from, to, exchangeValue); 37 | 38 | if (exchangeValue == null) { 39 | throw new RuntimeException("Unable to find data to convert " + from + " to " + to); 40 | } 41 | 42 | exchangeValue.setExchangeEnvironmentInfo(containerMetaDataService.retrieveContainerMetadataInfo()); 43 | 44 | return exchangeValue; 45 | } 46 | 47 | private void printAllHeaders(Map headers) { 48 | headers.forEach((key, value) -> { 49 | LOGGER.info(String.format("Header '%s' = %s", key, value)); 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/ExchangeValue.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.Id; 8 | import javax.persistence.Transient; 9 | 10 | @Entity 11 | public class ExchangeValue { 12 | 13 | @Id 14 | private Long id; 15 | 16 | @Column(name = "currency_from") 17 | private String from; 18 | 19 | @Column(name = "currency_to") 20 | private String to; 21 | 22 | private BigDecimal conversionMultiple; 23 | 24 | @Transient 25 | private String exchangeEnvironmentInfo; 26 | 27 | public ExchangeValue() { 28 | 29 | } 30 | 31 | public ExchangeValue(Long id, String from, String to, BigDecimal conversionMultiple) { 32 | super(); 33 | this.id = id; 34 | this.from = from; 35 | this.to = to; 36 | this.conversionMultiple = conversionMultiple; 37 | } 38 | 39 | public Long getId() { 40 | return id; 41 | } 42 | 43 | public String getFrom() { 44 | return from; 45 | } 46 | 47 | public String getTo() { 48 | return to; 49 | } 50 | 51 | public BigDecimal getConversionMultiple() { 52 | return conversionMultiple; 53 | } 54 | 55 | public String getExchangeEnvironmentInfo() { 56 | return exchangeEnvironmentInfo; 57 | } 58 | 59 | public void setExchangeEnvironmentInfo(String environmentInfo) { 60 | this.exchangeEnvironmentInfo = environmentInfo; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/resource/ExchangeValueRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.resource; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface ExchangeValueRepository extends JpaRepository { 6 | ExchangeValue findByFromAndTo(String from, String to); 7 | } 8 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/util/containerservice/ContainerMetaDataService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.util.containerservice; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Service 10 | public class ContainerMetaDataService { 11 | 12 | private static final String ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI = "ECS_CONTAINER_METADATA_URI"; 13 | 14 | private static final String DEFAULT_VALUE = "EMPTY"; 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ContainerMetaDataService.class); 17 | 18 | // @Value(${ENVIRONMENT_VARIABLE_NAME:DEFAULT_VALUE}) 19 | @Value("${" + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI + ":" + DEFAULT_VALUE + "}") 20 | private String containerMetadataUri; 21 | 22 | public String retrieveContainerMetadataInfo() { 23 | 24 | if (containerMetadataUri.contains(DEFAULT_VALUE)) { 25 | LOGGER.info("Environment Variable Not Available - " + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI); 26 | return "NA"; 27 | } 28 | 29 | return new RestTemplate().getForObject(containerMetadataUri, String.class); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/util/logging/EnvironmentConfigurationLogger.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.util.logging; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.StreamSupport; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.context.event.EventListener; 10 | import org.springframework.core.env.AbstractEnvironment; 11 | import org.springframework.core.env.EnumerablePropertySource; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.env.MutablePropertySources; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EnvironmentConfigurationLogger { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class); 20 | 21 | @SuppressWarnings("rawtypes") 22 | @EventListener 23 | public void handleContextRefresh(ContextRefreshedEvent event) { 24 | final Environment environment = event.getApplicationContext().getEnvironment(); 25 | LOGGER.info("====== Environment and configuration ======"); 26 | LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles())); 27 | final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources(); 28 | StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource) 29 | .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct() 30 | .forEach(prop -> LOGGER.info("{}", prop));// environment.getProperty(prop) 31 | LOGGER.info("==========================================="); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/xray/AwsXrayConfig.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.xray; 2 | 3 | import javax.servlet.Filter; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; 9 | 10 | @Configuration 11 | public class AwsXrayConfig { 12 | 13 | @Bean 14 | public Filter TracingFilter() { 15 | return new AWSXRayServletFilter("currency-exchange-service"); 16 | } 17 | } -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/java/com/in28minutes/microservices/currencyexchangeservice/xray/XRayInspector.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice.xray; 2 | 3 | import java.util.Map; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.aspectj.lang.annotation.Pointcut; 8 | import org.springframework.stereotype.Component; 9 | 10 | import com.amazonaws.xray.entities.Subsegment; 11 | import com.amazonaws.xray.spring.aop.AbstractXRayInterceptor; 12 | 13 | @Aspect 14 | @Component 15 | public class XRayInspector extends AbstractXRayInterceptor { 16 | @Override 17 | protected Map> generateMetadata(ProceedingJoinPoint proceedingJoinPoint, 18 | Subsegment subsegment) { 19 | return super.generateMetadata(proceedingJoinPoint, subsegment); 20 | } 21 | 22 | @Override 23 | @Pointcut("@within(com.amazonaws.xray.spring.aop.XRayEnabled) && bean(*)") 24 | public void xrayEnabledClasses() { 25 | } 26 | } -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-exchange-microservice 2 | server.port=8000 3 | 4 | spring.jpa.show-sql=true 5 | spring.h2.console.enabled=true 6 | 7 | management.endpoints.web.base-path=/manage 8 | server.servlet.context-path=/api/currency-exchange-microservice -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple) 2 | values(10001,'USD','INR',65); 3 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple) 4 | values(10002,'EUR','INR',75); 5 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple) 6 | values(10003,'AUD','INR',25); -------------------------------------------------------------------------------- /06-currency-exchange-service-h2-xray/src/test/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyExchangeServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 8100 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.microservices 8 | 07-aws-currency-conversion-service-xray 9 | 0.0.1-SNAPSHOT 10 | jar 11 | 12 | aws-currency-conversion-service-xray 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.1.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | Greenwich.RC2 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | com.h2database 42 | h2 43 | runtime 44 | 45 | 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-starter-sleuth 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-actuator 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-devtools 61 | runtime 62 | 63 | 64 | 65 | com.amazonaws 66 | aws-xray-recorder-sdk-spring 67 | 2.3.0 68 | 69 | 70 | 71 | com.amazonaws 72 | aws-xray-recorder-sdk-apache-http 73 | 2.3.0 74 | 75 | 76 | 77 | 78 | javax.xml.bind 79 | jaxb-api 80 | 81 | 82 | com.sun.xml.bind 83 | jaxb-impl 84 | 2.3.0 85 | 86 | 87 | org.glassfish.jaxb 88 | jaxb-runtime 89 | 90 | 91 | javax.activation 92 | activation 93 | 1.1.1 94 | 95 | 96 | 97 | 98 | org.springframework.boot 99 | spring-boot-starter-test 100 | test 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.springframework.cloud 108 | spring-cloud-dependencies 109 | ${spring-cloud.version} 110 | pom 111 | import 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | org.springframework.boot 120 | spring-boot-maven-plugin 121 | 122 | 123 | 124 | com.spotify 125 | dockerfile-maven-plugin 126 | 1.4.10 127 | 128 | 129 | default 130 | 131 | build 132 | 133 | 134 | 135 | 136 | 137 | in28min/${project.name} 138 | ${project.version} 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | spring-snapshots 148 | Spring Snapshots 149 | https://repo.spring.io/snapshot 150 | 151 | true 152 | 153 | 154 | 155 | spring-milestones 156 | Spring Milestones 157 | https://repo.spring.io/milestone 158 | 159 | false 160 | 161 | 162 | 163 | 164 | 165 | 166 | spring-snapshots 167 | Spring Snapshots 168 | https://repo.spring.io/snapshot 169 | 170 | true 171 | 172 | 173 | 174 | spring-milestones 175 | Spring Milestones 176 | https://repo.spring.io/milestone 177 | 178 | false 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/readme.md: -------------------------------------------------------------------------------- 1 | # Currency Conversion Micro Service 2 | 3 | Run com.in28minutes.microservices.currencyconversionservice.CurrencyConversionServiceApplication as a Java Application. 4 | 5 | ## Changes for X Ray 6 | 7 | - pom.xml - aws-xray-recorder-sdk-spring & aws-xray-recorder-sdk-apache-http 8 | - AwsXrayConfig.java 9 | - XRayInspector.java 10 | - CurrencyConversionServiceApplication.java 11 | 12 | ``` 13 | @Bean 14 | public RestTemplate restTemplate() { 15 | // return new RestTemplate(); 16 | return new RestTemplate(clientHttpRequestFactory()); 17 | 18 | } 19 | 20 | private ClientHttpRequestFactory clientHttpRequestFactory() { 21 | HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( 22 | HttpClientBuilder.create().useSystemProperties().build()); 23 | factory.setReadTimeout(10000); 24 | factory.setConnectTimeout(2000); 25 | factory.setConnectionRequestTimeout(2000); 26 | return factory; 27 | } 28 | 29 | ``` 30 | 31 | 32 | - CurrencyConversionController.java 33 | 34 | ``` 35 | @RestController 36 | @XRayEnabled 37 | public class CurrencyConversionController { 38 | ``` 39 | 40 | ## XRay Daemon 41 | 42 | - amazon/aws-xray-daemon:1 43 | 44 | 45 | ## Containerization 46 | 47 | ### Troubleshooting 48 | 49 | - Problem - Caused by: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: java.io.IOException: No such file or directory 50 | - Solution - Check if docker is up and running! 51 | - Problem - Error creating the Docker image on MacOS - java.io.IOException: Cannot run program “docker-credential-osxkeychain”: error=2, No such file or directory 52 | - Solution - https://medium.com/@dakshika/error-creating-the-docker-image-on-macos-wso2-enterprise-integrator-tooling-dfb5b537b44e 53 | 54 | ### Creating Containers 55 | 56 | - mvn package 57 | - docker run --publish 8100:8100 --network MY_BRIDGE --env CURRENCY_EXCHANGE_URI=http://currency-exchange-microservice:8000 in28min/aws-currency-conversion-service-xray:0.0.1-SNAPSHOT 58 | 59 | 60 | 61 | Test API 62 | - http://localhost:8100/api/currency-conversion-microservice/currency-converter/from/USD/to/INR/quantity/1000 63 | - http://localhost:8100/api/currency-conversion-microservice/currency-converter-feign/from/USD/to/INR/quantity/10000 64 | 65 | ``` 66 | docker login 67 | docker push @@REPO@@/aws-currency-conversion-service-xray:0.0.1-SNAPSHOT 68 | ``` 69 | 70 | 71 | ## Resources 72 | 73 | - http://localhost:8100/api/currency-conversion-microservice/currency-converter-feign/from/USD/to/INR/quantity/10000 74 | 75 | ```json 76 | { 77 | "id": 10001, 78 | "from": "USD", 79 | "to": "INR", 80 | "conversionMultiple": 65.00, 81 | "quantity": 1000, 82 | "totalCalculatedAmount": 65000.00, 83 | "environmentInfo": "NA" 84 | } 85 | ``` -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.http.client.ClientHttpRequestFactory; 7 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; 8 | import org.springframework.web.client.RestTemplate; 9 | 10 | import com.amazonaws.xray.proxies.apache.http.HttpClientBuilder; 11 | 12 | @SpringBootApplication 13 | public class CurrencyConversionServiceApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(CurrencyConversionServiceApplication.class, args); 17 | } 18 | 19 | @Bean 20 | public RestTemplate restTemplate() { 21 | // return new RestTemplate(); 22 | return new RestTemplate(clientHttpRequestFactory()); 23 | 24 | } 25 | 26 | private ClientHttpRequestFactory clientHttpRequestFactory() { 27 | HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( 28 | HttpClientBuilder.create().useSystemProperties().build()); 29 | factory.setReadTimeout(10000); 30 | factory.setConnectTimeout(2000); 31 | factory.setConnectionRequestTimeout(2000); 32 | return factory; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/resource/CurrencyConversionBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class CurrencyConversionBean { 6 | 7 | private Long id; 8 | 9 | private String from; 10 | 11 | private String to; 12 | 13 | private BigDecimal conversionMultiple; 14 | 15 | private BigDecimal quantity; 16 | 17 | private BigDecimal totalCalculatedAmount; 18 | 19 | private String exchangeEnvironmentInfo; 20 | 21 | private String conversionEnvironmentInfo; 22 | 23 | public CurrencyConversionBean() { 24 | 25 | } 26 | 27 | public CurrencyConversionBean(Long id, String from, String to, BigDecimal conversionMultiple, BigDecimal quantity, 28 | BigDecimal totalCalculatedAmount, String exchangeEnvironmentInfo, String conversionEnvironmentInfo) { 29 | super(); 30 | this.id = id; 31 | this.from = from; 32 | this.to = to; 33 | this.conversionMultiple = conversionMultiple; 34 | this.quantity = quantity; 35 | this.totalCalculatedAmount = totalCalculatedAmount; 36 | this.exchangeEnvironmentInfo = exchangeEnvironmentInfo; 37 | this.conversionEnvironmentInfo = conversionEnvironmentInfo; 38 | } 39 | 40 | public Long getId() { 41 | return id; 42 | } 43 | 44 | public void setId(Long id) { 45 | this.id = id; 46 | } 47 | 48 | public String getFrom() { 49 | return from; 50 | } 51 | 52 | public void setFrom(String from) { 53 | this.from = from; 54 | } 55 | 56 | public String getTo() { 57 | return to; 58 | } 59 | 60 | public void setTo(String to) { 61 | this.to = to; 62 | } 63 | 64 | public BigDecimal getConversionMultiple() { 65 | return conversionMultiple; 66 | } 67 | 68 | public void setConversionMultiple(BigDecimal conversionMultiple) { 69 | this.conversionMultiple = conversionMultiple; 70 | } 71 | 72 | public BigDecimal getQuantity() { 73 | return quantity; 74 | } 75 | 76 | public void setQuantity(BigDecimal quantity) { 77 | this.quantity = quantity; 78 | } 79 | 80 | public BigDecimal getTotalCalculatedAmount() { 81 | return totalCalculatedAmount; 82 | } 83 | 84 | public void setTotalCalculatedAmount(BigDecimal totalCalculatedAmount) { 85 | this.totalCalculatedAmount = totalCalculatedAmount; 86 | } 87 | 88 | public String getExchangeEnvironmentInfo() { 89 | return exchangeEnvironmentInfo; 90 | } 91 | 92 | public void setExchangeEnvironmentInfo(String environmentInfo) { 93 | this.exchangeEnvironmentInfo = environmentInfo; 94 | } 95 | 96 | public String getConversionEnvironmentInfo() { 97 | return conversionEnvironmentInfo; 98 | } 99 | 100 | public void setConversionEnvironmentInfo(String conversionEnvironmentInfo) { 101 | this.conversionEnvironmentInfo = conversionEnvironmentInfo; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/resource/CurrencyConversionController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.resource; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RestController; 15 | import org.springframework.web.client.RestTemplate; 16 | 17 | import com.amazonaws.xray.spring.aop.XRayEnabled; 18 | import com.in28minutes.microservices.currencyconversionservice.util.containerservice.ContainerMetaDataService; 19 | 20 | @RestController 21 | @XRayEnabled 22 | public class CurrencyConversionController { 23 | 24 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrencyConversionController.class); 25 | 26 | @Autowired 27 | private ContainerMetaDataService containerMetaDataService; 28 | 29 | @Value("${CURRENCY_EXCHANGE_URI:http://localhost:8000}") 30 | private String currencyExchangeHost; 31 | 32 | @Autowired 33 | private RestTemplate restTemplate; 34 | 35 | @GetMapping("/currency-converter/from/{from}/to/{to}/quantity/{quantity}") 36 | public CurrencyConversionBean convertCurrency(@PathVariable String from, @PathVariable String to, 37 | @PathVariable BigDecimal quantity) { 38 | 39 | LOGGER.info("Received Request to convert from {} {} to {} ", quantity, from, to); 40 | 41 | ResponseEntity responseEntity = restTemplate.getForEntity( 42 | currencyExchangeHost + "/api/currency-exchange-microservice/currency-exchange/from/{from}/to/{to}", 43 | CurrencyConversionBean.class, createUriVariables(from, to)); 44 | 45 | CurrencyConversionBean response = responseEntity.getBody(); 46 | 47 | BigDecimal convertedValue = quantity.multiply(response.getConversionMultiple()); 48 | 49 | String conversionEnvironmentInfo = containerMetaDataService.retrieveContainerMetadataInfo(); 50 | 51 | return new CurrencyConversionBean(response.getId(), from, to, response.getConversionMultiple(), quantity, 52 | convertedValue, response.getExchangeEnvironmentInfo(), conversionEnvironmentInfo); 53 | } 54 | 55 | private Map createUriVariables(String from, String to) { 56 | Map uriVariables = new HashMap<>(); 57 | uriVariables.put("from", from); 58 | uriVariables.put("to", to); 59 | return uriVariables; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/util/containerservice/ContainerMetaDataService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.util.containerservice; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Service 10 | public class ContainerMetaDataService { 11 | 12 | private static final String ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI = "ECS_CONTAINER_METADATA_URI"; 13 | 14 | private static final String DEFAULT_VALUE = "EMPTY"; 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ContainerMetaDataService.class); 17 | 18 | // @Value(${ENVIRONMENT_VARIABLE_NAME:DEFAULT_VALUE}) 19 | @Value("${" + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI + ":" + DEFAULT_VALUE + "}") 20 | private String containerMetadataUri; 21 | 22 | public String retrieveContainerMetadataInfo() { 23 | 24 | if (containerMetadataUri.contains(DEFAULT_VALUE)) { 25 | LOGGER.info("Environment Variable Not Available - " + ENVIRONMENT_VARIABLE_ECS_CONTAINER_METADATA_URI); 26 | return "NA"; 27 | } 28 | 29 | return new RestTemplate().getForObject(containerMetadataUri, String.class); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/util/logging/EnvironmentConfigurationLogger.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.util.logging; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.StreamSupport; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.context.event.EventListener; 10 | import org.springframework.core.env.AbstractEnvironment; 11 | import org.springframework.core.env.EnumerablePropertySource; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.env.MutablePropertySources; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EnvironmentConfigurationLogger { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class); 20 | 21 | @SuppressWarnings("rawtypes") 22 | @EventListener 23 | public void handleContextRefresh(ContextRefreshedEvent event) { 24 | final Environment environment = event.getApplicationContext().getEnvironment(); 25 | LOGGER.info("====== Environment and configuration ======"); 26 | LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles())); 27 | final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources(); 28 | StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource) 29 | .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct() 30 | .forEach(prop -> LOGGER.info("{}", prop));// environment.getProperty(prop) 31 | LOGGER.info("==========================================="); 32 | } 33 | } -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/xray/AwsXrayConfig.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.xray; 2 | 3 | import javax.servlet.Filter; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; 9 | 10 | @Configuration 11 | public class AwsXrayConfig { 12 | 13 | @Bean 14 | public Filter TracingFilter() { 15 | return new AWSXRayServletFilter("currency-conversion-service"); 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/java/com/in28minutes/microservices/currencyconversionservice/xray/XRayInspector.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice.xray; 2 | 3 | import java.util.Map; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.aspectj.lang.annotation.Pointcut; 8 | import org.springframework.stereotype.Component; 9 | 10 | import com.amazonaws.xray.entities.Subsegment; 11 | import com.amazonaws.xray.spring.aop.AbstractXRayInterceptor; 12 | 13 | @Aspect 14 | @Component 15 | public class XRayInspector extends AbstractXRayInterceptor { 16 | @Override 17 | protected Map> generateMetadata(ProceedingJoinPoint proceedingJoinPoint, 18 | Subsegment subsegment) { 19 | return super.generateMetadata(proceedingJoinPoint, subsegment); 20 | } 21 | 22 | @Override 23 | @Pointcut("@within(com.amazonaws.xray.spring.aop.XRayEnabled) && bean(*)") 24 | public void xrayEnabledClasses() { 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-conversion-microservice 2 | server.port=8100 3 | 4 | management.endpoints.web.base-path=/manage 5 | server.servlet.context-path=/api/currency-conversion-microservice -------------------------------------------------------------------------------- /07-currency-conversion-service-xray/src/test/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyConversionServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | EXPOSE 80 4 | ADD target/*.jar app.jar 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/appspec.yaml: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | Resources: 3 | - TargetService: 4 | Type: AWS::ECS::Service 5 | Properties: 6 | TaskDefinition: "arn:aws:ecs:us-east-1:183686979203:task-definition/aws-hello-world-rest-api:1" 7 | LoadBalancerInfo: 8 | ContainerName: "aws-hello-world-rest-api" 9 | ContainerPort: "80" 10 | PlatformVersion: "LATEST" -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/buildspec.yaml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | install: 4 | runtime-versions: 5 | java: corretto8 6 | pre_build: 7 | commands: 8 | - echo Logging in to Amazon ECR... 9 | - aws --version 10 | - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com 11 | - TAG="$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | head -c 8)" 12 | - IMAGE_URI=${REPOSITORY_URI}:${TAG} 13 | build: 14 | commands: 15 | - echo Build started on `date` 16 | - echo $IMAGE_URI 17 | - mvn clean package -Ddockerfile.skip 18 | - docker build --tag $IMAGE_URI . 19 | post_build: 20 | commands: 21 | - printenv 22 | - echo Build completed on `date` 23 | - echo $(docker images) 24 | - echo Pushing docker image 25 | - docker push $IMAGE_URI 26 | - echo push completed 27 | - printf '[{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME $IMAGE_URI > imagedefinitions.json 28 | artifacts: 29 | files: 30 | - imagedefinitions.json 31 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.in28minutes.rest.webservices 8 | 08-aws-hello-world-rest-api-pipeline 9 | 0.0.1-SNAPSHOT 10 | jar 11 | Demo project for Spring Boot 12 | aws-hello-world-rest-api-pipeline 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-devtools 37 | runtime 38 | 39 | 40 | 41 | javax.xml.bind 42 | jaxb-api 43 | 44 | 45 | com.sun.xml.bind 46 | jaxb-impl 47 | 2.3.0 48 | 49 | 50 | org.glassfish.jaxb 51 | jaxb-runtime 52 | 53 | 54 | javax.activation 55 | activation 56 | 1.1.1 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter-test 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | com.spotify 75 | dockerfile-maven-plugin 76 | 1.4.10 77 | 78 | 79 | default 80 | 81 | build 82 | 83 | 84 | 85 | 86 | 87 | in28min/${project.name} 88 | ${project.version} 89 | true 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | spring-snapshots 98 | Spring Snapshots 99 | https://repo.spring.io/snapshot 100 | 101 | true 102 | 103 | 104 | 105 | spring-milestones 106 | Spring Milestones 107 | https://repo.spring.io/milestone 108 | 109 | false 110 | 111 | 112 | 113 | 114 | 115 | 116 | spring-snapshots 117 | Spring Snapshots 118 | https://repo.spring.io/snapshot 119 | 120 | true 121 | 122 | 123 | 124 | spring-milestones 125 | Spring Milestones 126 | https://repo.spring.io/milestone 127 | 128 | false 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/readme.md: -------------------------------------------------------------------------------- 1 | # Hello World Rest API 2 | 3 | - Main class com.in28minutes.rest.webservices.restfulwebservices.RestfulWebServicesApplication 4 | - You cannot run this app on local as it is configured to run on port 80 - https://serverfault.com/questions/112795/how-to-run-a-server-on-port-80-as-a-normal-user-on-linux. You can run it as a docker container as shown below 5 | 6 | 7 | ### Creating Containers 8 | 9 | - mvn clean package 10 | - docker run --publish 8200:80 in28min/aws-hello-world-rest-api:0.0.1-SNAPSHOT 11 | 12 | ``` 13 | docker login 14 | docker push @@REPO@@/aws-hello-world-rest-api:0.0.1-SNAPSHOT 15 | ``` 16 | 17 | ## Test URLs 18 | 19 | - http://localhost:8200/hello-world 20 | 21 | ```txt 22 | Hello World 23 | ``` 24 | 25 | - http://localhost:8200/hello-world-bean 26 | 27 | ```json 28 | {"message":"Hello World - Changed"} 29 | ``` 30 | 31 | - http://localhost:8200/hello-world/path-variable/in28minutes 32 | 33 | ```json 34 | {"message":"Hello World, in28minutes"} 35 | ``` 36 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | public class HelloWorldBean { 4 | 5 | private String message; 6 | 7 | public HelloWorldBean(String message) { 8 | this.message = message; 9 | } 10 | 11 | public String getMessage() { 12 | return message; 13 | } 14 | 15 | public void setMessage(String message) { 16 | this.message = message; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return String.format("HelloWorldBean [message=%s]", message); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.PathVariable; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class HelloWorldController { 9 | 10 | @GetMapping(path = "/hello-world") 11 | public String helloWorld() { 12 | return "Hello World"; 13 | } 14 | 15 | @GetMapping(path = "/hello-world-bean") 16 | public HelloWorldBean helloWorldBean() { 17 | return new HelloWorldBean("Hello World - Changed - V2"); 18 | } 19 | 20 | @GetMapping(path = "/hello-world/path-variable/{name}") 21 | public HelloWorldBean helloWorldPathVariable(@PathVariable String name) { 22 | return new HelloWorldBean(String.format("Hello World, %s", name)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestfulWebServicesApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestfulWebServicesApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=80 -------------------------------------------------------------------------------- /08-hello-world-rest-api-code-pipeline/src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestfulWebServicesApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deploy Spring Boot and Docker Microservices to AWS using ECS and AWS Fargate 2 | 3 | [![Image](https://www.springboottutorial.com/images/Course-Deploy-Java-Spring-Boot-Microservices-To-ECS.png "Deploying Spring Boot Microservices to AWS using ECS and AWS Fargate")](https://www.udemy.com/course/deploy-spring-microservices-to-aws-with-ecs-and-aws-fargate/) 4 | 5 | 6 | ## Learn Amazon Web Services - AWS - deploying Spring Boot and Docker Microservices to AWS Fargate. Implement Service Discovery, Load Balancing, Auto Discovery, Centralized Configuration and Distributed Tracing in AWS. 7 | 8 | Spring Boot is the No 1 Java Framework to develop REST API and Microservices. AWS (Amazon Web Services) is the No 1 Cloud Service Provider today. 9 | 10 | How about learning AWS by deploying Spring Boot Docker Containers to Amazon Web Services using Elastic Container Service - ECS and AWS Fargate? 11 | 12 | ## Getting Started 13 | 14 | - [Video - Docker in 5 Steps](https://youtu.be/Rt5G5Gj7RP0) 15 | - [Video - Spring in 10 Steps](https://www.youtube.com/watch?v=edgZo2g-LTM) 16 | - [Video - Spring Boot in 10 Steps](https://www.youtube.com/watch?v=pcdpk3Yd1EA) 17 | - [Video - JPA/Hibernate in 10 Steps](https://www.youtube.com/watch?v=MaI0_XdpdP8) 18 | - [AWS Code Pipeline Github Repo](https://github.com/in28minutes/hello-world-rest-api-aws-ecs-codepipeline) 19 | 20 | ## Container Images 21 | 22 | | Application | Container | 23 | | ------------------------------- | --------------------------------------------- | 24 | | Hello World | in28min/aws-hello-world-rest-api:1.0.0-RELEASE | 25 | | Simple Task | in28min/aws-simple-spring-task:1.0.0-RELEASE | 26 | | CurrencyExchangeMicroservice-H2 | in28min/aws-currency-exchange-service-h2:0.0.1-SNAPSHOT | 27 | | CurrencyExchangeMicroservice-H2 - V2 | in28min/aws-currency-exchange-service-h2:1.0.1-RELEASE| 28 | | CurrencyExchangeMicroSevice-MySQL| in28min/aws-currency-exchange-service-mysql:0.0.1-SNAPSHOT| 29 | | CurrencyConversionMicroservice | in28min/aws-currency-conversion-service:0.0.1-SNAPSHOT | 30 | | Currency Exchange - X Ray | in28min/aws-currency-exchange-service-h2-xray:0.0.1-SNAPSHOT| 31 | | Currency Conversion - X Ray | in28min/aws-currency-conversion-service-xray:0.0.1-SNAPSHOT| 32 | 33 | | Utility | Container Image | 34 | | ------------- | ------------------------- | 35 | | aws-xray-daemon| amazon/aws-xray-daemon:1| 36 | 37 | ## Microservice URLs and Details 38 | 39 | ### Currency Exchange Service 40 | 41 | - PORT - 8000 42 | - URL - `http://localhost:8000/api/currency-exchange-microservice/currency-exchange/from/EUR/to/INR` 43 | - HEALTH URL - `http://localhost:8000/api/currency-exchange-microservice/manage/health` 44 | - Enviroment Variables 45 | - SSM URN - `arn:aws:ssm:us-east-1::parameter/` 46 | - /dev/currency-exchange-service/RDS_DB_NAME - exchange_db 47 | - /dev/currency-exchange-service/RDS_HOSTNAME 48 | - /dev/currency-exchange-service/RDS_PASSWORD 49 | - /dev/currency-exchange-service/RDS_PORT - 3306 50 | - /dev/currency-exchange-service/RDS_USERNAME - exchange_db_user 51 | 52 | ### Currency Conversion Service 53 | 54 | - PORT - 8100 55 | - URL - `http://localhost:8100/api/currency-conversion-microservice/currency-converter/from/USD/to/INR/quantity/10` 56 | - HEALTH URL - `http://localhost:8100/api/currency-conversion-microservice/manage/health` 57 | - Enviroment Variables 58 | - SSM URN - `arn:aws:ssm:us-east-1::parameter/` 59 | - /dev/currency-conversion-service/CURRENCY_EXCHANGE_URI 60 | 61 | ## Enviroment Variables 62 | 63 | SSM URN - `arn:aws:ssm:us-east-1::parameter/` 64 | 65 | - /dev/currency-conversion-service/CURRENCY_EXCHANGE_URI 66 | - /dev/currency-exchange-service/RDS_DB_NAME - exchange_db 67 | - /dev/currency-exchange-service/RDS_HOSTNAME 68 | - /dev/currency-exchange-service/RDS_PASSWORD 69 | - /dev/currency-exchange-service/RDS_PORT - 3306 70 | - /dev/currency-exchange-service/RDS_USERNAME - exchange_db_user 71 | 72 | ## Setting up App Mesh 73 | 74 | #### Virtual nodes 75 | - currency-exchange-service-vn - currency-exchange-service.in28minutes-dev.com 76 | - currency-conversion-service-vn - currency-conversion-service.in28minutes-dev.com 77 | 78 | #### Virtual services 79 | - currency-exchange-service.in28minutes-dev.com -> currency-exchange-service-vn 80 | - currency-conversion-service.in28minutes-dev.com -> currency-conversion-service-vn 81 | 82 | #### Backend Registration 83 | - currency-conversion-service-vn -> currency-exchange-service.in28minutes-dev.com 84 | 85 | #### Task Definition Updates 86 | - aws-currency-conversion-service 87 | - aws-currency-exchange-service-h2 88 | - ```ENVOY_LOG_LEVEL-trace, ENABLE_ENVOY_XRAY_TRACING-1``` 89 | 90 | #### Service Updates 91 | - aws-currency-conversion-service-appmesh 92 | - aws-currency-exchange-service-appmesh 93 | 94 | ## Deploying Version 2 of Currency Exchange Service to ECS and App Mesh 95 | 96 | #### App Mesh - New Virtual Node 97 | currency-exchange-service-v2-vn - currency-exchange-service-v2.in28minutes-dev.com 98 | 99 | #### ECS Fargate - Update Task Definition 100 | aws-currency-exchange-service-h2 101 | - in28min/aws-currency-exchange-service-h2:1.0.1-RELEASE 102 | - Use New Virtual Node 103 | 104 | #### ECS Fargate - Create New Service 105 | aws-currency-exchange-service-v2-appmesh 106 | - Service Discovery - currency-exchange-service-v2 107 | 108 | #### App Mesh - Create Virtual Router 109 | currency-exchange-service-vr distributing traffic to 110 | - currency-exchange-service-vn 111 | - currency-exchange-service-v2-vn 112 | 113 | #### App Mesh - Update Service to Use Virtual Router 114 | currency-exchange-service.in28minutes-dev.com -> currency-exchange-service-vr 115 | 116 | 117 | #### jq 118 | 119 | ``` 120 | sudo yum install jq 121 | ``` 122 | 123 | #### AWS CLI Hosted Zones 124 | 125 | ``` 126 | aws --version 127 | aws configure 128 | aws servicediscovery list-services 129 | aws servicediscovery delete-service --id={id} 130 | aws servicediscovery list-services 131 | 132 | aws servicediscovery list-namespaces 133 | aws servicediscovery delete-namespace --id={id} 134 | aws servicediscovery list-namespaces 135 | 136 | aws servicediscovery delete-service --id=srv-7q3fkztnbo6aa5kc 137 | aws servicediscovery delete-service --id=srv-mdybugm4bh5u4ugx 138 | aws servicediscovery delete-service --id=srv-7upzjx3mhfleyfoz 139 | aws servicediscovery delete-namespace --id=ns-ctvtysasurklojm3 140 | ``` 141 | 142 | ## Installation Guides 143 | 144 | #### Required Tools 145 | 146 | - Java 8+ 147 | - Eclipse - Oxygen+ - (Embedded Maven From Eclipse) 148 | - Git 149 | - Docker 150 | 151 | #### Installing Guides 152 | 153 | - [Playlist - Installing Java, Eclipse & Embedded Maven](https://www.youtube.com/playlist?list=PLBBog2r6uMCSmMVTW_QmDLyASBvovyAO3) 154 | 155 | #### Troubleshooting Installations 156 | - Eclipse and Embedded Maven 157 | - Troubleshooting Guide : https://github.com/in28minutes/in28minutes-initiatives/tree/master/The-in28Minutes-TroubleshootingGuide-And-FAQ#tip--troubleshooting-embedded-maven-in-eclipse 158 | - PDF : https://github.com/in28minutes/SpringIn28Minutes/blob/master/InstallationGuide-JavaEclipseAndMaven_v2.pdf 159 | - GIT Repository For Installation : https://github.com/in28minutes/getting-started-in-5-steps 160 | 161 | ## Course Overview 162 | 163 | This course would be a perfect first step as an introduction to Amazon Web Services - AWS and the Cloud. 164 | 165 | In this course, we deploy a variety of Java Spring Boot Microservices to Amazon Web Services using AWS Fargate and ECS - Elastic Container Service. 166 | 167 | You will learn the basics of implementing Container Orchestration with ECS (Elastic Container Service) - Cluster, Task Definitions, Tasks, Containers and Services. You will learn about the two launch types of ECS - EC2 and AWS Fargate. In this course, we would focus extensively on AWS Fargate to simplify your Container Orchestration. You will learn to deploy multiple containers in the same ECS task. 168 | 169 | You will learn to Build Container Images for your Java Spring Boot Microservice Projects. 170 | 171 | You will implement the following features for your Microservices 172 | - Centralized Configuration Management with AWS Parameter Store 173 | - Distributed Tracing with AWS X Ray 174 | - Auto Scaling and Load Balancing with ECS, Elastic Load Balancers and Target Groups 175 | - Service Mesh using AWS App Mesh. You will learn the basics of AWS App Mesh - Mesh, Virtual Nodes and Virtual Services. You will learn to perform Canary Deployments using AWS AppMesh. 176 | - Service Discovery with Route 53 Hosted Zones and DNS. 177 | - Continuous Integration and Continuous Deployment with AWS Code Pipeline 178 | 179 | You will learn to debug problems with deploying containers using Service events and AWS CloudWatch logs. 180 | 181 | You will learn about automating deployments and creating a continuous delivery pipeline with AWS Code Pipeline. You will learn how to Auto Scale applications based on load as well as deploy multiple instances behind a load balancer using AWS ECS Fargate. 182 | 183 | You will be using a number of AWS Services - ECS - Elastic Container Services, AWS Fargate, EC2 - Elastic Compute Cloud, S3, AWS CodePipeLine, AWS CodeBuild, IAM, CloudWatch, ELB, Target Groups, X Ray, AWS Parameter Store, AWS App Mesh and Route 53. 184 | 185 | You will be using deploying a variety of projects to Amazon Web Services (AWS). These projects are created with Spring Boot (REST API Framework), Spring (Dependency Management), Maven (dependencies management), Eclipse (Java IDE) and Tomcat Embedded Web Server. We will help you set up each one of these. 186 | 187 | ## What you'll learn 188 | - You will Learn the Fundamentals of Amazon Web Services from Zero, no previous experience required 189 | - You will learn to deploy Spring Boot REST API and Microservices to AWS with AWS Fargate and ECS 190 | - You will learn the basics of implementing Container Orchestration with ECS (Elastic Container Service) - Cluster, Task Definitions, Tasks, Containers and Services 191 | - You will learn to Build Container Images for your Java Spring Boot Microservice Projects 192 | - You will learn about the two launch types of ECS - EC2 and AWS Fargate 193 | - You will learn to debug problems with deploying containers using Service events and AWS CloudWatch logs 194 | - You will be using a number of AWS Services - ECS - Elastic Container Services, AWS Fargate, EC2 - Elastic Compute Cloud, S3, AWS CodePipeLine, AWS CodeBuild, IAM, CloudWatch, ELB, Target Groups, X Ray, AWS Parameter Store, AWS App Mesh and Route 53 195 | - You will learn to create a continuous delivery pipeline with AWS Code Pipeline 196 | - You will learn how to Auto Scale applications based on load as well as deploy multiple instances behind a load balancer using AWS Fargate. 197 | - You will learn to implement Centralized Configuration Management for your Java Spring Boot Microservices with AWS Parameter Store 198 | - You will learn to implement Distributed Tracing for Java Spring Boot Microservices with AWS X Ray 199 | - You will learn the basics of AWS App Mesh - Mesh, Virtual Nodes and Virtual Services. You will learn to perform Canary Deployments for Java Spring Boot Microservices using AWS AppMesh. 200 | - You will Join 300,000 Learners having AMAZING LEARNING Experiences with in28Minutes 201 | 202 | ## Requirements 203 | - You have an attitude to learn while having fun :) 204 | - You have some programming experience with Java, Spring and Spring Boot 205 | - You have a valid debit or credit card to create a AWS Account 206 | - AWS Fargate is not in FREE Tier. You are responsible for monitoring the usage of AWS resources to reduce your billing. 207 | - You DO NOT need to have any experience with AWS (Amazon Web Services) 208 | 209 | 210 | ## Step By Step Details 211 | 212 | ### Getting Started with the course 213 | 214 | - Step 00 - Deploying Spring Boot Microservices with ECS and AWS Fargate - Introduction 215 | - Step 01 - Deploying Spring Boot Microservices with ECS and AWS Fargate - Getting Started with the Course 216 | 217 | ### Getting Started with AWS 218 | 219 | - Step 01 - Creating an AWS Root Account 220 | - Step 02 - Creating an IAM User for your AWS Account 221 | 222 | ### Getting Started with ECS and AWS Fargate 223 | 224 | - Step 01 - 10000 Feet Overview of Cloud, AWS, ECS and AWS Fargate 225 | - Step 02 - Getting Started with AWS Fargate - Deploy First Docker Container to AWS 226 | - Step 03 - Launch Sample App in Browser 227 | - Step 04 - Understanding AWS ECS Task Definition - Create first task definition for Hello World API 228 | - Step 05 - Create an ECS Service for Hello World API 229 | - Step 06 - Explore ECS Services - Launch Hello World REST API in Browser 230 | - Step 07 - Its Your Responsibility to Monitor Billing on the Cloud - 5 Recommendations 231 | - Step 08 - Monitor AWS Billing - Setting Billing Alerts 232 | - Step 09 - Reduce Bills - Set Service Desired Tasks to 0 233 | - Step 10 - Launch an AWS Fargate Task Directly 234 | - Step 11 - Run Batch Programs Using ECS Tasks - Simple Spring Task 235 | 236 | ### Getting Started with ECS with EC2 instances 237 | 238 | - Step 01 - Getting Started with ECS with EC2 instances 239 | - Step 02 - Create a Cluster for ECS with EC2 instances 240 | - Step 03 - Create a Service - Introduction to Region and AZ 241 | - Step 04 - Using Host Network Mode - Create New Task Definition and Service 242 | - Step 05 - ECS Cluster Management - Scale EC2 Instances 243 | - Step 06 - Debugging ECS and Fargate Problems using Service Events 244 | - Step 07 - Debugging Problems - Container Status, Stopped Reason and Cloud Watch Logs 245 | - Step 08 - Clean up Cluster 246 | - Step 09 - ECS with EC2 vs AWS Fargate 247 | 248 | ### Introduction to Microservices 249 | 250 | - Step 01 - Introduction to Microservices 251 | - Step 02 - Microservices - Challenges 252 | - Step 03 - Advantages of Microservices 253 | 254 | ### Deploying Currency Exchange Microservice with H2 to AWS Fargate 255 | 256 | - Step 01 - Import Microservices Projects into Eclipse 257 | - Step 02 - Code Review and Running Currency Exchange Microservice on Local 258 | - Step 03 - Build and Run Docker Container Image on Local for Currency Exchange Microservice 259 | - Step 04 - Push Currency Exchange Microservice Docker Image to Docker Hub 260 | - Step 05 - Currency Exchange Microservice with H2 - Create Task Definition and Service 261 | - Step 06 - Execute Currency Exchange Microservice on AWS 262 | - Step 07 - Using Task Metadata service to populate environment information 263 | - Step 08 - Exercise - Build Container Images for Hello World and Spring Task Projects 264 | 265 | ### Deploying Currency Exchange Microservice with MySQL to AWS Fargate 266 | 267 | - Step 00 - Quick Tip - Use Prebuild Container Images from Docker Hub 268 | - Step 01 - Currency Exchange Microservice with MySQL - Code Review 269 | - Step 02 - Launch MySQL as a Docker Container in Local 270 | - Step 03 - Connect Local Currency Exchange Microservice with MySQL 271 | - Step 04 - Create Currency Exchange Microservice with MySQL Docker Image and Push to Docker Hub 272 | - Step 05 - Create MySQL Database on AWS using RDS 273 | - Step 06 - Create Task Definition and Service for Currency Exchange Microservice with MySQL 274 | - Step 07 - Configure Security Group to all traffic from Microsevice to RDS Database 275 | - Step 08 - Creating a New Security Group for RDS Database 276 | 277 | ### Deploying Currency Conversion Microservice to AWS Fargate 278 | 279 | - Step 01 - Code Review and Running Currency Conversion Microservice on Local 280 | - Step 02 - Create Docker Image for Currency Conversion Microservice and Connect to Exchange Microservice using same network 281 | - Step 03 - Deploy Currency Conversion Microservice to AWS Fargate - Create ECS Task Definition and Service 282 | - Step 04 - Execute Currency Conversion Microservice on AWS Fargate 283 | - Step 05 - Running Currency Conversion Microservice and Currency Conversion Microservice in Same Task - Part 1 284 | - Step 06 - Running Currency Conversion Microservice and Currency Conversion Microservice in Same Task - Part 2 285 | 286 | ### Implement Centralized Configuration Management with AWS Parameter Store 287 | 288 | - Step 01 - Introduction to Centralized Configuration Management with AWS Parameter Store 289 | - Step 02 - Update ECS Task Definitions to use Centralized Configuration 290 | - Step 03 - Provide access to Parameter Store for ECS Task Execution Role and Test the REST API 291 | - Step 04 - Centralized Configuration Management - A Review 292 | 293 | ### Implement Distributed Tracing with AWS X Ray 294 | 295 | - Step 01 - Introduction to Distributed Tracing with AWS X Ray - Code Review 296 | - Step 02 - Deploy Currency Exchange Microservice with AWS X Ray - Update Task Def and Service 297 | - Step 03 - Provide access to AWS X Ray for ECS Task Execution Role 298 | - Step 04 - Currency Conversion Microservice with X Ray - Code Review and Deployment to AWS 299 | - Step 05 - CCS and CES in X Ray - Service Maps, Traces and Analytics 300 | 301 | ## Implement Auto Scaling and Load Balancing with AWS Fargate 302 | 303 | - Step 01 - Introduction to Auto Scaling and Load Balancing - Create ELB 304 | - Step 02 - Deploy New Load Balanced Service for Currency Exchange Microservice 305 | - Step 03 - Testing Currency Exchange Microservice through Load Balancer 306 | - Step 04 - Deploy New Load Balanced Service for Currency Conversion Microservice 307 | - Step 05 - Testing Currency Conversion Microservice through Load Balancer 308 | - Step 06 - Configure Auto Scaling for Currency Exchange Microservice 309 | - Step 07 - AWS Fargate Auto Scaling in Action - Scale in and Scale out 310 | - Step 08 - Clean Resources from this section 311 | - Step 09 - Tracing Request across Microservices using AWS CloudWatch Log Groups 312 | 313 | ## Deploying Service Mesh using AWS App Mesh 314 | 315 | - Step 01 - Introduction to AWS App Mesh 316 | - Step 02 - Introduction to Service Discovery and Implementing Service Discovery for Currency Exchange Microservice 317 | - Step 03 - Implementing Service Discovery for Currency Conversion Microservice - Review Hosted Zones and DNS 318 | - Step 04 - Creating EC2 Instance in VPC for Service Discovery Testing 319 | - Step 05 - SSH into EC2 Instance and Run Microservices using curl 320 | - Step 06 - Quick Tip - Format using jq 321 | - Step 07 - Basics of AWS App Mesh - Mesh, Virtual Nodes and Virtual Services 322 | - Step 08 - Integrate Microservics with AWS App Mesh - Update ECS Task Definitions and Service 323 | - Step 09 - Review AWS App Mesh - Cloud Watch Logs and X Ray Tracing 324 | - Step 10 - App Mesh and X Ray - Zero Microservice Code Change Needed - Deploy Non X Ray Microsevices to AWS Fargate 325 | - Step 11 - Canary Deployments with AWS AppMesh - Deploy Multiple Version of Microservice - 1 326 | - Step 12 - Canary Deployments with AWS AppMesh - Deploy Multiple Version of Microservice - 2 327 | - Step 13 - Clean Up Services and Hosted Zones 328 | 329 | ## Implement CI and CD with AWS Code Pipeline 330 | 331 | - Step 01 - Overview - CI and CD with AWS Code Pipeline - Create ECR Repository 332 | - Step 02 - Commit Hello World REST API Project to GIT Repository 333 | - Step 03 - Updating Application Specification for ECS Deployment with Task Definition and Container Name 334 | - Step 04 - Create Code Pipeline for Hello World REST API 335 | - Step 05 - Provide Access to ECR to Code Build Role 336 | - Step 06 - Understanding Code Build Specification - Build Spec 337 | - Step 07 - Review of AWS Code Pipeline 338 | 339 | ## Diagrams 340 | 341 | - Courtesy http://viz-js.com/ 342 | 343 | ``` 344 | graph architecture { 345 | 346 | node[style=filled,color="#59C8DE"] 347 | //node [style=filled,color="#D14D28", fontcolor=white]; 348 | rankdir = TB; 349 | node[shape=record, width=2] 350 | 351 | 1 -- 2 -- 3 -- 4 352 | 353 | 1[label=] 354 | 2[label=] 355 | 3[label=] 356 | 4[label=] 357 | 358 | } 359 | 360 | digraph architecture { 361 | 362 | node[style=filled,color="#59C8DE"] 363 | //node [style=filled,color="#D14D28", fontcolor=white]; 364 | rankdir = TB; 365 | node[shape=record] 366 | CO[shape=record, width=6.5, style=filled,color="#D14D28", fontcolor=white] 367 | CI,CC[shape=record, width=2] 368 | CL[shape=record, width=6] 369 | 2,3,4[shape=record, width=1.5] 370 | CI -> CO 371 | CC -> CO 372 | CO -> CL 373 | CL -> 2 374 | CL -> 3 375 | CL -> 4 376 | 377 | CI[label=] 378 | CO[label=] 379 | CC[label=] 380 | CL[label=] 381 | 2[label=] 382 | 3[label=] 383 | 4[label=] 384 | 385 | } 386 | 387 | digraph architecture { 388 | 389 | node[style=filled,color="#36BF80"] 390 | //node [style=filled,color="#D14D28", fontcolor=white]; 391 | rankdir = TB; 392 | node[shape=record] 393 | CO[shape=record, width=6.5, style=filled,color="#D14D28", fontcolor=white] 394 | CI,CC[shape=record, width=2] 395 | CL[shape=record, width=6] 396 | 2,3,4[shape=record, width=1.5] 397 | CI -> CO 398 | CC -> CO 399 | CO -> CL 400 | CL -> 2 401 | CL -> 3 402 | CL -> 4 403 | 404 | CI[label=] 405 | CO[label=] 406 | CC[label=] 407 | CL[label=] 408 | 2[label=] 409 | 3[label=] 410 | 4[label=] 411 | } 412 | 413 | digraph architecture { 414 | 415 | node[style=filled,color="#36BF80"] 416 | //node [style=filled,color="#D14D28", fontcolor=white]; 417 | rankdir = TB; 418 | node[shape=record] 419 | CO[shape=record, width=6.5, style=filled,color="#D14D28", fontcolor=white] 420 | CI,CC[shape=record, width=2] 421 | CL[shape=record, width=6,color="#59C8DE"] 422 | CI -> CO 423 | CC -> CO 424 | CO -> CL 425 | 426 | CI[label=] 427 | CO[label=] 428 | CC[label=] 429 | CL[label=] 430 | } 431 | 432 | digraph architecture { 433 | rankdir=TB; 434 | {rank=same; CurrencyConversionService, CurrencyExchangeService}; 435 | Database[shape=cylinder] 436 | CurrencyConversionService, CurrencyExchangeService[shape=component] 437 | 438 | CurrencyConversionService -> CurrencyExchangeService; 439 | 440 | CurrencyExchangeService->Database; 441 | 442 | CurrencyConversionService[label=
10 USD = 600 INR


>]; 443 | CurrencyExchangeService[label=
1 USD = 60 INR
1 EUR = 70 INR
1 AUD = 50 INR
>]; 444 | 445 | } 446 | 447 | graph architecture { 448 | 449 | node[style=filled,color="#59C8DE"] 450 | //node [style=filled,color="#D14D28", fontcolor=white]; 451 | rankdir = TB 452 | 453 | node[shape=record, width=0.5] 454 | LoadBalancer[width=5,label=,color="#D14D28", fontcolor=white] 455 | Listener1[width=3,label=>] 456 | Listener2[width=3,label=] 457 | TG1,TG2[width=2.5,label=>] 458 | Rule1[width=2.75,label=/api/currency-conversion-microservice>] 459 | Rule2[width=2.75,label=/api/currency-exchange-microservice>] 460 | CCS1,CCS2,CCS3[label=Service>] 461 | CES1,CES2[label=Service>] 462 | LoadBalancer -- Listener1 463 | LoadBalancer -- Listener2 464 | Listener1 -- Rule1 465 | Listener1 -- Rule2 466 | Rule1 -- TG1 467 | Rule2 -- TG2 468 | TG1 -- CCS1 469 | TG1 -- CCS2 470 | TG1 -- CCS3 471 | TG2 -- CES1 472 | TG2 -- CES2 473 | 474 | } 475 | 476 | graph architecture { 477 | 478 | node[style=filled,color="#59C8DE"] 479 | //node [style=filled,color="#D14D28", fontcolor=white]; 480 | rankdir = TB; 481 | node[shape=record] 482 | 483 | IAM -- Console 484 | Console -- UserID 485 | Console -- Password 486 | IAM -- Application 487 | Application -- AccessKeyID 488 | Application -- SecretAccessKey 489 | 490 | IAM[label=] 491 | AccessKeyID[label=] 492 | UserID[label=] 493 | SecretAccessKey[label=] 494 | Console[label=] 495 | Application[label=] 496 | } 497 | 498 | graph architecture { 499 | 500 | node[style=filled,color="#59C8DE"] 501 | //node [style=filled,color="#D14D28", fontcolor=white]; 502 | rankdir = TB; 503 | node[shape=record] 504 | 505 | Users -- RootUser 506 | Users -- IAM 507 | 508 | RootUser[label=] 509 | IAM[label=] 510 | 511 | } 512 | 513 | 514 | 515 | graph architecture { 516 | 517 | node[style=filled,color="#59C8DE"] 518 | //node [style=filled,color="#D14D28", fontcolor=white]; 519 | rankdir = TB 520 | node[shape=record, width=2] 521 | edge [width=0] 522 | graph [pad=".75", ranksep="0.05", nodesep="0.25"]; 523 | 524 | Applications -- Software [style=invis] 525 | Software -- OS [style=invis] 526 | OS -- Hardware [style=invis] 527 | 528 | } 529 | 530 | 531 | graph architecture { 532 | 533 | node[style=filled,color="#59C8DE"] 534 | //node [style=filled,color="#D14D28", fontcolor=white]; 535 | rankdir = TB 536 | node[shape=record, width=3] 537 | 538 | Containers, LocalImages [height=1] 539 | 540 | DockerClient -- Daemon 541 | Daemon -- Containers 542 | Daemon -- LocalImages 543 | Daemon -- ImageRegistry 544 | 545 | DockerClient[label=] 546 | ImageRegistry[label=nginx
mysql
eureka
your-app

>]; 547 | Daemon[label=] 548 | 549 | 550 | } 551 | 552 | 553 | graph architecture { 554 | 555 | node[style=filled,color="#59C8DE"] 556 | //node [style=filled,color="#D14D28", fontcolor=white]; 557 | rankdir = TB 558 | node[shape=record, width=2] 559 | Hypervisor,HostOS, Hardware[shape=record, width=6.5, style=filled,color="#D14D28", fontcolor=white] 560 | edge [width=0] 561 | graph [pad=".75", ranksep="0.05", nodesep="0.25"]; 562 | 563 | Application1 -- Software1 [style=invis] 564 | Application2 -- Software2 [style=invis] 565 | Application3 -- Software3 [style=invis] 566 | 567 | Software1 -- GuestOS1 [style=invis] 568 | Software2 -- GuestOS2 [style=invis] 569 | Software3 -- GuestOS3 [style=invis] 570 | GuestOS1 -- Hypervisor [style=invis] 571 | GuestOS2 -- Hypervisor [style=invis] 572 | GuestOS3 -- Hypervisor [style=invis] 573 | Hypervisor -- HostOS [style=invis] 574 | HostOS -- Hardware [style=invis] 575 | 576 | } 577 | 578 | 579 | graph architecture { 580 | 581 | node[style=filled,color="#59C8DE"] 582 | //node [style=filled,color="#D14D28", fontcolor=white]; 583 | rankdir = TB 584 | node[shape=record, width=2] 585 | HostOS, CloudInfrastructure, DockerEngine[shape=record, width=6.5, style=filled,color="#D14D28", fontcolor=white] 586 | edge [width=0] 587 | graph [pad=".75", ranksep="0.05", nodesep="0.25"]; 588 | Container1,Container2,Container3[height=2] 589 | 590 | Container1 -- DockerEngine [style=invis] 591 | Container2 -- DockerEngine [style=invis] 592 | Container3 -- DockerEngine [style=invis] 593 | DockerEngine -- HostOS [style=invis] 594 | HostOS -- CloudInfrastructure [style=invis] 595 | 596 | } 597 | ``` 598 | 599 | ### Troubleshooting 600 | - Refer our TroubleShooting Guide - https://github.com/in28minutes/in28minutes-initiatives/tree/master/The-in28Minutes-TroubleshootingGuide-And-FAQ 601 | 602 | ## Youtube Playlists - 500+ Videos 603 | 604 | [Click here - 30+ Playlists with 500+ Videos on Spring, Spring Boot, REST, Microservices and the Cloud](https://www.youtube.com/user/rithustutorials/playlists?view=1&sort=lad&flow=list) 605 | 606 | ## Keep Learning in28Minutes 607 | 608 | in28Minutes is creating amazing solutions for you to learn Spring Boot, Full Stack and the Cloud - Docker, Kubernetes, AWS, React, Angular etc. - [Check out all our courses here](https://github.com/in28minutes/learn) 609 | --------------------------------------------------------------------------------