Без сервера не новость, но справедливо сказать, что по-прежнему много шумихи по поводу того, как это все изменит, и как в будущем все будет без серверов. Помимо безсерверных / функций, предоставляемых облачными провайдерами, на нашем пути появляется все больше и больше безсерверных проектов, цель которых — избавить нас от привязки к поставщикам и позволить нам работать без серверов даже в помещении. Давайте посмотрим на один такой проект FN Project.
Что такое FN Project
Если мы перейдем на официальный сайт проекта FN http://fnproject.io/, мы можем прочитать что-то вроде этого:
«Проект Fn представляет собой серверную платформу с открытым исходным кодом, которую вы можете запускать где угодно — в любом облаке или локально. Он прост в использовании, поддерживает все языки программирования, является расширяемым и производительным ».
FN Project — это проект с открытым исходным кодом, поддерживаемый Oracle, основанный на контейнерах. Таким образом, теоретически все, что может стать контейнером и может читать и записывать из / в stdin / stdout, может стать функцией в проекте FN. Это очень хорошая функция, поскольку она означает, что теоретически она может поддерживать любой язык программирования, в отличие от безсерверных / функций, предоставляемых облачными провайдерами, где, если ваш предпочитаемый язык не поддерживается, вы не сможете использовать его с безсерверным.
Еще одна приятная особенность проекта FN заключается в том, что он может работать локально, либо в облаке, либо в нескольких облаках, либо в сочетании всего перечисленного.
Начальная настройка
Единственным предварительным условием для проекта FN является Docker 17.10.0-ce или новее.
Для настройки проекта FN нам нужно только скачать бинарный файл FN
и добавьте его к пути. После этого мы готовы начать играть с FN.
Начальная функция в проекте FN
Первое, что нам нужно сделать, это запустить сервер FN. Для этого нам нужно всего лишь набрать это в терминале / консоли
1
|
$ fn start |
Чтобы проверить, что все работает хорошо, мы можем запустить эту команду
1
|
$ fn version |
Это распечатает версию сервера fn и клиента fn, работающего на машине. В случае моего ноутбука я получаю эти значения
1
2
3
|
$ fn version Client version: 0.5 . 15 Server version: 0.3 . 595 |
Как только мы проверили, что все хорошо, мы можем начать создавать нашу первую функцию.
Первая функция в проекте FN
Как уже упоминалось, проект FN «независим от языка» , теоретически он может поддерживать любой язык, но это не значит, что он поддерживает все языки в настоящий момент. Чтобы увидеть, какие языки поддерживаются в имеющейся у нас версии, мы можем запустить следующую команду:
1
|
$ fn init --help |
Существует опция –runtime, в которой перечислены все опции, доступные на нашей машине. В моем случае я выберу язык программирования Java. Итак, чтобы создать первую функцию в Java, нам просто нужно запустить эту команду:
1
|
$ fn init --runtime java --trigger http function1 |
function1 — это имя функции, и здесь мы помещаем имя, которое хотим использовать. Опция –trigger http означает, что мы хотим создать HTTP-триггер для нашей функции, который позволит нам вызывать его по HTTP, например, через curl. После выполнения этой команды fn сгенерирует начальную функцию для нас и поместит ее в каталог, названный так, как мы назвали нашу функцию, в моем случае function1 .
Давайте посмотрим на то, что генерируется
1
2
3
4
5
6
7
|
$ cd function1 $ find . ./src/main/java/com/example/fn/HelloFunction.java ./src/test/java/com/example/fn/HelloFunctionTest.java ./pom.xml ./func.yaml |
Если мы откроем файл pom.xml, он будет выглядеть как любой другой файл pom.xml. Только зависимости там для проекта FN будут зависимостями для тестируемой части, нет никаких зависимостей для сборки или запуска нашей java-функции fn.
Если мы откроем HelloFunction.java , мы снова увидим, что это простой Java-класс с ZERO-зависимостями.
01
02
03
04
05
06
07
08
09
10
11
|
package com.example.fn; public class HelloFunction { public String handleRequest(String input) { String name = (input == null || input.isEmpty()) ? "world" : input; return "Hello, " + name + "!" ; } } |
Существует только один метод handleRequest, который принимает String в качестве входных данных и предоставляет String в качестве выходных данных. Это очень отличается от написания функций в реализации облачных провайдеров, поскольку они всегда добавляют определенные библиотеки или другие типы зависимостей, чтобы функции могли работать с их системой. В случае FN, поскольку нет никаких зависимостей, он может работать без проблем в любом месте, и вы ни на что не заглядываете.
«Магия» проекта FN
Так как же тогда работает FN? Как он знает, как запустить нашу функцию?
Вся магия в файле func.yaml . Или, если быть более точным, все настройки, необходимые для создания функции в проекте FN. Давайте посмотрим на это поближе.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
$ cat func.yaml schema_version: 20180708 name: function1 version: 0.0 . 1 runtime: java build_image: fnproject/fn-java-fdk-build:jdk9- 1.0 . 75 run_image: fnproject/fn-java-fdk:jdk9- 1.0 . 75 cmd: com.example.fn.HelloFunction::handleRequest format: http-stream triggers: - name: function1-trigger type: http source: /function1-trigger |
Здесь есть несколько полей:
- schema_version указывает, какая версия Fn использовалась для создания этого файла
- имя это имя нашей функции
- версия — это текущая версия нашей функции, и при ее развертывании она будет автоматически инкрементирована
- язык выполнения, который мы выбрали для написания нашей функции
- Образ докера build_image, используемый для построения нашей функции, зависит, конечно, от выбранного языка
- Образ докера run_image, используемый для запуска нашей функции
- cmd точка входа в нашу функцию, что нужно вызвать для выполнения нашей бизнес-логики
- триггеры здесь определены триггеры для вызова нашей функции, в нашем случае у нас есть триггер HTTP
Модульные испытания в проекте FN
Возможно, вы заметили, что один из сгенерированных файлов — HelloFunctionTest.java , этот файл действительно является файлом модульного теста для нашей функции, который также автоматически сгенерирован для нас, и содержит простой пример модульного теста. Давайте посмотрим на этот файл.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public class HelloFunctionTest { @Rule public final FnTestingRule testing = FnTestingRule.createDefault(); @Test public void shouldReturnGreeting() { testing.givenEvent().enqueue(); testing.thenRun(HelloFunction. class , "handleRequest" ); FnResult result = testing.getOnlyResult(); assertEquals( "Hello, world!" , result.getBodyAsString()); } } |
За исключением некоторых зависимостей fn и части с @Rule , все остальное похоже на любой другой тест JUnit в java. Этот модульный тест просто вызовет нашу функцию без передачи каких-либо параметров и проверит, является ли результат «Hello world!». Самое замечательное в этом тесте состоит в том, что мы можем запустить его как любой другой модульный тест, мы можем вызвать его из maven или IDE любым стандартным способом.
Давайте теперь напишем тест, в котором мы передадим несколько аргументов и подтвердим, что наша функция все еще работает, как и ожидалось. Для этого мы можем добавить этот код в наш тестовый класс
1
2
3
4
5
6
7
8
9
|
@Test public void shouldReturnGreetingwithBodyValue() { testing.givenEvent().withBody( "Java" ).enqueue(); testing.thenRun(HelloFunction. class , "handleRequest" ); FnResult result = testing.getOnlyResult(); assertEquals( "Hello, Java!" , result.getBodyAsString()); } |
Опять же, мы можем запустить его как любой другой модульный тест и проверить, что все хорошо.
Развертывание и вызов функции FN
Теперь, когда мы определили нашу функцию, мы понимаем, какие файлы генерируются и какова их цель, мы также провели модульное тестирование. Тогда нам пора развернуть и вызвать функцию. Мы можем развернуть нашу функцию в облачном и докерском реестре, но гораздо проще и быстрее развернуть ее только локально, особенно когда мы заняты разработкой. Для развертывания функции нам просто нужно запустить эту команду
1
|
$ fn deploy --app myapp1 --local |
Здесь мы говорим fn развернуть нашу функцию в приложении myapp1 и развернуть ее только локально, указав параметр –local . Как только мы успешно развернули нашу функцию, мы можем вызвать ее. Чтобы вызвать его, мы можем запустить следующую команду
1
|
$ fn invoke myapp1 function1 |
Мы предоставляем название нашего приложения и название нашей функции. Если мы хотим внести свой вклад в нашу функцию, мы можем сделать это следующим образом
1
|
$ echo "Java is great" | fn invoke myapp1 function1 |
Если вы помните, мы также создали триггер HTTP, поэтому давайте использовать его для вызова нашей функции.
1
|
$ curl http: //localhost:8080/t/myapp1/function1-trigger |
Функция FN с JSON
Мы уже можем сделать много хороших вещей с этим, но давайте перейдем к следующему уровню, где мы будем использовать JSON в качестве ввода и вывода наших функций FN. Во-первых, нам нужно создать простой класс POJO, что-то вроде этого
01
02
03
04
05
06
07
08
09
10
11
12
|
public class Hello { private String message; public String getMessage() { return message; } public void setMessage(String message) { this .message = message; } } |
Теперь мы можем изменить нашу функцию, чтобы она воспринимала этот класс как ввод и вывод, чтобы функция выглядела так:
01
02
03
04
05
06
07
08
09
10
|
public Hello handleRequest(Hello input) { String name = (input == null || input.getMessage().isEmpty()) ? "world" : input.getMessage(); Hello hello = new Hello(); hello.setMessage(message + ", " + name + "!" ) return hello; } |
после того, как мы развернем функцию, мы можем вызвать ее так
1
2
|
$ curl -d '{"message":"JSON Input"}' \ http: //localhost:8080/t/myapp1/function1-trigger |
Ссылки и будущие чтения
Как мы увидели, начинать разработку функций с помощью проекта FN очень легко и увлекательно, также за небольшое время мы можем создавать мощные функции.
То, что мы увидели здесь, является лишь частью возможностей проекта FN, для получения дополнительной информации о FN в целом и дополнительной информации о возможностях, которые я бы предложил посмотреть на сайтах, перечисленных ниже
- http://fnproject.io/
- https://github.com/fnproject/fn
- https://github.com/vladimir-dejanovic/java-in-fn-project
Опубликовано на Java Code Geeks с разрешения Владимира Деяновича, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Serverless, Java и FN Project, первые шаги
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |