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:
Travis Reeder
2016-11-08 09:44:08 -08:00
committed by GitHub
parent 4717889693
commit 85e15fe48a
49 changed files with 282 additions and 99 deletions

View File

@@ -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
View 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
View 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.

View File

@@ -1,5 +0,0 @@
vendor/
/hello
/go
/app
/__uberscript__

View File

@@ -1,6 +0,0 @@
FROM iron/go
WORKDIR /app
ADD . /app
ENTRYPOINT ["./hello"]

View File

@@ -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
```

View File

@@ -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

View File

@@ -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, "!!!")
}

View File

@@ -1,3 +0,0 @@
{
"name": "Johnny"
}

View File

@@ -1 +0,0 @@
node_modules/

View File

@@ -1,6 +0,0 @@
FROM iron/node
WORKDIR /app
ADD . /app
ENTRYPOINT ["node", "hello.js"]

View File

@@ -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
```

View File

@@ -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

View File

@@ -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!");

View File

@@ -1,3 +0,0 @@
{
"name": "Johnny"
}

View File

@@ -1,4 +0,0 @@
{
"dependencies": {
}
}

View File

@@ -1 +0,0 @@
vendor/

View File

@@ -1,6 +0,0 @@
FROM iron/php
WORKDIR /app
ADD . /app
ENTRYPOINT ["php", "hello.php"]

View File

@@ -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
```

View File

@@ -1,4 +0,0 @@
{
"require": {
}
}

View File

@@ -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

View File

@@ -1,3 +0,0 @@
{
"name": "Johnny"
}

View File

@@ -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";
}

View File

@@ -1 +0,0 @@
packages/

View File

@@ -1,6 +0,0 @@
FROM iron/python:2
WORKDIR /app
ADD . /app
ENTRYPOINT ["python", "hello.py"]

View File

@@ -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
```

View File

@@ -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

View File

@@ -1,3 +0,0 @@
{
"name": "Johnny"
}

View File

@@ -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
View 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
View 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
View 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`.

View 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
View 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
View 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
```

View File

@@ -1,4 +1,3 @@
# Message Queues
A message queue is used to coordinate asynchronous function calls that run through IronFunctions.

View File

@@ -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
View 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
```

View File

@@ -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
```
```

View File

@@ -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)