From e8ba4e77d6235eb48e98653c44250a25f7e92dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Mon, 7 Sep 2020 21:52:05 +0200 Subject: [PATCH 01/18] add first native image implementation --- pom.xml | 61 +++++++++++++++++++++++ src/main/java/com/s24/geoip/GeoIpApi.java | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cfa3084..19a2ef9 100644 --- a/pom.xml +++ b/pom.xml @@ -63,8 +63,26 @@ true true + + com.s24.geoip.GeoIpApi + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + com.google.guava @@ -74,13 +92,16 @@ org.springframework.boot spring-boot-starter-web + + + + org.springframework.experimental + spring-graalvm-native + 0.7.1 + + + org.springframework + spring-context-indexer + true + com.maxmind.geoip2 geoip2 @@ -115,4 +147,33 @@ + + + native + + + + org.graalvm.nativeimage + native-image-maven-plugin + 20.2.0 + + -J-Xmx4G -H:+TraceClassInitialization -H:+ReportExceptionStackTraces + -Dspring.graal.remove-unused-autoconfig=true -Dspring.graal.remove-yaml-support=true + + ${project.artifactId} + + + + + native-image + + package + + + + + + + + diff --git a/src/main/java/com/s24/geoip/GeoIpApi.java b/src/main/java/com/s24/geoip/GeoIpApi.java index 0a88c71..8d8e0cb 100644 --- a/src/main/java/com/s24/geoip/GeoIpApi.java +++ b/src/main/java/com/s24/geoip/GeoIpApi.java @@ -17,7 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@SpringBootApplication +@SpringBootApplication(proxyBeanMethods = false) public class GeoIpApi { private static final Logger logger = LoggerFactory.getLogger(GeoIpApi.class); From 271b6b162ba20722e04bec6ebf5135032316555b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Thu, 10 Sep 2020 21:56:48 +0200 Subject: [PATCH 02/18] wip on native docker build --- .dockerignore | 4 ++-- Dockerfile | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.dockerignore b/.dockerignore index 3e3fec2..4d41b5e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,2 @@ -** -!target/*.jar \ No newline at end of file +#** +#!target/*.jar \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 85009be..0d31868 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,40 @@ -FROM openjdk:11.0.8 -ARG MAXMIND_LICENSE_KEY +# build stage +FROM oracle/graalvm-ce:20.2.0-java11 AS builder + +ADD . /build +WORKDIR /build + +# For SDKMAN to work we need unzip & zip +RUN yum -y update && yum -y install unzip zip +RUN \ + # Install SDKMAN + curl -s "https://get.sdkman.io" | bash; \ + source "$HOME/.sdkman/bin/sdkman-init.sh" && \ + sdk install maven && \ + # Install GraalVM Native Image + gu install native-image && \ + native-image --version && \ + mvn --version && \ + java -version && \ + ls -la . -# place app -COPY target/*.jar /opt/geoip-api.jar +# build image +RUN source "$HOME/.sdkman/bin/sdkman-init.sh" && mvn -P native clean package + +# run stage +FROM alpine:3 +ARG MAXMIND_LICENSE_KEY # download current maxmind databases WORKDIR /srv -RUN curl -sSL "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&suffix=tar.gz&license_key=${MAXMIND_LICENSE_KEY}" | tar -xz && \ +RUN apk add curl && \ + curl -sSL "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&suffix=tar.gz&license_key=${MAXMIND_LICENSE_KEY}" | tar -xz && \ ln -s GeoLite2-City_*/GeoLite2-City.mmdb . +# place app +COPY --from=builder "/build/target/geoip-api" geoip-api + ENV CITY_DB_FILE /srv/GeoLite2-City.mmdb HEALTHCHECK --interval=5s --timeout=2s CMD curl -f http://localhost:8080/actuator/health EXPOSE 8080 -CMD exec java ${JAVA_GC_OPTS} ${JAVA_OPTS} -jar /opt/geoip-api.jar +CMD exec /srv/geoip-api From 12bb78e9476afbcf1716ea616e1c37ca7decb1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Fri, 9 Oct 2020 22:35:47 +0200 Subject: [PATCH 03/18] add body to release // set committer date --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0a95073..cd99e6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,14 +23,15 @@ after_success: - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD - docker push observabilitystack/geoip-api:latest - docker push observabilitystack/geoip-api:${TRAVIS_TAG} -- git tag ${TRAVIS_TAG} +- GIT_COMMITTER_DATE=$(date -R) git tag v${TRAVIS_TAG} -m '${TRAVIS_TAG}' - fi deploy: provider: releases - name: ${TRAVIS_TAG} (recent Maxmind geolite database) + name: ${TRAVIS_TAG} api_key: secure: "mQjbs/LMn51IG8oDHqo6SP329E4q+mT4+Bb5QD0luyJFf5mzde1DOnlevukm9ZFQUgBtzOJBxQt64OU4k0vrQx2glIGxRcpsHwyFDjcAcb8SIv4sv8KzjWXmSisMTnCTEe+PTuLSeK96SMZh373KF1E02chGCYhiD9ECfTQaOTI4lzrx8XC0YoOeODOKzeCId+W6UcfJMyZo4klve7b85bqkFEOvIZV9cklCzaGUKVp+k/vacdE9FIOiEc/iYctyN6qe2erY1k1KPL7oIiMz2vb5icAvQW0u/Uyjo3yrNZc48RSAcZE13LbVPkV/thgDHwQRUsKKx6ersIVQWjB0hky0d/tkTlnRlJXX4n2Owyzg0zv0dlgee6O5WOMjNDAjvaRXB/IjbkmulN6jKGyHC03q24zYjMTF9En6koCt+A2B0HOpq0XvZVjlmAN9G4MyBEd/BOWVvetJn/eCx2fPTsNvx2GklwzKUejiuyMECAYI9OsjnzEIunNd5b5+xc9baYxQIP4HpJNiEn5t/JoxSwICEKrkxND5Lykq/hWZGYN6JZvIDc4abJAZ2UeiLMzpoYazGauUmMpRAT8K9mIy3NUbppS8BJyKXyTDfDpRHBrX4cp075Vf/x2FCv2tdd45u58h74fRUdJWEkHGLgwJi0AitDYndlM/B+aJ+dJI8Gg=" skip_cleanup: true + body: Updated MaxMind GeoLite database as of ${TRAVIS_TAG} on: tags: true \ No newline at end of file From c68c50cc5412575a06d5d3ec47f5f6f64b5caf8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Fri, 9 Oct 2020 22:37:36 +0200 Subject: [PATCH 04/18] fix tag name --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cd99e6e..8b2c3db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,12 +23,13 @@ after_success: - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD - docker push observabilitystack/geoip-api:latest - docker push observabilitystack/geoip-api:${TRAVIS_TAG} -- GIT_COMMITTER_DATE=$(date -R) git tag v${TRAVIS_TAG} -m '${TRAVIS_TAG}' +- GIT_COMMITTER_DATE=$(date -R) git tag ${TRAVIS_TAG} -m '${TRAVIS_TAG}' - fi deploy: provider: releases name: ${TRAVIS_TAG} + tag_name: ${TRAVIS_TAG} api_key: secure: "mQjbs/LMn51IG8oDHqo6SP329E4q+mT4+Bb5QD0luyJFf5mzde1DOnlevukm9ZFQUgBtzOJBxQt64OU4k0vrQx2glIGxRcpsHwyFDjcAcb8SIv4sv8KzjWXmSisMTnCTEe+PTuLSeK96SMZh373KF1E02chGCYhiD9ECfTQaOTI4lzrx8XC0YoOeODOKzeCId+W6UcfJMyZo4klve7b85bqkFEOvIZV9cklCzaGUKVp+k/vacdE9FIOiEc/iYctyN6qe2erY1k1KPL7oIiMz2vb5icAvQW0u/Uyjo3yrNZc48RSAcZE13LbVPkV/thgDHwQRUsKKx6ersIVQWjB0hky0d/tkTlnRlJXX4n2Owyzg0zv0dlgee6O5WOMjNDAjvaRXB/IjbkmulN6jKGyHC03q24zYjMTF9En6koCt+A2B0HOpq0XvZVjlmAN9G4MyBEd/BOWVvetJn/eCx2fPTsNvx2GklwzKUejiuyMECAYI9OsjnzEIunNd5b5+xc9baYxQIP4HpJNiEn5t/JoxSwICEKrkxND5Lykq/hWZGYN6JZvIDc4abJAZ2UeiLMzpoYazGauUmMpRAT8K9mIy3NUbppS8BJyKXyTDfDpRHBrX4cp075Vf/x2FCv2tdd45u58h74fRUdJWEkHGLgwJi0AitDYndlM/B+aJ+dJI8Gg=" skip_cleanup: true From f99068085cea411244ea40eabd39070bb9ba29c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Wed, 14 Oct 2020 11:15:13 +0200 Subject: [PATCH 05/18] make Prometheus Actuator work again --- pom.xml | 4 ++ src/main/resources/application.yml | 3 +- src/test/java/com/s24/geoip/RestApiIT.java | 18 ++++++ .../com/s24/geoip/SpringBootActuatorIT.java | 60 +++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/s24/geoip/SpringBootActuatorIT.java diff --git a/pom.xml b/pom.xml index 19a2ef9..e9f3eb8 100644 --- a/pom.xml +++ b/pom.xml @@ -106,6 +106,10 @@ org.springframework.boot spring-boot-starter-actuator + + io.micrometer + micrometer-registry-prometheus + org.springframework.boot spring-boot-starter-log4j2 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1e75f22..ca3d3b8 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1 +1,2 @@ -server.http2.enabled: true \ No newline at end of file +server.http2.enabled: true +management.endpoints.web.exposure.include: info, health, prometheus \ No newline at end of file diff --git a/src/test/java/com/s24/geoip/RestApiIT.java b/src/test/java/com/s24/geoip/RestApiIT.java index ca0ff8a..b719092 100644 --- a/src/test/java/com/s24/geoip/RestApiIT.java +++ b/src/test/java/com/s24/geoip/RestApiIT.java @@ -72,4 +72,22 @@ public void test400ResponseForInvalidInput() { ResponseEntity response = restTemplate.getForEntity(REST_URL, String.class, "invalid"); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); } + + @Test + public void testActuator() { + ResponseEntity response = restTemplate.getForEntity("/actuator", String.class, "invalid"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + public void testActuatorHealth() { + ResponseEntity response = restTemplate.getForEntity("/actuator/health", String.class, "invalid"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + public void testActuatorPrometheus() { + ResponseEntity response = restTemplate.getForEntity("/actuator/prometheus", String.class, "invalid"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } } diff --git a/src/test/java/com/s24/geoip/SpringBootActuatorIT.java b/src/test/java/com/s24/geoip/SpringBootActuatorIT.java new file mode 100644 index 0000000..d29f4cf --- /dev/null +++ b/src/test/java/com/s24/geoip/SpringBootActuatorIT.java @@ -0,0 +1,60 @@ +package com.s24.geoip; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.junit.Assert.assertThat; + +import java.net.InetAddress; + +import com.google.common.net.InetAddresses; +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.exception.AddressNotFoundException; +import com.maxmind.geoip2.model.CityResponse; +import com.maxmind.geoip2.record.Country; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class SpringBootActuatorIT { + + @Autowired + private TestRestTemplate restTemplate; + + @MockBean(name = "ispDatabaseReader") + private DatabaseReader ispDatabaseReader; + + @Before + public void setUp() throws Exception { + when(ispDatabaseReader.isp(any(InetAddress.class))).thenThrow(new AddressNotFoundException("test")); + } + + @Test + public void testActuator() { + ResponseEntity response = restTemplate.getForEntity("/actuator", String.class, "invalid"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + public void testActuatorHealth() { + ResponseEntity response = restTemplate.getForEntity("/actuator/health", String.class, "invalid"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + public void testActuatorPrometheus() { + ResponseEntity response = restTemplate.getForEntity("/actuator/prometheus", String.class, "invalid"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } +} From c2b742fc125979bc92c852c46f7f14856f84d5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Wed, 14 Oct 2020 11:23:10 +0200 Subject: [PATCH 06/18] add kubernetes example --- examples/kubernetes-deployment.yml | 73 ++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/kubernetes-deployment.yml diff --git a/examples/kubernetes-deployment.yml b/examples/kubernetes-deployment.yml new file mode 100644 index 0000000..d0c00e0 --- /dev/null +++ b/examples/kubernetes-deployment.yml @@ -0,0 +1,73 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: geoip +spec: + ports: + - name: web + port: 8080 + selector: + name: geoip + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: geoip +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + name: geoip + template: + metadata: + labels: + name: geoip + annotations: + "prometheus.io/scrape": "true" + "prometheus.io/path": "/actuator/prometheus" + "prometheus.io/port": "8080" + + spec: + containers: + + - name: geoip + image: observabilitystack/geoip-api:latest + resources: + requests: + cpu: "100m" + memory: "1Gi" + limits: + cpu: "500m" + memory: "1Gi" + ports: + - containerPort: 8080 + name: web + readinessProbe: + httpGet: + path: /actuator/health + port: 8080 + scheme: HTTP + initialDelaySeconds: 30 + failureThreshold: 20 + periodSeconds: 3 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: geoip +spec: + rules: + - host: geoip.${HOSTNAME} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: geoip + port: + name: web From 2401feb6fb6ffce296c3dba1da97531aa90bf1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B8gh=20K=C3=B6ster?= Date: Wed, 14 Oct 2020 20:59:19 +0200 Subject: [PATCH 07/18] compiling actually works --- pom.xml | 24 ++++++++++--------- src/test/java/com/s24/geoip/RestApiIT.java | 2 ++ .../com/s24/geoip/SpringBootActuatorIT.java | 2 ++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index e9f3eb8..74bed8f 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.3.3.RELEASE + 2.3.4.RELEASE @@ -101,7 +101,6 @@ --> -