mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
More doc updates, explanation of serverless. (#228)
* More doc updates, explanation of serverless. * Moved howto directory to examples and some minor doc updates. * Added apps and routes docs. * Fixes for Carlos' comments. * Added bit about importing lambda functions.
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
|
||||
# IronFunctions Documentation
|
||||
|
||||
* [IronFunctions Run Options](options.md)
|
||||
* [Writing Functions](function-format.md)
|
||||
## For Developers
|
||||
|
||||
If you are a developer using IronFunctions through the API, this section is for you.
|
||||
|
||||
* [Quickstart](https://github.com/iron-io/functions#quickstart)
|
||||
* [CLI tool - fnctl](../fnctl/README.md)
|
||||
* [Writing functions](writing.md)
|
||||
* [Packaging functions](packaging.md)
|
||||
* [Open Function Format](function-format.md)
|
||||
* [API Reference](https://app.swaggerhub.com/api/iron/functions/)
|
||||
|
||||
## For Operators
|
||||
|
||||
If you are operating IronFunctions, this section is for you.
|
||||
|
||||
* [Running in Production](production.md)
|
||||
* [Databases](databases/README.md)
|
||||
* [Message Queues](mqs/README.md)
|
||||
* [Logging](logging.md)
|
||||
* [Metrics](metrics.md)
|
||||
* [Function Memory Requirements](memory.md)
|
||||
* [Triggers](triggers.md)
|
||||
* [Extending IronFunctions](extending.md)
|
||||
* [Docker Configuration](docker.md)
|
||||
* [Function Format](function-format.md)
|
||||
|
||||
9
docs/apps.md
Normal file
9
docs/apps.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Applications
|
||||
|
||||
Applications are the top level object that groups routes together to create an API.
|
||||
|
||||
## App level configuration
|
||||
|
||||
When creating or updating an app, you can pass in a map of config variables.
|
||||
|
||||
TODO: link to swagger doc on swaggerhub after it's updated.
|
||||
21
docs/faq.md
Normal file
21
docs/faq.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
## Which languages are supported?
|
||||
|
||||
Since we use containers are the base building block, all languages can be used. There there may not be higher level
|
||||
helper libraries like our Lambda wrapper for every language, but you can use any language if you follow the
|
||||
base [function format](function-format.md).
|
||||
|
||||
## Where can I run IronFunctions?
|
||||
|
||||
Anywhere. Any cloud, on-premise, on your laptop. As long as you can run a Docker container, you can run IronFunctions.
|
||||
|
||||
## Which orchestration platforms does IronFunctions support?
|
||||
|
||||
IronFunctions can run using any orchestration tool, any server
|
||||
|
||||
## Does IronFunctions require Docker?
|
||||
|
||||
For now, we do require Docker primarily for the packaging and distribution via Docker Registries.
|
||||
But we've built IronFunctions in a way that abstracts the container technology so we can support others as
|
||||
needed. For instance, we'll probably add rkt support shortly.
|
||||
5
docs/howto/go/.gitignore
vendored
5
docs/howto/go/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
vendor/
|
||||
/hello
|
||||
/go
|
||||
/app
|
||||
/__uberscript__
|
||||
@@ -1,6 +0,0 @@
|
||||
FROM iron/go
|
||||
|
||||
WORKDIR /app
|
||||
ADD . /app
|
||||
|
||||
ENTRYPOINT ["./hello"]
|
||||
@@ -1,40 +0,0 @@
|
||||
## Quick Example for a Go Function (3 minutes)
|
||||
|
||||
This example will show you how to test and deploy Go (Golang) code to IronFunctions.
|
||||
|
||||
### 1. Prepare the `functions.yaml` file:
|
||||
|
||||
At functions.yaml you will find:
|
||||
```yml
|
||||
app: goapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/go/src/ -w /go/src/ -e "GOPATH=/go/src/vendor:/go" iron/go:dev go build -o hello
|
||||
```
|
||||
|
||||
The important step here is to ensure you replace `USERNAME` with your Docker Hub account name. Some points of note:
|
||||
the application name is `goapp` and the route for incoming requests is `/hello`. These informations are relevant for
|
||||
the moment you try to test this function.
|
||||
|
||||
### 2. Build:
|
||||
|
||||
```sh
|
||||
fnctl publish
|
||||
```
|
||||
|
||||
`-v` is optional, but it allows you to see how this function is being built.
|
||||
|
||||
### 3. Queue jobs for your function
|
||||
|
||||
Now you can start jobs on your function. Let's quickly queue up a job to try it out.
|
||||
|
||||
```sh
|
||||
cat hello.payload.json | fnctl run goapp /hello
|
||||
```
|
||||
|
||||
Here's a curl example to show how easy it is to do in any language:
|
||||
|
||||
```sh
|
||||
curl -H "Content-Type: application/json" -X POST -d @hello.payload.json http://localhost:8080/r/goapp/hello
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
app: goapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/go/src/ -w /go/src/ -e "GOPATH=/go/src/vendor:/go" iron/go:dev go build -o hello
|
||||
@@ -1,17 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
p := &Person{Name: "World"}
|
||||
json.NewDecoder(os.Stdin).Decode(p)
|
||||
fmt.Println("Hello", p.Name, "!!!")
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "Johnny"
|
||||
}
|
||||
1
docs/howto/node/.gitignore
vendored
1
docs/howto/node/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
node_modules/
|
||||
@@ -1,6 +0,0 @@
|
||||
FROM iron/node
|
||||
|
||||
WORKDIR /app
|
||||
ADD . /app
|
||||
|
||||
ENTRYPOINT ["node", "hello.js"]
|
||||
@@ -1,40 +0,0 @@
|
||||
## Quick Example for a NodeJS Function (4 minutes)
|
||||
|
||||
This example will show you how to test and deploy Go (Golang) code to IronFunctions.
|
||||
|
||||
### 1. Prepare the `functions.yaml` file:
|
||||
|
||||
At functions.yaml you will find:
|
||||
```yml
|
||||
app: nodeapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/worker -w /worker iron/node:dev npm install
|
||||
```
|
||||
|
||||
The important step here is to ensure you replace `USERNAME` with your Docker Hub account name. Some points of note:
|
||||
the application name is `nodeapp` and the route for incoming requests is `/hello`. These informations are relevant for
|
||||
the moment you try to test this function.
|
||||
|
||||
### 2. Build:
|
||||
|
||||
```sh
|
||||
fnctl publish
|
||||
```
|
||||
|
||||
`-v` is optional, but it allows you to see how this function is being built.
|
||||
|
||||
### 3. Queue jobs for your function
|
||||
|
||||
Now you can start jobs on your function. Let's quickly queue up a job to try it out.
|
||||
|
||||
```sh
|
||||
cat hello.payload.json | fnctl run nodeapp /hello
|
||||
```
|
||||
|
||||
Here's a curl example to show how easy it is to do in any language:
|
||||
|
||||
```sh
|
||||
curl -H "Content-Type: application/json" -X POST -d @hello.payload.json http://localhost:8080/r/nodeapp/hello
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
app: nodeapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/worker -w /worker iron/node:dev npm install
|
||||
@@ -1,9 +0,0 @@
|
||||
name = "World";
|
||||
fs = require('fs');
|
||||
try {
|
||||
obj = JSON.parse(fs.readFileSync('/dev/stdin').toString())
|
||||
if (obj.name != "") {
|
||||
name = obj.name
|
||||
}
|
||||
} catch(e) {}
|
||||
console.log("Hello", name, "from Node!");
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "Johnny"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
1
docs/howto/php/.gitignore
vendored
1
docs/howto/php/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
vendor/
|
||||
@@ -1,6 +0,0 @@
|
||||
FROM iron/php
|
||||
|
||||
WORKDIR /app
|
||||
ADD . /app
|
||||
|
||||
ENTRYPOINT ["php", "hello.php"]
|
||||
@@ -1,40 +0,0 @@
|
||||
## Quick Example for a PHP Function (4 minutes)
|
||||
|
||||
This example will show you how to test and deploy Go (Golang) code to IronFunctions.
|
||||
|
||||
### 1. Prepare the `functions.yaml` file:
|
||||
|
||||
At functions.yaml you will find:
|
||||
```yml
|
||||
app: phpapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/worker -w /worker iron/php:dev composer install
|
||||
```
|
||||
|
||||
The important step here is to ensure you replace `USERNAME` with your Docker Hub account name. Some points of note:
|
||||
the application name is `phpapp` and the route for incoming requests is `/hello`. These informations are relevant for
|
||||
the moment you try to test this function.
|
||||
|
||||
### 2. Build:
|
||||
|
||||
```sh
|
||||
fnctl publish
|
||||
```
|
||||
|
||||
`-v` is optional, but it allows you to see how this function is being built.
|
||||
|
||||
### 3. Queue jobs for your function
|
||||
|
||||
Now you can start jobs on your function. Let's quickly queue up a job to try it out.
|
||||
|
||||
```sh
|
||||
cat hello.payload.json | fnctl run phpapp /hello
|
||||
```
|
||||
|
||||
Here's a curl example to show how easy it is to do in any language:
|
||||
|
||||
```sh
|
||||
curl -H "Content-Type: application/json" -X POST -d @hello.payload.json http://localhost:8080/r/phpapp/hello
|
||||
```
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"require": {
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
app: phpapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/worker -w /worker iron/php:dev composer install
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "Johnny"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
stream_set_blocking(STDIN, 0);
|
||||
$payload = json_decode(file_get_contents("php://stdin"), true);
|
||||
if (isset($payload['name'])) {
|
||||
echo "Hello ", $payload['name'],"!\n\n";
|
||||
} else {
|
||||
echo "Hello World!\n\n";
|
||||
}
|
||||
1
docs/howto/python/.gitignore
vendored
1
docs/howto/python/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
packages/
|
||||
@@ -1,6 +0,0 @@
|
||||
FROM iron/python:2
|
||||
|
||||
WORKDIR /app
|
||||
ADD . /app
|
||||
|
||||
ENTRYPOINT ["python", "hello.py"]
|
||||
@@ -1,40 +0,0 @@
|
||||
## Quick Example for a Python Function (4 minutes)
|
||||
|
||||
This example will show you how to test and deploy Go (Golang) code to IronFunctions.
|
||||
|
||||
### 1. Prepare the `functions.yaml` file:
|
||||
|
||||
At functions.yaml you will find:
|
||||
```yml
|
||||
app: pythonapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/worker -w /worker iron/python:2-dev pip install -t packages -r requirements.txt
|
||||
```
|
||||
|
||||
The important step here is to ensure you replace `USERNAME` with your Docker Hub account name. Some points of note:
|
||||
the application name is `pythonapp` and the route for incoming requests is `/hello`. These informations are relevant for
|
||||
the moment you try to test this function.
|
||||
|
||||
### 2. Build:
|
||||
|
||||
```sh
|
||||
fnctl publish
|
||||
```
|
||||
|
||||
`-v` is optional, but it allows you to see how this function is being built.
|
||||
|
||||
### 3. Queue jobs for your function
|
||||
|
||||
Now you can start jobs on your function. Let's quickly queue up a job to try it out.
|
||||
|
||||
```sh
|
||||
cat hello.payload.json | fnctl run pythonapp /hello
|
||||
```
|
||||
|
||||
Here's a curl example to show how easy it is to do in any language:
|
||||
|
||||
```sh
|
||||
curl -H "Content-Type: application/json" -X POST -d @hello.payload.json http://localhost:8080/r/pythonapp/hello
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
app: pythonapp
|
||||
route: /hello
|
||||
image: USERNAME/hello:0.0.1
|
||||
build:
|
||||
- docker run --rm -v "$PWD":/worker -w /worker iron/python:2-dev pip install -t packages -r requirements.txt
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "Johnny"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import sys
|
||||
sys.path.append("packages")
|
||||
import os
|
||||
import json
|
||||
|
||||
name = "World"
|
||||
if not os.isatty(sys.stdin.fileno()):
|
||||
obj = json.loads(sys.stdin.read())
|
||||
if obj["name"] != "":
|
||||
name = obj["name"]
|
||||
|
||||
print "Hello", name, "!!!"
|
||||
48
docs/lambda/README.md
Normal file
48
docs/lambda/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Lambda everywhere.
|
||||
|
||||
AWS Lambda introduced serverless computing to the masses. Wouldn't it be nice
|
||||
if you could run the same Lambda functions on any platform, in any cloud?
|
||||
Iron.io is proud to release a set of tools that allow just this. Package your
|
||||
Lambda function in a Docker container and run it anywhere with an environment
|
||||
similar to AWS Lambda.
|
||||
|
||||
Using a job scheduler such as IronFunctions, you can connect these functions to
|
||||
webhooks and run them on-demand, at scale. You can also use a container
|
||||
management system paired with a task queue to run these functions in
|
||||
a self-contained, platform-independent manner.
|
||||
|
||||
## Use cases
|
||||
|
||||
Lambda functions are great for writing "worker" processes that perform some
|
||||
simple, parallelizable task like image processing, ETL transformations,
|
||||
asynchronous operations driven by Web APIs, or large batch processing.
|
||||
|
||||
All the benefits that containerization brings apply here. Our tools make it
|
||||
easy to write containerized applications that will run anywhere without having
|
||||
to fiddle with Docker and get the various runtimes set up. Instead you can just
|
||||
write a simple function and have an "executable" ready to go.
|
||||
|
||||
## How does it work?
|
||||
|
||||
We provide base Docker images for the various runtimes that AWS Lambda
|
||||
supports. The `fnctl` tool helps package up your Lambda function into
|
||||
a Docker image layered on the base image. We provide a bootstrap script and
|
||||
utilities that provide a AWS Lambda environment to your code. You can then run
|
||||
the Docker image on any platform that supports Docker. This allows you to
|
||||
easily move Lambda functions to any cloud provider, or host it yourself.
|
||||
|
||||
## Next steps
|
||||
|
||||
Write, package and run your Lambda functions with our [Getting started
|
||||
guide](./getting-started.md). [Here is the environment](./environment.md) that
|
||||
Lambda provides. `fnctl lambda` lists the commands to work with Lambda
|
||||
functions locally.
|
||||
|
||||
You can [import](./import.md) existing Lambda functions hosted on Amazon!
|
||||
The Docker environment required to run Lambda functions is described
|
||||
[here](./docker.md).
|
||||
|
||||
Non-AWS Lambda functions can continue to interact with AWS services. [Working
|
||||
with AWS](./aws.md) describes how to access AWS credentials, interact with
|
||||
services like S3 and how to launch a Lambda function due a notification from
|
||||
SNS.
|
||||
22
docs/lambda/create.md
Normal file
22
docs/lambda/create.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Creating Docker images out of Lambda functions
|
||||
Docker images created by running the `create-function` subcommand on a Lambda function are ready to execute.
|
||||
|
||||
You can convert any Lambda function of type nodejs 0.10, python 2.7 and Java 8 into an
|
||||
IronFunction compatible Docker Image as follows:
|
||||
```bash
|
||||
fnctl lambda create-function <name> <runtime> <handler> <files...>
|
||||
```
|
||||
|
||||
* name: the name of the created docker image which should have the format `<username>/<image-name>`
|
||||
* runtime: any of the following `nodejs`, `python2.7` or `java8`
|
||||
* handler: a handler takes a different form per runtime
|
||||
* java8: `<namespace>.<class>::<handler>`
|
||||
* python2.7: `<filename>.<handler>`
|
||||
* nodejs: `<filename>.<handler>`
|
||||
* file: the files to be converted, however for java8 only one file of type `jar` is allowed.
|
||||
|
||||
e.g:
|
||||
```bash
|
||||
fnctl lambda create-function irontest/node-exec:1 nodejs node_exec.handler node_exec.js
|
||||
```
|
||||
|
||||
170
docs/lambda/environment.md
Normal file
170
docs/lambda/environment.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Environment
|
||||
|
||||
The base images strive to provide the same environment that AWS provides to
|
||||
Lambda functions. This page describes it and any incompatibilities between AWS
|
||||
Lambda and Dockerized Lambda.
|
||||
|
||||
## Request/Response
|
||||
|
||||
IronFunctions has sync/async communication with Request/Response workflows.
|
||||
* sync: returns the result as the body of the response
|
||||
* async: returns the task id in the body of the response as a json
|
||||
|
||||
The `context.succeed()` will not do anything with result
|
||||
on node.js, nor will returning anything from a Python function.
|
||||
|
||||
## Paths
|
||||
|
||||
We do not make any compatibility efforts towards running your lambda function
|
||||
in the same working directory as it would run on AWS. If your function makes
|
||||
such assumptions, please rewrite it.
|
||||
|
||||
## nodejs
|
||||
|
||||
* node.js version [0.10.42][iron/node]
|
||||
* ImageMagick version [6.9.3][magickv] and nodejs [wrapper 6.9.3][magickwrapperv]
|
||||
* aws-sdk version [2.2.12][awsnodev]
|
||||
|
||||
[iron/node]: https://github.com/iron-io/dockers/blob/master/node/Dockerfile
|
||||
[magickv]: https://pkgs.alpinelinux.org/package/main/x86_64/imagemagick
|
||||
[magickwrapperv]: https://www.npmjs.com/package/imagemagick
|
||||
[awsnodev]: https://aws.amazon.com/sdk-for-node-js/
|
||||
|
||||
### Event
|
||||
|
||||
Payloads MUST be a valid JSON object literal.
|
||||
|
||||
### Context object
|
||||
|
||||
* context.fail() does not currently truncate error logs.
|
||||
* `context.functionName` is of the form of a docker image, for example
|
||||
`iron/test-function`.
|
||||
* `context.functionVersion` is always the string `"$LATEST"`.
|
||||
* `context.invokedFunctionArn` is not supported. Value is empty string.
|
||||
* `context.memoryLimitInMB` does not reflect reality. Value is always `256`.
|
||||
* `context.awsRequestId` reflects the environment variable `TASK_ID`. On local
|
||||
runs from `ironcli` this is a UUID. On IronFunctions this is the task ID.
|
||||
* `logGroupName` and `logStreamName` are empty strings.
|
||||
* `identity` and `clientContext` are always `null`.
|
||||
|
||||
### Exceptions
|
||||
|
||||
If your handler throws an exception, we only log the error message. There is no
|
||||
`v8::CallSite` compatible stack trace yet.
|
||||
|
||||
## Python 2.7
|
||||
|
||||
* CPython [2.7.11][pythonv]
|
||||
* boto3 (Python AWS SDK) [1.2.3][botov].
|
||||
|
||||
[pythonv]: https://hub.docker.com/r/iron/python/tags/
|
||||
[botov]: https://github.com/boto/boto3/releases/tag/1.2.3
|
||||
|
||||
### Event
|
||||
|
||||
Event is always a `__dict__` and the payload MUST be a valid JSON object
|
||||
literal.
|
||||
|
||||
### Context object
|
||||
|
||||
* `context.functionName` is of the form of a docker image, for example
|
||||
`iron/test-function`.
|
||||
* `context.functionVersion` is always the string `"$LATEST"`.
|
||||
* `context.invokedFunctionArn` is `None`.
|
||||
* `context.awsRequestId` reflects the environment variable `TASK_ID` which is
|
||||
set to the task ID on IronFunctions. If TASK_ID is empty, a new UUID is used.
|
||||
* `logGroupName`, `logStreamName`, `identity` and `clientContext` are `None`.
|
||||
|
||||
### Exceptions
|
||||
|
||||
If your Lambda function throws an Exception, it will not currently be logged as
|
||||
a JSON object with trace information.
|
||||
|
||||
## Java 8
|
||||
|
||||
* OpenJDK Java Runtime [1.8.0][javav]
|
||||
|
||||
[javav]: https://hub.docker.com/r/iron/java/tags/
|
||||
|
||||
The Java8 runtime is significantly lacking at this piont and we **do not
|
||||
recommend** using it.
|
||||
|
||||
### Handler types
|
||||
|
||||
There are some restrictions on the handler types supported.
|
||||
|
||||
#### Only a void return type is allowed
|
||||
|
||||
Since Lambda does not support request/response invocation, we explicitly
|
||||
prohibit a non-void return type on the handler.
|
||||
|
||||
#### JSON parse error stack differences
|
||||
|
||||
AWS uses the Jackson parser, this project uses the GSON parser. So JSON parse
|
||||
errors will have different traces.
|
||||
|
||||
#### Single item vs. List
|
||||
|
||||
Given a list handler like:
|
||||
|
||||
```java
|
||||
public static void myHandler(List<Double> l) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
If the payload is a single number, AWS Lambda will succeed and pass the handler
|
||||
a list with a single item. This project will raise an exception.
|
||||
|
||||
#### Collections of POJOs
|
||||
|
||||
This project cannot currently deserialize a List or Map containing POJOs. For
|
||||
example:
|
||||
|
||||
```java
|
||||
public class Handler {
|
||||
public static MyPOJO {
|
||||
private String attribute;
|
||||
public void setAttribute(String a) {
|
||||
attribute = a;
|
||||
}
|
||||
|
||||
public String getAttribute() {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
|
||||
public static void myHandler(List<MyPOJO> l) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This handler invoked with the below event will fail!
|
||||
|
||||
```js
|
||||
[{ "attribute": "value 1"}, { "attribute": "value 2" }]
|
||||
```
|
||||
|
||||
#### Leveraging predefined types is not supported
|
||||
|
||||
Using the types in `aws-lambda-java-core` to [implement handlers][predef] is
|
||||
untested and unsupported right now. While the package is available in your
|
||||
function, we have not tried it out.
|
||||
|
||||
[predef]: http://docs.aws.amazon.com/lambda/latest/dg/java-handler-using-predefined-interfaces.html
|
||||
|
||||
### Logging
|
||||
|
||||
The [log4j and LambdaLogger
|
||||
styles](http://docs.aws.amazon.com/lambda/latest/dg/java-logging.html) that log
|
||||
to CloudWatch are not supported.
|
||||
|
||||
### Context object
|
||||
|
||||
* `context.getFunctionName()` returns a String of the form of a docker image,
|
||||
for example `iron/test-function`.
|
||||
* `context.getFunctionVersion()` is always the string `"$LATEST"`.
|
||||
* `context.getAwsRequestId()` reflects the environment variable `TASK_ID` which is
|
||||
set to the task ID on IronFunctions. If TASK_ID is empty, a new UUID is used.
|
||||
* `getInvokedFunctionArn()`, `getLogGroupName()`, `getLogStreamName()`, `getIdentity()`, `getClientContext()`, `getLogger()` return `null`.
|
||||
128
docs/lambda/getting-started.md
Normal file
128
docs/lambda/getting-started.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Introduction
|
||||
|
||||
This guide will walk you through creating and testing a simple Lambda function.
|
||||
|
||||
We need the the `fnctl` tool for the rest of this guide. You can install it
|
||||
by following [these instructions](https://github.com/iron-io/function/fnctl).
|
||||
|
||||
*For this getting started we are assuming you already have working lambda function code available, if not head to the [import instructions] (import.md) and skip the next section.*
|
||||
|
||||
## Creating the function
|
||||
|
||||
Let's convert the `hello_world` AWS Lambda example to Docker.
|
||||
|
||||
```python
|
||||
def my_handler(event, context):
|
||||
message = 'Hello {} {}!'.format(event['first_name'],
|
||||
event['last_name'])
|
||||
return {
|
||||
'message' : message
|
||||
}
|
||||
```
|
||||
|
||||
Create an empty directory for your project and save this code in a file called
|
||||
`hello_world.py`.
|
||||
|
||||
Now let's use `fnctl`'s Lambda functionality to create a Docker image. We can
|
||||
then run the Docker image with a payload to execute the Lambda function.
|
||||
|
||||
```sh
|
||||
$ fnctl lambda create-function irontest/hello_world:1 python2.7 hello_world.my_handler hello_world.py
|
||||
Creating directory: irontest/hello_world:1 ... OK
|
||||
Creating Dockerfile: irontest/hello_world:1/Dockerfile ... OK
|
||||
Copying file: irontest/hello_world/hello_world:1.py ... OK
|
||||
Creating function.yaml ... OK
|
||||
```
|
||||
|
||||
As you can see, this is very similar to creating a Lambda function using the
|
||||
`aws` CLI tool. We name the function as we would name other Docker images. The
|
||||
`1` indicates the version. You can use any string. This way you can configure
|
||||
your deployment environment to use different versions. The handler is
|
||||
the name of the function to run, in the form that python expects
|
||||
(`module.function`). Where you would package the files into a `.zip` to upload
|
||||
to Lambda, we just pass the list of files to `fnctl`.
|
||||
|
||||
## Publishing the function to IronFunctions
|
||||
|
||||
Next we want to publish the function to our IronFunctions
|
||||
```sh
|
||||
$ fnctl publish -v -f -d ./irontest
|
||||
publishing irontest/hello_world:1/function.yaml
|
||||
Sending build context to Docker daemon 4.096 kB
|
||||
Step 1 : FROM iron/lambda-python2.7
|
||||
latest: Pulling from iron/lambda-python2.7
|
||||
c52e3ed763ff: Pull complete
|
||||
789cf808491a: Pull complete
|
||||
d1b635efed57: Pull complete
|
||||
fe23c3dbcfa8: Pull complete
|
||||
63c874a9687e: Pull complete
|
||||
a6d462dae1df: Pull complete
|
||||
Digest: sha256:c5dde3bf3be776c0f6b909d4ad87255a0af9b6696831fbe17c5f659655a0494a
|
||||
Status: Downloaded newer image for iron/lambda-python2.7:latest
|
||||
---> 66d3adf47835
|
||||
Step 2 : ADD hello_world.py ./hello_world:1.py
|
||||
---> 91a592e0dfa9
|
||||
Removing intermediate container 1a1ef40ff0dd
|
||||
Step 3 : CMD hello_world.my_handler
|
||||
---> Running in 318da1bba060
|
||||
---> db9b9644168e
|
||||
Removing intermediate container 318da1bba060
|
||||
Successfully built db9b9644168e
|
||||
The push refers to a repository [docker.io/irontest/hello_world:1]
|
||||
5d9d142e21b2: Pushed
|
||||
11d8145d6038: Layer already exists
|
||||
23885f85dbd0: Layer already exists
|
||||
6a350a8d14ee: Layer already exists
|
||||
e67f7ef625c5: Layer already exists
|
||||
321db514ef85: Layer already exists
|
||||
6102f0d2ad33: Layer already exists
|
||||
latest: digest: sha256:5926ff413f134fa353e4b42f2d4a0d2d4f5b3a39489cfdf6dd5b4a63c4e40dee size: 1784
|
||||
updating API with appName: irontest route: /hello_world:1 image: irontest/hello_world:1
|
||||
path result
|
||||
irontest/hello_world:1/function.yaml done
|
||||
```
|
||||
|
||||
This will publish the generated function under the app `irontest` with `hello_world` as a route, e.g:
|
||||
`http://<hostname>/r/irontest/hello_world:1`,
|
||||
|
||||
You should also now see the generated Docker image.
|
||||
|
||||
```sh
|
||||
$ docker images
|
||||
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
|
||||
irontest/hello_world:1 latest db9b9644168e About a minute ago 108.4 MB
|
||||
...
|
||||
```
|
||||
|
||||
## Testing the function
|
||||
|
||||
The `test-function` subcommand can launch the Dockerized function with the
|
||||
right parameters.
|
||||
|
||||
```sh
|
||||
$ fnctl lambda test-function irontest/hello_world:1 --payload '{ "first_name": "Jon", "last_name": "Snow" }'
|
||||
{"message": "Hello Jon Snow!"}
|
||||
```
|
||||
|
||||
You should see the output.
|
||||
|
||||
## Calling the function from IronFunctions
|
||||
|
||||
The `fnctl call` command can call the published version with a given payload.
|
||||
|
||||
```sh
|
||||
$ echo '{ "first_name": "Jon", "last_name": "Snow" }' | ./fnctl call irontest /hello_world:1
|
||||
{"message": "Hello Jon Snow!"}
|
||||
```
|
||||
|
||||
You should see the output.
|
||||
|
||||
|
||||
## Commands documentation
|
||||
* [create-function](create.md)
|
||||
* [test-function](test.md)
|
||||
* [aws-import](import.md)
|
||||
|
||||
## More documentation
|
||||
* [env](environment.md)
|
||||
* [aws](aws.md)
|
||||
50
docs/lambda/import.md
Normal file
50
docs/lambda/import.md
Normal file
@@ -0,0 +1,50 @@
|
||||
Import existing AWS Lambda functions
|
||||
====================================
|
||||
|
||||
The [fnctl](https://github.com/iron-io/functions/fnctl/) tool includes a set of
|
||||
commands to act on Lambda functions. Most of these are described in
|
||||
[getting-started](./getting-started.md). One more subcommand is `aws-import`.
|
||||
|
||||
If you have an existing AWS Lambda function, you can use this command to
|
||||
automatically convert it to a Docker image that is ready to be deployed on
|
||||
other platforms.
|
||||
|
||||
### Credentials
|
||||
|
||||
To use this, either have your AWS access key and secret key set in config
|
||||
files, or in environment variables. In addition, you'll want to set a default
|
||||
region. You can use the `aws` tool to set this up. Full instructions are in the
|
||||
[AWS documentation][awscli].
|
||||
|
||||
[awscli]: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files
|
||||
|
||||
### Importing
|
||||
|
||||
The aws-import command is constructed as follows:
|
||||
|
||||
```bash
|
||||
fnctl lambda aws-import <arn> <region> <image>
|
||||
```
|
||||
|
||||
* arn: describes the ARN formats which uniquely identify the AWS lambda resource
|
||||
* region: region on which the lambda is hosted
|
||||
* image: the name of the created docker image which should have the format <username>/<image-name>
|
||||
|
||||
Assuming you have a lambda with the following arn `arn:aws:lambda:us-west-2:123141564251:function:my-function`, the following command:
|
||||
|
||||
```sh
|
||||
fnctl lambda aws-import arn:aws:lambda:us-west-2:123141564251:function:my-function us-east-1 user/my-function
|
||||
```
|
||||
|
||||
will import the function code from the region `us-east-1` to a directory called `./my-function`. It will
|
||||
then create a docker image called `my-function`.
|
||||
|
||||
Using Lambda with Docker Hub and IronFunctions requires that the Docker image be
|
||||
named `<Docker Hub username>/<image name>`. This is used to uniquely identify
|
||||
images on Docker Hub. Please use the `<Docker Hub username>/<image
|
||||
name>` as the image name with `aws-import` to create a correctly named image.
|
||||
|
||||
If you only want to download the code, pass the `--download-only` flag. The
|
||||
`--profile` flag is available similar to the `aws` tool to help
|
||||
you tweak the settings on a command level. Finally, you can import a different version of your lambda function than the latest one
|
||||
by passing `--version <version>.`
|
||||
65
docs/lambda/test.md
Normal file
65
docs/lambda/test.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Testing the Lambda Docker images
|
||||
|
||||
The `test-function` subcommand can pass the correct parameters to `docker run`
|
||||
to run those images with the payload and environment variables set up
|
||||
correctly. If you would like more control, like mounting volumes, or adding
|
||||
more environment variables this guide describes how to directly run these
|
||||
images using:
|
||||
```sh
|
||||
docker run
|
||||
```
|
||||
|
||||
An example of a valid `test-function` command would look as follows:
|
||||
```
|
||||
fnctl lambda test-function user/my-function --payload='{"firstName":"John", "lastName":"Yo" }'
|
||||
```
|
||||
|
||||
## Payload
|
||||
|
||||
The payload is passed via stdin.
|
||||
It is also possible to pass the payload by using the `payload` argument. Using it the payload is written to a random, opaque directory on the host.
|
||||
The file itself is called `payload.json`. This directory is mapped to the
|
||||
`/mnt` volume in the container, so that the payload is available in
|
||||
`/mnt/payload.json`. This is not REQUIRED, since the actual runtimes use the
|
||||
`PAYLOAD_FILE` environment variable to discover the payload location.
|
||||
|
||||
|
||||
## Environment variables
|
||||
|
||||
The `TASK_ID` variable maps to the AWS Request ID. This should be set to
|
||||
something unique (a UUID, or an incrementing number).
|
||||
|
||||
`test-function` runs a container with 300MB memory allocated to it. This same
|
||||
information is available inside the container in the `TASK_MAXRAM` variable.
|
||||
This value can be a number in bytes, or a number suffixed by `b`, `k`, `m`, `g`
|
||||
for bytes, kilobytes, megabytes and gigabytes respectively. These are
|
||||
case-insensitive.
|
||||
|
||||
The following variables are set for AWS compatibility:
|
||||
* `AWS_LAMBDA_FUNCTION_NAME` - The name of the docker image.
|
||||
* `AWS_LAMBDA_FUNCTION_VERSION` - The default is `$LATEST`, but any string is
|
||||
allowed.
|
||||
* `AWS_ACCESS_KEY_ID` - Set this to the Access Key to allow the Lambda function
|
||||
to use AWS APIs.
|
||||
* `AWS_SECRET_ACCESS_KEY` - Set this to the Secret Key to allow the Lambda
|
||||
function to use AWS APIs.
|
||||
|
||||
## Running the container
|
||||
|
||||
The default `test-function` can then be approximated as the following `docker
|
||||
run` command:
|
||||
|
||||
```sh
|
||||
mkdir /tmp/payload_dir
|
||||
echo "<payload>" |
|
||||
docker run -v /tmp/payload_dir:/mnt \
|
||||
-m 1G \
|
||||
-e TASK_ID=$RANDOM \
|
||||
-e TASK_MAXRAM=1G \
|
||||
-e AWS_LAMBDA_FUNCTION_NAME=user/fancyfunction \
|
||||
-e AWS_LAMBDA_FUNCTION_VERSION=1.0 \
|
||||
-e AWS_ACCESS_KEY_ID=<access key> \
|
||||
-e AWS_SECRET_ACCESS_KEY=<secret key> \
|
||||
--rm -it
|
||||
user/fancyfunction
|
||||
```
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# Message Queues
|
||||
|
||||
A message queue is used to coordinate asynchronous function calls that run through IronFunctions.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# IronFunctions Configuration Options
|
||||
# IronFunctions Runtime Options
|
||||
|
||||
## Configuration
|
||||
|
||||
When starting IronFunctions, you can pass in the following configuration variables as environment variables. Use `-e VAR_NAME=VALUE` in
|
||||
docker run. For example:
|
||||
@@ -14,19 +16,19 @@ docker run -e VAR_NAME=VALUE ...
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DB</td>
|
||||
<td>The database URL to use in URL format. See Databases below for more information. Default: BoltDB in current working directory `bolt.db`.</td>
|
||||
<td>The database URL to use in URL format. See [Databases](databases/README.md) for more information. Default: BoltDB in current working directory `bolt.db`.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MQ</td>
|
||||
<td>The message queue to use in URL format. See Message Queues below for more information. Default: BoltDB in current working directory `queue.db`.</td>
|
||||
<td>The message queue to use in URL format. See [Message Queues](mqs/README.md) for more information. Default: BoltDB in current working directory `queue.db`.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>API_URL</td>
|
||||
<td>The primary functions api URL to pull tasks from (the address is that of another running functions process).</td>
|
||||
<td>The primary IronFunctions API URL to that this instance will talk to. In a production environment, this would be your load balancer URL.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PORT</td>
|
||||
<td>Default (8080), sets the port to run on.</td>
|
||||
<td>Sets the port to run on. Default: `8080`.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>NUM_ASYNC</td>
|
||||
@@ -34,6 +36,33 @@ docker run -e VAR_NAME=VALUE ...
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LOG_LEVEL</td>
|
||||
<td>Set to `DEBUG` to enable debugging. Default is INFO.</td>
|
||||
<td>Set to `DEBUG` to enable debugging. Default: INFO.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Starting without Docker in Docker
|
||||
|
||||
The default way to run IronFunctions, as it is in the Quickstart guide, is to use docker-in-docker (dind). There are
|
||||
a couple reasons why we did it this way:
|
||||
|
||||
* It's clean. Once the container exits, there is nothing left behind including all the function images.
|
||||
* You can set resource restrictions for the entire IronFunctions instance. For instance, you can set `--memory` on
|
||||
the docker run command to set the max memory for the IronFunctions instance AND all of the functions it's running.
|
||||
|
||||
There are some reasons you may not want to use dind, such as using the image cache during testing or you're running
|
||||
[Windows](windows.md).
|
||||
|
||||
### Mount the Host Docker
|
||||
|
||||
One way is to mount the host Docker. Everything is essentially the same except you add a `-v` flag:
|
||||
|
||||
```sh
|
||||
docker run --rm --name functions -it -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/data:/app/data -p 8080:8080 iron/functions
|
||||
```
|
||||
|
||||
### Run outside Docker
|
||||
|
||||
You can of course just run the binary directly, you'll just have to change how you set the environment variables above.
|
||||
|
||||
See [contributing doc](../CONTRIBUTING.md) for information on how to build and run.
|
||||
|
||||
|
||||
50
docs/packaging.md
Normal file
50
docs/packaging.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Packaging your Function
|
||||
|
||||
Packaging a function has two parts:
|
||||
|
||||
* Create a Docker image for your function with an ENTRYPOINT
|
||||
* Push your Docker image to a registry (Docker Hub by default)
|
||||
|
||||
Once it's pushed to a registry, you can use it by referencing it when adding a route.
|
||||
|
||||
## Creating an image
|
||||
|
||||
The basic Dockerfile for most languages is along these lines:
|
||||
|
||||
```
|
||||
# Choose base image
|
||||
FROM iron/go
|
||||
# Set the working directory
|
||||
WORKDIR /function
|
||||
# Add your binary or code to the working directory
|
||||
ADD funcbin /function/
|
||||
# Set what will run when a container is started for this image
|
||||
ENTRYPOINT ["./funcbin"]
|
||||
```
|
||||
|
||||
Then you simply build your function:
|
||||
|
||||
```sh
|
||||
docker run --rm -v "$PWD":/go/src/$FUNCPKG -w /go/src/$FUNCPKG iron/go:dev go build -o funcbin
|
||||
docker build -t $USERNAME/myfunction .
|
||||
```
|
||||
|
||||
Or using [fnctl](../fnctl/README.md):
|
||||
|
||||
```sh
|
||||
fnctl build
|
||||
```
|
||||
|
||||
## Push your image
|
||||
|
||||
This part is simple:
|
||||
|
||||
```sh
|
||||
docker push $USERNAME/myfunction
|
||||
```
|
||||
|
||||
Or using [fnctl](../fnctl/README.md):
|
||||
|
||||
```sh
|
||||
fnctl push
|
||||
```
|
||||
@@ -1,16 +1,26 @@
|
||||
# Function Memory Requirements
|
||||
# IronFunctions Routes
|
||||
|
||||
Routes have a many-to-one mapping to an [app](apps.md).
|
||||
|
||||
A good practice to get the best performance on your IronFunctions API is define the required memory for each function.
|
||||
|
||||
## Route level configuration
|
||||
|
||||
When creating or updating a route, you can pass in a map of config variables.
|
||||
|
||||
Note: Route level configuration overrides app level configuration.
|
||||
|
||||
TODO: link to swagger doc on swaggerhub after it's updated.
|
||||
|
||||
## Understanding IronFunctions memory management
|
||||
|
||||
When IronFunctions starts it registers the total available memory in your system in order to know during its runtime if the system has the required amount of free memory to run each function.
|
||||
Every function starts the runner reduces the amount of memory used by that function from the available memory register.
|
||||
When the function finishes the runner returns the used memory to the available memory register.
|
||||
|
||||
By default the required memory of a function is *128 mb*.
|
||||
Default memory is 128MB.
|
||||
|
||||
## Defining function's required memory
|
||||
## Defining function's memory requirement
|
||||
|
||||
You can define the function's required memory in the route creation or updating it.
|
||||
|
||||
@@ -56,4 +66,4 @@ curl -H "Content-Type: application/json" -X POST -d '{
|
||||
"memory": 100
|
||||
}
|
||||
}' http://localhost:8080/v1/apps/myapp/routes/hello
|
||||
```
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
# Writing Functions
|
||||
|
||||
This will give you the basic overview of writing base level functions. You can also use higher level abstractions that make it easier such
|
||||
as [lambda](lambda.md).
|
||||
This will give you the basic overview of writing base level functions. You can also use higher level
|
||||
abstractions that make it easier such as [lambda](lambda/README.md).
|
||||
|
||||
## Code
|
||||
|
||||
@@ -20,7 +20,7 @@ STDOUT.write(JSON.generate(return_struct))
|
||||
db.update(return_struct)
|
||||
```
|
||||
|
||||
## Inputs
|
||||
## Inputs
|
||||
|
||||
Inputs are provided through standard input and environment variables. We'll just talk about the default input format here, but you can find others [here](function-format.md).
|
||||
To read in the function body, just read from STDIN.
|
||||
@@ -62,20 +62,7 @@ In Ruby:
|
||||
STDERR.puts("hi")
|
||||
```
|
||||
|
||||
## Packaging
|
||||
## Next Steps
|
||||
|
||||
Packaging a function is essentially just creating a Docker image for your function with an ENTRYPOINT.
|
||||
|
||||
The basic Dockerfile for most languages is something like this:
|
||||
|
||||
```
|
||||
# Choose base image
|
||||
FROM iron/go
|
||||
# Set th working directory
|
||||
WORKDIR /function
|
||||
# Add your binary or code to the working directory
|
||||
ADD hello /function/
|
||||
# Set what will run when a container is started for this image
|
||||
ENTRYPOINT ["./hello"]
|
||||
```
|
||||
* [Packaging your function](packaging.md)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user