updates docs for running fn on k8s

- removes docker swarm doc
This commit is contained in:
Derek Schultz
2017-09-28 12:59:21 -06:00
parent 2f090d0aab
commit 232069cbca
11 changed files with 191 additions and 268 deletions

View File

@@ -1,121 +1,66 @@
# HOWTO run Oracle Functions in Kubernetes at AWS
*Prerequisite 1: it assumes you have a working Kubernetes, and a locally configured kubectl.*
*Prerequisite 2: It assumes you are using Kubernetes 1.4 or newer.*
# How to run Fn on Kubernetes
*Prerequisite 1: working Kubernetes cluster (v1.7+), and a locally configured kubectl.*
## Quickstart
### Steps
1. Start Oracle Functions in the Kubernetes cluster:
```ShellSession
$ cd docs/
$ kubectl create -f kubernetes-quick
1. Deploy Fn to the Kubernetes cluster:
```bash
$ cd docs/operating/
$ kubectl create -f fn-service.yaml
```
2. Once the daemon is started, check where it is listening for connections:
```ShellSession
# kubectl describe svc functions
Name: functions
Namespace: default
Labels: app=functions
Selector: app=functions
Type: LoadBalancer
IP: 10.0.116.122
LoadBalancer Ingress: a23122e39900111e681ba0e29b70bb46-630391493.us-east-1.elb.amazonaws.com
Port: <unset> 8080/TCP
NodePort: <unset> 30802/TCP
Endpoints: 10.244.1.12:8080
Session Affinity: None
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
22m 22m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer
22m 22m 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
2. Once the Pods have started, check the service for the load balanacer IP:
```bash
$ kubectl get svc --watch
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fn-mysql-master 10.96.57.185 <none> 3306/TCP 10m
fn-redis-master 10.96.127.51 <none> 6379/TCP 10m
fn-service 10.96.245.95 <pending> 8080:30768/TCP,80:31921/TCP 10m
kubernetes 10.96.0.1 <none> 443/TCP 15d
```
Note `a23122e39900111e681ba0e29b70bb46-630391493.us-east-1.elb.amazonaws.com` in `LoadBalancer Ingress` line, this is where the service is listening.
Note that `fn-service` is initially pending on allocating an external IP. The `kubectl get svc --watch` command will update this once an IP has been assigned.
3. Test the cluster:
If you are using a Kubernetes setup that can expose a public loadbalancer run:
```ShellSession
$ export FUNCTIONS=$(kubectl get -o json svc functions | jq -r '.status.loadBalancer.ingress[0].hostname'):8080
If you are using a Kubernetes setup that can expose a public load balancer, run:
```bash
$ export FUNCTIONS=$(kubectl get -o json svc fn-service | jq -r '.status.loadBalancer.ingress[0].ip'):8080
```
If you are using a Kubernetes setup like minikube run
```ShellSession
$ export ns=default ; export label='app=functions'; kubectl -n $ns get pod -l $label -o jsonpath='{.items[0].metadata.name}' | xargs -I{} kubectl -n $ns port-forward {} 8080:8080
$ export FUNCTIONS=localhost:8080
If you are using a Kubernetes setup like minikube, run
```bash
$ echo $(minikube ip):$(kubectl get svc fn-service -o json | jq -r '.spec.ports[0].nodePort')
192.168.99.100:30966
$ export API_URL=http://192.168.99.100:30966
```
Now setup the functions:
Now, test by creating a function via curl:
```ShellSession
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps
```bash
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$API_URL/v1/apps
{"message":"App successfully created","app":{"name":"myapp","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"type":"sync","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$API_URL/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"headers":{},"type":"sync","format":"default","timeout":30,"idle_timeout":30,"config":{}}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$API_URL/r/myapp/hello-sync
Hello Johnny!
```
## Production
You can also use the [Fn CLI](https://github.com/fnproject/cli):
### Steps
1. Start Oracle Functions and its dependencies:
```ShellSession
$ cd docs/
$ kubectl create -f kubernetes-production
```
*Optionally, you might have both Redis and PostgreSQL started somewhere else, in this case, remember to update kubernetes-production/functions-config.yaml with the appropriate configuration.*
2. Once the daemon is started, check where it is listening for connections:
```ShellSession
# kubectl describe svc functions
Name: functions
Namespace: default
Labels: app=functions
Selector: app=functions
Type: LoadBalancer
IP: 10.0.116.122
LoadBalancer Ingress: a23122e39900111e681ba0e29b70bb46-630391493.us-east-1.elb.amazonaws.com
Port: <unset> 8080/TCP
NodePort: <unset> 30802/TCP
Endpoints: 10.244.1.12:8080
Session Affinity: None
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
22m 22m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer
22m 22m 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
```
Note `a23122e39900111e681ba0e29b70bb46-630391493.us-east-1.elb.amazonaws.com` in `LoadBalancer Ingress` line, this is where the service is listening.
3. Test the cluster:
```ShellSession
$ export FUNCTIONS=$(kubectl get -o json svc functions | jq -r '.status.loadBalancer.ingress[0].hostname'):8080
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps
{"message":"App successfully created","app":{"name":"myapp","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"type":"sync","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync
Hello Johnny!
```bash
$ export API_URL=http://192.168.99.100:30966
$ fn apps list
myapp
$ fn routes list myapp
path image endpoint
/hello-sync fnproject/hello 192.168.99.100:30966/r/myapp/hello-sync
```

View File

@@ -0,0 +1,151 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: fn-service-config
namespace: default
data:
MQ_URL: redis://fn-redis-master.default
DB_URL: mysql://root:fnsecretpassword@tcp(fn-mysql-master:3306)/fn
API_URL: http://fn-service:8080
---
apiVersion: v1
kind: Service
metadata:
name: fn-service
labels:
app: fn
role: fn-service
spec:
type: LoadBalancer
ports:
- name: fn-service
port: 8080
targetPort: 8080
- name: fn-ui
port: 80
targetPort: 80
selector:
app: fn
role: fn-service
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: fn-service
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
minReadySeconds: 30
template:
metadata:
labels:
app: fn
role: fn-service
spec:
containers:
- name: fn-service
image: fnproject/functions:latest
securityContext:
privileged: true
ports:
- containerPort: 8080
env:
- name: MQ_URL
valueFrom:
configMapKeyRef:
name: fn-service-config
key: MQ_URL
- name: DB_URL
valueFrom:
configMapKeyRef:
name: fn-service-config
key: DB_URL
- name: fn-ui
image: fnproject/ui:latest
ports:
- containerPort: 80
env:
- name: PORT
value: "80"
- name: API_URL
valueFrom:
configMapKeyRef:
name: fn-service-config
key: API_URL
---
apiVersion: v1
kind: Service
metadata:
name: fn-mysql-master
labels:
app: mysql
role: datastore
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mysql
role: datastore
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: fn-mysql-master
spec:
replicas: 1
template:
metadata:
labels:
app: mysql
role: datastore
spec:
containers:
- name: fn-mysql
image: mysql:5.7
args:
- "--max-connections=500"
- "--wait-timeout=300"
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: fnsecretpassword
- name: MYSQL_DATABASE
value: fn
---
apiVersion: v1
kind: Service
metadata:
name: fn-redis-master
labels:
app: redis
role: mq
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
role: mq
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: fn-redis-master
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: mq
spec:
terminationGracePeriodSeconds: 1
containers:
- name: fn-redis
image: redis:4.0
ports:
- containerPort: 6379

View File

@@ -1,7 +0,0 @@
kind: ConfigMap
apiVersion: v1
metadata:
name: functions-config
data:
MQ_URL: redis://redis-master.default
DB_URL: postgres://postgres:mysecretpassword@postgresql-master.default/?sslmode=disable

View File

@@ -1,43 +0,0 @@
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: functions
labels:
app: functions
spec:
replicas: 1
template:
metadata:
labels:
app: functions
spec:
containers:
- name: functions
image: treeder/functions
securityContext:
privileged: true
env:
- name: DOCKER_HOST
value: unix:///var/run/docker.sock
- name: MQ_URL
valueFrom:
configMapKeyRef:
name: functions-config
key: MQ_URL
- name: DB_URL
valueFrom:
configMapKeyRef:
name: functions-config
key: DB_URL
volumeMounts:
- mountPath: "/var/run/docker.sock"
name: docker-socket
readOnly: false
ports:
- name: http-server
containerPort: 8080
volumes:
- name: docker-socket
hostPath:
path: "/var/run/docker.sock"

View File

@@ -1,14 +0,0 @@
---
kind: Service
apiVersion: v1
metadata:
name: functions
labels:
app: functions
spec:
ports:
- port: 8080
targetPort: http-server
selector:
app: functions
type: LoadBalancer

View File

@@ -1,17 +0,0 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: postgresql-master
spec:
replicas: 1
template:
metadata:
labels:
app: postgresql
role: datastore
spec:
containers:
- name: functions-postgresql
image: postgres
ports:
- containerPort: 5432

View File

@@ -1,14 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: postgresql-master
labels:
app: postgresql
role: datastore
spec:
ports:
- port: 5432
targetPort: 5432
selector:
app: postgresql
role: datastore

View File

@@ -1,17 +0,0 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-master
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: mq
spec:
containers:
- name: functions-redis
image: redis
ports:
- containerPort: 6379

View File

@@ -1,14 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
role: mq
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
role: mq

View File

@@ -1,33 +0,0 @@
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: functions
labels:
app: functions
spec:
replicas: 1
template:
metadata:
labels:
app: functions
spec:
containers:
- name: functions
image: treeder/functions
securityContext:
privileged: true
env:
- name: DOCKER_HOST
value: unix:///var/run/docker.sock
volumeMounts:
- mountPath: "/var/run/docker.sock"
name: docker-socket
readOnly: false
ports:
- name: http-server
containerPort: 8080
volumes:
- name: docker-socket
hostPath:
path: "/var/run/docker.sock"

View File

@@ -1,14 +0,0 @@
---
kind: Service
apiVersion: v1
metadata:
name: functions
labels:
app: functions
spec:
ports:
- port: 8080
targetPort: http-server
selector:
app: functions
type: LoadBalancer