diff --git a/README.md b/README.md index 9afca32..4e54968 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Create the ECS Task Execution role and default Task Role. * ECSDefaultTaskRole including a policy for ECS Exec ```bash -cd ../iam-role +cd ../ecs-iam-role cdk deploy ``` @@ -234,4 +234,4 @@ Load average: 0.00 0.02 0.00 4/301 75 * [Task Role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html) -* [Exec Role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-exec.html) \ No newline at end of file +* [Exec Role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-exec.html) diff --git a/app/Dockerfile b/app/Dockerfile index 70d7315..b4d0896 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -4,11 +4,8 @@ RUN mkdir -p /opt/build ADD ./ /opt/build WORKDIR /opt/build -RUN pwd \ - && ls -alh \ - && ./gradlew build --no-daemon \ - && ls -alh ./build/libs/ \ - && cp ./build/libs/devopssample-java-gradle-0.0.1.jar app.jar +RUN ./gradlew build --no-daemon \ + && cp ./build/libs/devops-java-gradle.jar app.jar VOLUME /tmp EXPOSE 8080 diff --git a/app/build.gradle b/app/build.gradle index ee52712..783bddd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,24 +1,36 @@ plugins { - id 'org.springframework.boot' version '2.2.1.RELEASE' - id 'io.spring.dependency-management' version '1.0.8.RELEASE' + id 'base' id 'java' + id 'application' + id 'org.springframework.boot' version '2.7.2' + id "io.spring.dependency-management" version "1.0.13.RELEASE" + id "org.sonarqube" version "3.4.0.2513" } -group = 'devopssample' -version = '0.0.1' -sourceCompatibility = '1.8' - repositories { mavenCentral() } -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } +archivesBaseName = 'devops-java-gradle' +application { + mainClass = 'com.sample.DemoApplication' } -test { - useJUnitPlatform() +dependencies { + implementation('org.springframework.boot:spring-boot-starter-web') + // implementation('org.springframework.boot:spring-boot-starter-data-jpa') } + +sonarqube { + properties { + property "sonar.projectName", "devops-java-gradle" + property "sonar.projectKey", "ContainerOnAWS_devops-java-gradle" + property "sonar.organization", "containeronaws" + // property "sonar.host.url", "http://127.0.0.1:9000" + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.sourceEncoding", "UTF-8" + property "sonar.python.version", "3.9" + property "sonar.links.ci", "https://github.com/ContainerOnAWS/devops-java-gradle" + property "sonar.log.level", "DEBUG" + } +} \ No newline at end of file diff --git a/app/sample-rest-api-template.yaml b/app/sample-rest-api-template.yaml new file mode 100644 index 0000000..09ecb29 --- /dev/null +++ b/app/sample-rest-api-template.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sample-rest-api + namespace: default + annotations: + app: 'sample-rest-api' +spec: + replicas: 2 + selector: + matchLabels: + app: sample-rest-api + template: + metadata: + labels: + app: sample-rest-api + spec: + containers: + - name: sample-rest-api + image: .dkr.ecr..amazonaws.com/sample-rest-api:latest + imagePullPolicy: Always + ports: + - containerPort: 8000 + resources: + requests: + cpu: 1 + memory: "1024Mi" + env: + - name: env + value: "dev" +--- +apiVersion: v1 +kind: Service +metadata: + name: sample-rest-api + annotations: + app: 'sample-rest-api' + alb.ingress.kubernetes.io/healthcheck-path: "/ping" +spec: + selector: + app: sample-rest-api + type: NodePort + ports: + - port: 8000 + targetPort: 8000 + protocol: TCP +--- +apiVersion: autoscaling/v2beta2 +kind: HorizontalPodAutoscaler +metadata: + name: 'sample-rest-api-hpa' + namespace: default +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: 'sample-rest-api' + minReplicas: 2 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 50 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: "sample-rest-api-ingress" + namespace: default + annotations: + app: 'sample-rest-api' + kubernetes.io/ingress.class: alb + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/load-balancer-name: sample-rest-api + alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=30 + alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=10 + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]' + # alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:::certificate/ + # alb.ingress.kubernetes.io/ssl-redirect: '443' + alb.ingress.kubernetes.io/tags: env=dev + alb.ingress.kubernetes.io/healthcheck-interval-seconds: '16' + alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '15' + alb.ingress.kubernetes.io/healthy-threshold-count: '2' + alb.ingress.kubernetes.io/unhealthy-threshold-count: '5' +spec: + rules: + - http: + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: "sample-rest-api" + port: + number: 8000 \ No newline at end of file diff --git a/app/src/main/java/com/sample/DemoApplication.java b/app/src/main/java/com/sample/DemoApplication.java new file mode 100644 index 0000000..fb9ba90 --- /dev/null +++ b/app/src/main/java/com/sample/DemoApplication.java @@ -0,0 +1,12 @@ +package com.sample; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class); + } +} diff --git a/app/src/main/java/com/sample/SampleController.java b/app/src/main/java/com/sample/SampleController.java new file mode 100644 index 0000000..40253ee --- /dev/null +++ b/app/src/main/java/com/sample/SampleController.java @@ -0,0 +1,29 @@ +package com.sample; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMethod; + +@RestController +public class SampleController { + + @RequestMapping(value="/", method=RequestMethod.GET) + public String home() { + return "OK"; + } + + @RequestMapping(value="/{seviceid}/{pathvar1}", method=RequestMethod.GET) + public String pingPath2() { + return "OK"; + } + + @RequestMapping(value="/{seviceid}/{pathvar1}/{pathvar2}", method=RequestMethod.GET) + public String pingPath3() { + return "OK"; + } + + @RequestMapping(value="/{seviceid}/{pathvar1}/{pathvar2}/{pathvar3}", method=RequestMethod.GET) + public String pingPath4() { + return "OK"; + } +} diff --git a/build.gradle b/build.gradle index fb0e2a7..70d312c 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,8 @@ sonarqube { property "sonar.host.url", "https://sonarcloud.io" property "sonar.sourceEncoding", "UTF-8" property "sonar.sources", "." - property "sonar.exclusions", "**/node_modules/**, **/cdk.out/**, **/*.java, **/*.jar" + // property "sonar.java.binaries", "build" + property "sonar.exclusions", "**/node_modules/**, **/cdk.out/**, app/**/*.java, app/**/*.jar" property "sonar.issue.ignore.multicriteria", "e1" property "sonar.issue.ignore.multicriteria.e1.ruleKey", "typescript:S1848" property "sonar.issue.ignore.multicriteria.e1.resourceKey", "**/*.ts" diff --git a/ecs-restapi-service/lib/ecs-restapi-service-stack.ts b/ecs-restapi-service/lib/ecs-restapi-service-stack.ts index 515e3fa..618f5f9 100644 --- a/ecs-restapi-service/lib/ecs-restapi-service-stack.ts +++ b/ecs-restapi-service/lib/ecs-restapi-service-stack.ts @@ -1,6 +1,5 @@ import { Construct } from 'constructs'; -import * as cdk from 'aws-cdk-lib'; -import { Stack, StackProps, CfnOutput, Duration } from 'aws-cdk-lib'; +import { Stack, StackProps, CfnOutput, Duration, Lazy, RemovalPolicy } from 'aws-cdk-lib'; import * as path from 'path'; import * as ecs from 'aws-cdk-lib/aws-ecs'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; @@ -41,8 +40,8 @@ export class EcsRestAPIServiceStack extends Stack { const taskDefinition = new ecs.TaskDefinition(this, 'task-definition', { compatibility: ecs.Compatibility.EC2, family: `${serviceName}-task`, - executionRole: iam.Role.fromRoleArn(this, 'task-execution-role', cdk.Lazy.string({ produce: () => executionRoleArn })), - taskRole: iam.Role.fromRoleArn(this, 'task-role', cdk.Lazy.string({ produce: () => taskRoleArn })) + executionRole: iam.Role.fromRoleArn(this, 'task-execution-role', Lazy.string({ produce: () => executionRoleArn })), + taskRole: iam.Role.fromRoleArn(this, 'task-role', Lazy.string({ produce: () => taskRoleArn })) }); const container = taskDefinition.addContainer('container-restapi', { containerName, @@ -75,7 +74,7 @@ export class EcsRestAPIServiceStack extends Stack { scaleInCooldown: Duration.seconds(120) }); const logGroup = new logs.LogGroup(this, 'loggroup', { - removalPolicy: cdk.RemovalPolicy.DESTROY, + removalPolicy: RemovalPolicy.DESTROY, logGroupName: serviceName, retention: logs.RetentionDays.TWO_WEEKS, }); @@ -95,7 +94,7 @@ export class EcsRestAPIServiceStack extends Stack { loadBalancerName: `alb-${serviceName}`, internetFacing: true, deletionProtection: false, - idleTimeout: cdk.Duration.seconds(30), + idleTimeout: Duration.seconds(30), }); const listener = alb.addListener('https-listener', { @@ -115,7 +114,7 @@ export class EcsRestAPIServiceStack extends Stack { healthyThresholdCount: 2, unhealthyThresholdCount: 5, interval: Duration.seconds(12), - path: '/ping', + path: '/', timeout: Duration.seconds(10), }, deregistrationDelay: Duration.seconds(15) diff --git a/ecs-restapi2-service/lib/ecs-restapi-service-stack.ts b/ecs-restapi2-service/lib/ecs-restapi-service-stack.ts index 48d443a..387d3cb 100644 --- a/ecs-restapi2-service/lib/ecs-restapi-service-stack.ts +++ b/ecs-restapi2-service/lib/ecs-restapi-service-stack.ts @@ -1,6 +1,5 @@ -import * as cdk from 'aws-cdk-lib'; +import { Stack, StackProps, CfnOutput, Duration, Lazy, RemovalPolicy } from 'aws-cdk-lib'; import * as path from 'path'; -import { Stack, StackProps, CfnOutput, Duration } from 'aws-cdk-lib'; import * as ecs from 'aws-cdk-lib/aws-ecs'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as logs from 'aws-cdk-lib/aws-logs'; @@ -41,8 +40,8 @@ export class EcsRestAPIServiceStack extends Stack { const taskDefinition = new ecs.TaskDefinition(this, 'task-definition', { compatibility: ecs.Compatibility.EC2, family: `${serviceName}-task`, - executionRole: iam.Role.fromRoleArn(this, 'task-execution-role', cdk.Lazy.string({ produce: () => executionRoleArn })), - taskRole: iam.Role.fromRoleArn(this, 'task-role', cdk.Lazy.string({ produce: () => taskRoleArn })) + executionRole: iam.Role.fromRoleArn(this, 'task-execution-role', Lazy.string({ produce: () => executionRoleArn })), + taskRole: iam.Role.fromRoleArn(this, 'task-role', Lazy.string({ produce: () => taskRoleArn })) }); const container = taskDefinition.addContainer('container-restapi', { containerName, @@ -73,7 +72,7 @@ export class EcsRestAPIServiceStack extends Stack { scaleOutCooldown: Duration.seconds(60), }); const logGroup = new logs.LogGroup(this, 'logGroup', { - removalPolicy: cdk.RemovalPolicy.DESTROY, + removalPolicy: RemovalPolicy.DESTROY, logGroupName: serviceName, retention: logs.RetentionDays.TWO_WEEKS, }); @@ -93,7 +92,7 @@ export class EcsRestAPIServiceStack extends Stack { loadBalancerName: `alb-${serviceName}`, internetFacing: true, deletionProtection: false, - idleTimeout: cdk.Duration.seconds(30), + idleTimeout: Duration.seconds(30), }); const listener = alb.addListener('https-listener', {