This repository has been archived by the owner on Dec 15, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 753
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
java support with prometheus and dependency management with maven (#738)
* basic java support with prometheus and dependency management with maven * pass the event and context details to called function * fix NPE when all expected event details are not there * buid container support to run java functions with deps * addressing review comments * review fixes * docs for java runtime * update the runtimeImage and initImage for Java
- Loading branch information
1 parent
baa1457
commit d379421
Showing
21 changed files
with
607 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FROM openjdk:8-jdk-alpine | ||
|
||
USER 1000 | ||
|
||
CMD ["java", "-cp", "/kubeless/lib/*:/kubeless/handler/target/handler-1.0-SNAPSHOT.jar:/kubeless/function/target/function-1.0-SNAPSHOT.jar", "io.kubeless.Handler"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FROM openjdk:8-jdk-alpine | ||
|
||
RUN apk add --no-cache maven | ||
|
||
COPY . /usr/src/myapp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
init-image: | ||
docker build -f Dockerfile.init -t kubeless/java-init:1.8 . | ||
|
||
runtime-image: | ||
docker build -f Dockerfile -t kubeless/java:1.8 . | ||
|
||
push-init: | ||
docker push kubeless/java-init:1.8 | ||
|
||
push-runtime: | ||
docker push kubeless/java:1.8 | ||
|
||
build-all: init-image runtime-image | ||
push-all: push-init push-runtime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>function</artifactId> | ||
<name>function</name> | ||
<version>1.0-SNAPSHOT</version> | ||
<dependencies> | ||
<dependency> | ||
<groupId>io.kubeless</groupId> | ||
<artifactId>params</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</dependency> | ||
</dependencies> | ||
<parent> | ||
<groupId>io.kubeless</groupId> | ||
<artifactId>kubeless</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
</project> |
7 changes: 7 additions & 0 deletions
7
docker/runtime/java/function/src/main/java/io/kubeless/Example.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package io.kubeless; | ||
|
||
public class Example { | ||
public String sayHello(io.kubeless.Event event, io.kubeless.Context context) { | ||
return "Hello world!"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>handler</artifactId> | ||
<name>handler</name> | ||
<version>1.0-SNAPSHOT</version> | ||
<parent> | ||
<groupId>io.kubeless</groupId> | ||
<artifactId>kubeless</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
<dependencies> | ||
<dependency> | ||
<groupId>io.kubeless</groupId> | ||
<artifactId>function</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.kubeless</groupId> | ||
<artifactId>params</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.prometheus</groupId> | ||
<artifactId>simpleclient</artifactId> | ||
<version>0.3.0</version> | ||
</dependency> | ||
<!-- Hotspot JVM metrics--> | ||
<dependency> | ||
<groupId>io.prometheus</groupId> | ||
<artifactId>simpleclient_hotspot</artifactId> | ||
<version>0.3.0</version> | ||
</dependency> | ||
<!-- Exposition HTTPServer--> | ||
<dependency> | ||
<groupId>io.prometheus</groupId> | ||
<artifactId>simpleclient_httpserver</artifactId> | ||
<version>0.3.0</version> | ||
</dependency> | ||
<!-- Pushgateway exposition--> | ||
<dependency> | ||
<groupId>io.prometheus</groupId> | ||
<artifactId>simpleclient_pushgateway</artifactId> | ||
<version>0.3.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>log4j</groupId> | ||
<artifactId>log4j</artifactId> | ||
<version>1.2.17</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
189 changes: 189 additions & 0 deletions
189
docker/runtime/java/handler/src/main/java/io/kubeless/Handler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* | ||
Copyright (c) 2016-2017 Bitnami | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package io.kubeless; | ||
|
||
import com.sun.net.httpserver.HttpExchange; | ||
import com.sun.net.httpserver.HttpHandler; | ||
import com.sun.net.httpserver.HttpServer; | ||
import com.sun.net.httpserver.Headers; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.io.InputStreamReader; | ||
import java.io.BufferedReader; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.net.InetSocketAddress; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import io.prometheus.client.Counter; | ||
import io.prometheus.client.Histogram; | ||
import io.kubeless.Event; | ||
import io.kubeless.Context; | ||
import org.apache.log4j.Logger; | ||
import org.apache.log4j.BasicConfigurator; | ||
|
||
public class Handler { | ||
|
||
static String className = System.getenv("MOD_NAME"); | ||
static String methodName = System.getenv("FUNC_HANDLER"); | ||
static String timeout = System.getenv("FUNC_TIMEOUT"); | ||
static String runtime = System.getenv("FUNC_RUNTIME"); | ||
static String memoryLimit = System.getenv("FUNC_MEMORY_LIMIT"); | ||
static Method method; | ||
static Object obj; | ||
static Logger logger = Logger.getLogger(Handler.class.getName()); | ||
|
||
static final Counter requests = Counter.build().name("function_calls_total").help("Total function calls.").register(); | ||
static final Counter failures = Counter.build().name("function_failures_total").help("Total function call failuress.").register(); | ||
static final Histogram requestLatency = Histogram.build().name("function_duration_seconds").help("Duration of time user function ran in seconds.").register(); | ||
|
||
public static void main(String[] args) { | ||
|
||
BasicConfigurator.configure(); | ||
|
||
String funcPort = System.getenv("FUNC_PORT"); | ||
if(funcPort == null || funcPort.isEmpty()) { | ||
funcPort = "8080"; | ||
} | ||
int port = Integer.parseInt(funcPort); | ||
try { | ||
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); | ||
server.createContext("/", new FunctionHandler()); | ||
server.createContext("/healthz", new HealthHandler()); | ||
server.setExecutor(java.util.concurrent.Executors.newFixedThreadPool(50)); | ||
server.start(); | ||
|
||
Class<?> c = Class.forName("io.kubeless."+className); | ||
obj = c.newInstance(); | ||
method = c.getMethod(methodName, io.kubeless.Event.class, io.kubeless.Context.class); | ||
} catch (Exception e) { | ||
failures.inc(); | ||
if (e instanceof ClassNotFoundException) { | ||
logger.error("Class: " + className + " not found"); | ||
} else if (e instanceof NoSuchMethodException) { | ||
logger.error("Method: " + methodName + " not found"); | ||
} else if (e instanceof java.io.IOException) { | ||
logger.error("Failed to starting listener."); | ||
} else { | ||
logger.error("An exception occured running Class: " + className + " method: " + methodName); | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
||
static class FunctionHandler implements HttpHandler { | ||
|
||
@Override | ||
public void handle(HttpExchange he) throws IOException { | ||
Histogram.Timer requestTimer = requestLatency.startTimer(); | ||
try { | ||
requests.inc(); | ||
|
||
InputStreamReader reader = new InputStreamReader(he.getRequestBody(), StandardCharsets.UTF_8.name()); | ||
BufferedReader br = new BufferedReader(reader); | ||
String requestBody = br.lines().collect(Collectors.joining()); | ||
br.close(); | ||
reader.close(); | ||
|
||
Headers headers = he.getRequestHeaders(); | ||
String eventId = getEventId(headers); | ||
String eventType = getEventType(headers); | ||
String eventTime = getEventTime(headers); | ||
String eventNamespace = getEventNamespace(headers); | ||
|
||
Event event = new Event(requestBody, eventId, eventType, eventTime, eventNamespace); | ||
Context context = new Context(methodName, timeout, runtime, memoryLimit); | ||
|
||
Object returnValue = Handler.method.invoke(Handler.obj, event, context); | ||
String response = (String)returnValue; | ||
logger.info("Response: " + response); | ||
he.sendResponseHeaders(200, response.length()); | ||
OutputStream os = he.getResponseBody(); | ||
os.write(response.getBytes()); | ||
os.close(); | ||
} catch (Exception e) { | ||
failures.inc(); | ||
if (e instanceof ClassNotFoundException) { | ||
logger.error("Class: " + className + " not found"); | ||
} else if (e instanceof NoSuchMethodException) { | ||
logger.error("Method: " + methodName + " not found"); | ||
} else if (e instanceof InvocationTargetException) { | ||
logger.error("Failed to Invoke Method: " + methodName); | ||
} else if (e instanceof InstantiationException) { | ||
logger.error("Failed to instantiate method: " + methodName); | ||
} else { | ||
logger.error("An exception occured running Class: " + className + " method: " + methodName); | ||
e.printStackTrace(); | ||
} | ||
} finally { | ||
requestTimer.observeDuration(); | ||
} | ||
} | ||
|
||
private String getEventType(Headers headers) { | ||
if (headers.containsKey("event-type")) { | ||
List<String> values = headers.get("event-type"); | ||
if (values != null) { | ||
return values.get(0); | ||
} | ||
} | ||
return ""; | ||
} | ||
|
||
private String getEventTime(Headers headers) { | ||
if (headers.containsKey("event-time")) { | ||
List<String> values = headers.get("event-time"); | ||
if (values != null) { | ||
return values.get(0); | ||
} | ||
} | ||
return ""; | ||
} | ||
|
||
private String getEventNamespace(Headers headers) { | ||
if (headers.containsKey("event-namespace")) { | ||
List<String> values = headers.get("event-namespace"); | ||
if (values != null) { | ||
return values.get(0); | ||
} | ||
} | ||
return ""; | ||
} | ||
|
||
private String getEventId(Headers headers) { | ||
if (headers.containsKey("event-id")) { | ||
List<String> values = headers.get("event-id"); | ||
if (values != null) { | ||
return values.get(0); | ||
} | ||
} | ||
return ""; | ||
} | ||
} | ||
|
||
static class HealthHandler implements HttpHandler { | ||
@Override | ||
public void handle(HttpExchange t) throws IOException { | ||
String response = "OK"; | ||
t.sendResponseHeaders(200, response.length()); | ||
OutputStream os = t.getResponseBody(); | ||
os.write(response.getBytes()); | ||
os.close(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Root logger option | ||
log4j.rootLogger=INFO, stdout | ||
|
||
# Redirect log messages to console | ||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender | ||
log4j.appender.stdout.Target=System.out | ||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout | ||
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>params</artifactId> | ||
<name>params</name> | ||
<version>1.0-SNAPSHOT</version> | ||
<parent> | ||
<groupId>io.kubeless</groupId> | ||
<artifactId>kubeless</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
</project> |
34 changes: 34 additions & 0 deletions
34
docker/runtime/java/params/src/main/java/io/kubeless/Context.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
Copyright (c) 2016-2017 Bitnami | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package io.kubeless; | ||
|
||
/** | ||
* Context includes information about the function environment | ||
*/ | ||
public class Context { | ||
String functionName; | ||
String timeout; | ||
String runtime; | ||
String memoryLimit; | ||
|
||
public Context(String functionName, String timeout, String runtime, String memoryLimit) { | ||
this.functionName = functionName; | ||
this.timeout = timeout; | ||
this.runtime = runtime; | ||
this.memoryLimit = memoryLimit; | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
docker/runtime/java/params/src/main/java/io/kubeless/Event.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
Copyright (c) 2016-2017 Bitnami | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package io.kubeless; | ||
|
||
/** | ||
* Event includes information about the event source | ||
*/ | ||
public class Event { | ||
String Data; | ||
String EventID; | ||
String EventType; | ||
String EventTime; | ||
String EventNamespace; | ||
|
||
public Event(String data, String eventId, String eventType, String eventTime, String eventNamespace) { | ||
this.Data = data; | ||
this.EventID = eventId; | ||
this.EventType = eventType; | ||
this.EventTime = eventTime; | ||
this.EventNamespace = eventNamespace; | ||
} | ||
} |
Oops, something went wrong.