歡迎訪問我的GitHub
https://github.com/zq2599/blog_demos
內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;
OpenFaaS實戰系列文章連結
- 部署
- 函式入門
- Java函式
- 模板操作(template)
- 大話watchdog
- of-watchdog(為效能而生)
- java11模板解析
- OpenFaaS實戰之八:自制模板(maven+jdk8)
- OpenFaaS實戰之九:終篇,自制模板(springboot+maven+jdk8)
本篇概覽
- 本文是《OpenFaaS實戰》系列的第三篇,經過前文實戰,我們們掌握了函式開發和部署的要領,作為一名Java程式設計師,當然迫切的希望用Java編寫OpenFaaS函式,於是就有了本文;
- 本文開發一個Java函式,功能是解析請求body中的JSON字串,再加上JVM程式ID、IP地址、當前時間一起拼成字串,包裝在JSON中返回;
- 平時寫java程式碼會用到各種二方庫,這裡引入jackson的庫,作為OpenFaaS新增依賴的參考;
原始碼下載
- 本篇實戰中的原始碼可在GitHub下載到,地址和連結資訊如下表所示(https://github.com/zq2599/blog_demos):
名稱 | 連結 | 備註 |
---|---|---|
專案主頁 | https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協議 |
git倉庫地址(ssh) | git@github.com:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協議 |
- 這個git專案中有多個資料夾,本章的應用在openfaas資料夾下,如下圖紅框所示:
- openfaas裡面有多個子資料夾,本篇的原始碼在currenttime中,如下圖紅框:
建立函式
- 執行以下命令,即可建立名為faas-currenttime的函式,此函式的映象字首是bolingcavalry,語言型別為java11:
faas-cli new faas-currenttime --lang java11 -p bolingcavalry
- 控制檯響應如下:
[root@node1 20]# faas-cli new faas-currenttime --lang java11 -p bolingcavalry
2020/11/20 15:47:50 No templates found in current directory.
2020/11/20 15:47:50 Attempting to expand templates from https://github.com/openfaas/templates.git
2020/11/20 15:47:56 Fetched 12 template(s) : [csharp dockerfile go java11 java11-vert-x node node12 php7 python python3 python3-debian ruby] from https://github.com/openfaas/templates.git
Folder: faas-currenttime created.
___ _____ ____
/ _ \ _ __ ___ _ __ | ___|_ _ __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) | __/ | | | _| (_| | (_| |___) |
\___/| .__/ \___|_| |_|_| \__,_|\__,_|____/
|_|
Function created in folder: faas-currenttime
Stack file written: faas-currenttime.yml
Notes:
You have created a function using the java11 template which uses an LTS
version of the OpenJDK.
- 當前目錄已經新增了檔案faas-currenttime.yml和資料夾faas-currenttime
- 資料夾faas-currenttime的內容如下,可見是個gradle工程:
faas-currenttime
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ └── java
│ └── com
│ └── openfaas
│ └── function
│ └── Handler.java
└── test
└── java
└── HandlerTest.java
- 開啟build.gradle檔案,新增下圖紅框中的內容,即jackson和common庫的依賴:
- 進入資料夾faas-currenttime/src/main/java/com/openfaas/function/,可見已建立了預設的業務功能類Handler.java,開啟看看OpenFaaS給的預設程式碼啥樣的,如下所示:
package com.openfaas.function;
import com.openfaas.model.IHandler;
import com.openfaas.model.IResponse;
import com.openfaas.model.IRequest;
import com.openfaas.model.Response;
public class Handler extends com.openfaas.model.AbstractHandler {
public IResponse Handle(IRequest req) {
Response res = new Response();
res.setBody("Hello, world!");
return res;
}
}
- 把Handler.java的內容用以下程式碼替換掉,替換後的函式,其功能是取得請求引數,再把當前JVM的程式ID、IP地址、當前時間都拼接到一個字串中返回,需要重點關注的有兩點:將請求引數反序列化成Map例項,以及將Map序列化成JSON字串返回:
package com.openfaas.function;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.openfaas.model.IRequest;
import com.openfaas.model.IResponse;
import com.openfaas.model.Response;
import org.apache.commons.lang3.StringUtils;
import java.lang.management.ManagementFactory;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class Handler extends com.openfaas.model.AbstractHandler {
private static final String PARAM_USER_NAME = "name";
private static final String RESPONSE_TEMPLETE = "Hello %s, response from [%s], PID [%s], %s";
private ObjectMapper mapper = new ObjectMapper();
/**
* 獲取本機IP地址
* @return
*/
public static String getIpAddress() {
try {
Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress ip = null;
while (allNetInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
continue;
} else {
Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
ip = addresses.nextElement();
if (ip != null && ip instanceof Inet4Address) {
return ip.getHostAddress();
}
}
}
}
} catch (Exception e) {
System.err.println("IP地址獲取失敗" + e.toString());
}
return "";
}
/**
* 返回當前程式ID
* @return
*/
private static String getPID() {
return ManagementFactory
.getRuntimeMXBean()
.getName()
.split("@")[0];
}
private String getUserName(IRequest req) {
// 如果從請求body中取不到userName,就用
String userName = null;
try {
Map<String, Object> mapFromStr = mapper.readValue(req.getBody(),
new TypeReference<Map<String, Object>>() {});
if(null!=mapFromStr && mapFromStr.containsKey(PARAM_USER_NAME)) {
userName = String.valueOf(mapFromStr.get(PARAM_USER_NAME));
}
} catch (Exception e) {
e.printStackTrace();
}
// 如果從請求body中取不到userName,就給個預設值
if(StringUtils.isBlank(userName)) {
userName = "anonymous";
}
return userName;
}
public IResponse Handle(IRequest req) {
String userName = getUserName(req);
System.out.println("1. ---" + userName);
// 返回資訊帶上當前JVM所在機器的IP、程式號、時間
String message = String.format(RESPONSE_TEMPLETE,
userName,
getIpAddress(),
getPID(),
new SimpleDateFormat( "yyyy-MM-dd hh:mm:ss" ).format(new Date()));
System.out.println("2. ---" + message);
// 響應內容也是JSON格式,所以先存入map,然後再序列化
Map<String, Object> rlt = new HashMap<>();
rlt.put("success", true);
rlt.put("message", message);
String rltStr = null;
try {
rltStr = mapper.writeValueAsString(rlt);
} catch (Exception e) {
e.printStackTrace();
}
Response res = new Response();
res.setContentType("application/json;charset=utf-8");
res.setBody(rltStr);
return res;
}
}
- 至此編碼完成,接下來是製作映象和部署;
部署
- 在faas-currenttime.yml所在目錄執行以下命令,即可開始製作映象,製作過程中會有gradle的編譯過程,如果編譯失敗會中斷映象製作:
faas-cli build -f ./faas-currenttime.yml
- 映象製作成功時,控制檯輸出類似如下資訊:
Step 27/30 : ENV fprocess="java -XX:+UseContainerSupport com.openfaas.entrypoint.App"
---> Running in 0f50636cc747
Removing intermediate container 0f50636cc747
---> 54a5c9a193c8
Step 28/30 : EXPOSE 8080
---> Running in 3252f165af15
Removing intermediate container 3252f165af15
---> c05afc826ec5
Step 29/30 : HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1
---> Running in 4106410be0a2
Removing intermediate container 4106410be0a2
---> 6d95b73b5f33
Step 30/30 : CMD ["fwatchdog"]
---> Running in 1606dbcd7003
Removing intermediate container 1606dbcd7003
---> 99a519ab82fd
Successfully built 99a519ab82fd
Successfully tagged bolingcavalry/faas-currenttime:latest
Image: bolingcavalry/faas-currenttime:latest built.
[0] < Building faas-currenttime done in 34.94s.
[0] Worker done.
Total build time: 34.94s
- 將映象推送到映象倉庫,以便Kubernetes可以下載到此映象,我這裡用的是hub.docker.com,因為我的ID是bolingcavalry,所執行以下命令即可推送成功:
docker push bolingcavalry/faas-currenttime:latest
- 執行以下命令部署函式到OpenFaaS:
faas-cli deploy -f faas-currenttime.yml
- 控制檯響應如下,可見部署已經開始,並且給出了endpoint:
[root@node1 20]# faas-cli deploy -f faas-currenttime.yml
Deploying: faas-currenttime.
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.
Deployed. 202 Accepted.
URL: http://192.168.133.187:31112/function/faas-currenttime.openfaas-fn
- 開啟web端,在頁面上可見新增的函式,驗證操作如下圖所示,可見入參的JSON內容可以被正常解析:
- 也可以在控制檯用curl命令測試:
[root@node1 20]# curl \
> -H "Content-Type: application/json" \
> -X POST \
> --data '{"name":"Jerry}' \
> http://192.168.133.187:31112/function/faas-currenttime
{"success":true,"message":"Hello anonymous, response from [10.233.90.79], PID [11], 2020-11-20 02:14:46"}
- 執行命令faas-cli deploy -f faas-currenttime.yml開始部署,控制檯已經接受了部署請求,並給出了函式的endpoint:
[root@node1 20]# faas-cli deploy -f faas-currenttime.yml
Deploying: faas-currenttime.
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.
Deployed. 202 Accepted.
URL: http://192.168.133.187:31112/function/faas-currenttime.openfaas-fn
清理
- 刪除函式的命令如下,依舊是faas-currenttime.yml所在目錄:
faas-cli remove -f faas-currenttime.yml
- 至此,最基本的Java函式的開發、部署、驗證都已經完成,如果您也打算用Java開發OpenFaaS函式,希望本文能給您一些參考;
你不孤單,欣宸原創一路相伴
歡迎關注公眾號:程式設計師欣宸
微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos