├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── caddy ├── caddy-cfg.yaml ├── caddy-dep.yaml └── caddy-lb.yaml ├── cluster-down.sh ├── cluster-up.sh ├── functions ├── certinfo.yml ├── promql.yml ├── stack.yml └── tweet.yml ├── gke-preemptible.md ├── namespaces.yaml ├── openfaas-down.sh ├── openfaas-tls ├── README.md ├── caddy-cfg.yaml ├── caddy-dep.yaml ├── caddy-svc.yaml ├── ingress-tls.yaml ├── lego-cfg.yaml ├── lego-dep.yaml └── lego-rbac.yaml ├── openfaas-up.sh ├── openfaas ├── alertmanager-cfg.yaml ├── alertmanager-dep.yaml ├── alertmanager-svc.yaml ├── gateway-dep.yaml ├── gateway-svc.yaml ├── nats-dep.yaml ├── nats-svc.yaml ├── netesd-dep.yaml ├── netesd-rbac.yaml ├── netesd-svc.yaml ├── prometheus-cfg.yaml ├── prometheus-dep.yaml ├── prometheus-svc.yaml └── queue-worker-dep.yaml └── screens ├── banner.jpg ├── gke-network-policies.png ├── gke-openfaas-costs.png ├── gke-openfaas-envs.png ├── gke-openfaas-operator.png ├── gke-operator.png ├── gke-pools.png ├── ingress-stats.png ├── ingress-tls.png ├── kube-dash.png ├── metrics.png ├── nodes.png ├── pods-scaling.png └── scaling.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Go 14 | .glide/ 15 | .idea 16 | .DS_Store 17 | 18 | # GCP key 19 | account.json 20 | 21 | # OpenFaaS CLI build 22 | build/ 23 | credentials.yml 24 | up.sh 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: generic 3 | 4 | before_install: 5 | - gem install yaml-lint 6 | 7 | script: 8 | - cat namespaces.yaml > openfaas.yaml 9 | - cat ./openfaas/*.yaml >> openfaas.yaml 10 | - cat ./caddy/*.yaml > openfaas-auth.yaml 11 | - yaml-lint openfaas.yaml 12 | - yaml-lint openfaas-auth.yaml 13 | 14 | deploy: 15 | provider: releases 16 | overwrite: true 17 | skip_cleanup: true 18 | api_key: 19 | secure: OvCArR2HpVBjxGmeA8ri49c7Tsl1cYI0oD/8M1dVB8AjsTdHTVo2CQV1qMkjw+FNygYJp280PF+Clf8ShSboU1eHLYj4cRvW/DXHUW2+FgMBeT4OJPjSoCZVFw3OnvV7TnkP0MOG/7E6gjEzN1352zIW1jM5eudogB9MIdFMTA+M7J5EpUy2GijRZRrt+xVaVX5XNSHaENAgml8a1oYfh6ggesIQRECaOUvIiiNK2vFrcCGs8mPePU5+lp03t7RMh+LEfKaax66qNoly7dmd7ZltmU+8GS0Hso21kGBs5JEWD4olN//HsLWde8vEz9WdFM14E7+x01Tpc42Gahx6BZLpiUfYvo66LYKpZ7wsg1y3oe2u6M3FW5pcamqMfR1l8dyqV9PT4/dlD/2bnEE8ZBIGEIVWbxi+9fKdHqksC7HL/09j+gujNcYbffMFcUaHBN60IThtlvy4q1VEsth3v5E1emd+E7cEAI+PGHg9JNvkzoX5HAHHbtaKEhh2NNvUZbAew9hxHGMOrfH9v91CxgIP745XqWvMEQfe9mE6sVgGdVHkVg10UyiZgmjRFw1ibmVHV5PFB3zdJA5qI/H4+QTmGEPb6DL0x/4YkA/M/AeAmPREeLYS7ZYjdroZcdXLTseRNSplyn1jXdsIFhB7FBZTlrH5yaKNe0/Pi6PaqcI= 20 | file: 21 | - openfaas.yaml 22 | - openfaas-auth.yaml 23 | on: 24 | repo: stefanprodan/openfaas-gke 25 | tags: true 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Stefan Prodan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenFaaS GKE 2 | 3 | ![OpenFaaS](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/banner.jpg) 4 | 5 | OpenFaaS is a serverless framework that runs on top of Kubernetes. It comes with a built-in UI and a handy CLI that 6 | takes you from scaffolding new functions to deploying them on your Kubernetes cluster. What's special about OpenFaaS 7 | is that you can package any executable as a function, and as long as it runs in a Docker container, it will work on OpenFaaS. 8 | 9 | What follows is a step by step guide on running OpenFaaS with Kubernetes 1.8 on Google Cloud. 10 | 11 | This setup is optimized for production use: 12 | 13 | * Kubernetes multi-zone cluster 14 | * OpenFaaS system API and UI are username/password protected 15 | * all OpenFaaS components have 1GB memory limits 16 | * the gateway read/write timeouts are set to one minute 17 | * asynchronous function calls with NATS streaming and three queue workers 18 | * optional GKE Ingress controller with Let's Encrypt TLS 19 | 20 | ### Create a GCP project 21 | 22 | Login to GCP and create a new project named openfaas. If you don't have a GCP account you can apply for 23 | a free trial. After creating the project, enable billing and wait for the API and related services to be enabled. 24 | Download and install the Google Cloud SDK from this [page](https://cloud.google.com/sdk/). After installing 25 | the SDK run `gcloud init` and then, set the default project to `openfaas` and the default zone to `europe-west3-a`. 26 | 27 | Install `kubectl` using `gcloud`: 28 | 29 | ```bash 30 | gcloud components install kubectl 31 | ``` 32 | 33 | Go to _Google Cloud Platform -> API Manager -> Credentials -> Create Credentials -> Service account key_ and 34 | choose JSON as key type. Rename the file to `account.json` and put it in the project root. 35 | Add your SSH key under _Compute Engine -> Metadata -> SSH Keys_, also create a metadata entry named `sshKeys` 36 | with your public SSH key as value. 37 | 38 | ### Create a Kubernetes cluster 39 | 40 | Create a three node cluster with each node in a different zone: 41 | 42 | ```bash 43 | k8s_version=$(gcloud container get-server-config --format=json | jq -r '.validNodeVersions[0]') 44 | 45 | gcloud container clusters create demo \ 46 | --cluster-version=${k8s_version} \ 47 | --zone=europe-west3-a \ 48 | --additional-zones=europe-west3-b,europe-west3-c \ 49 | --num-nodes=1 \ 50 | --machine-type=n1-standard-2 \ 51 | --scopes=default,storage-rw 52 | ``` 53 | 54 | Increase the size of the default node pool to 6 nodes: 55 | 56 | ```bash 57 | gcloud container clusters resize --size=2 58 | ``` 59 | 60 | You can delete the cluster at any time with: 61 | 62 | ```bash 63 | gcloud container clusters delete demo -z=europe-west3-a 64 | ``` 65 | 66 | Set up credentials for `kubectl`: 67 | 68 | ```bash 69 | gcloud container clusters get-credentials demo -z=europe-west3-a 70 | ``` 71 | 72 | Create a cluster admin user: 73 | 74 | ```bash 75 | kubectl create clusterrolebinding "cluster-admin-$(whoami)" \ 76 | --clusterrole=cluster-admin \ 77 | --user="$(gcloud config get-value core/account)" 78 | ``` 79 | 80 | Grant admin privileges to kubernetes-dashboard (don't do this on a production environment): 81 | 82 | ```bash 83 | kubectl create clusterrolebinding kube-system-cluster-admin \ 84 | --clusterrole cluster-admin \ 85 | --user system:serviceaccount:kube-system:default 86 | ``` 87 | 88 | You can access the kubernetes-dashboard at `http://localhost:9099/ui` using kubectl reverse proxy: 89 | 90 | ```bash 91 | kubectl proxy --port=9099 & 92 | ``` 93 | 94 | ### Create a Weave Cloud Instance 95 | 96 | Now that you have a Kubernetes cluster up and running you can start monitoring it with Weave Cloud. 97 | You'll need a Weave Could service token, if you don't have a Weave token go 98 | to [Weave Cloud](https://cloud.weave.works/) and sign up for a trial account. 99 | 100 | Deploy the Weave Cloud agents: 101 | 102 | ```bash 103 | kubectl apply -n kube-system -f \ 104 | "https://cloud.weave.works/k8s.yaml?k8s-version=$(kubectl version | base64 | tr -d '\n')&t=" 105 | ``` 106 | 107 | Navigate to Weave Cloud Explore to inspect your K8S cluster: 108 | 109 | ![nodes](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/nodes.png) 110 | 111 | ### Deploy OpenFaaS with basic authentication 112 | 113 | Clone `openfaas-gke` repo: 114 | 115 | ```bash 116 | git clone https://github.com/stefanprodan/openfaas-gke 117 | cd openfaas-gke 118 | ``` 119 | 120 | Create the `openfaas` and `openfaas-fn` namespaces: 121 | 122 | ```bash 123 | kubectl apply -f ./namespaces.yaml 124 | ``` 125 | 126 | Deploy OpenFaaS services in the `openfaas` namespace: 127 | 128 | ```bash 129 | kubectl apply -f ./openfaas 130 | ``` 131 | 132 | This will create the pods, deployments and services for an OpenFaaS gateway, faas-netesd (K8S controller), 133 | Prometheus, Alert Manager, Nats and the Queue worker. 134 | 135 | Before exposing OpenFaaS on the Internet, you'll need to setup authentication. 136 | First create a basic-auth secret with your username and password: 137 | 138 | ```bash 139 | kubectl -n openfaas create secret generic basic-auth \ 140 | --from-literal=user=admin \ 141 | --from-literal=password=admin 142 | ``` 143 | 144 | Deploy Caddy as a reverse proxy for OpenFaaS gateway: 145 | 146 | ```bash 147 | kubectl apply -f ./caddy 148 | ``` 149 | 150 | Wait for an external IP to be allocated and then use it to access the OpenFaaS gateway UI 151 | with your credentials at `http://`. You can get the external IP by running `kubectl get svc`. 152 | 153 | ```bash 154 | get_gateway_ip() { 155 | kubectl -n openfaas describe service caddy-lb | grep Ingress | awk '{ print $NF }' 156 | } 157 | 158 | until [[ "$(get_gateway_ip)" ]] 159 | do sleep 1; 160 | echo -n "."; 161 | done 162 | echo "." 163 | gateway_ip=$(get_gateway_ip) 164 | echo "OpenFaaS Gateway IP: ${gateway_ip}" 165 | ``` 166 | 167 | Install the OpenFaaS CLI: 168 | 169 | ```bash 170 | curl -sL cli.openfaas.com | sudo sh 171 | ``` 172 | 173 | Login with the CLI: 174 | 175 | ```bash 176 | faas-cli login -u admin -p admin --gateway http:// 177 | ``` 178 | 179 | If you want to avoid having your password in bash history, you could create a text file with it and use that 180 | along with the `--password-stdin` flag: 181 | 182 | ```bash 183 | cat ~/faas_pass.txt | faas-cli login -u admin --password-stdin --gateway http:// 184 | ``` 185 | 186 | You can logout at any time with: 187 | 188 | ```bash 189 | faas-cli logout --gateway http:// 190 | ``` 191 | 192 | Optionally you could expose the gateway using Google Cloud L7 HTTPS load balancer. A detailed guide on 193 | how to use Kubernetes Ingress controller with Let's Encrypt can be found [here](https://stefanprodan.com/2017/openfaas-kubernetes-ingress-ssl-gke/). 194 | 195 | ### Deploy the OpenFaaS functions 196 | 197 | Create a stack file named `stack.yml` containing two functions: 198 | 199 | ```yaml 200 | provider: 201 | name: faas 202 | gateway: http:// 203 | 204 | functions: 205 | nodeinfo: 206 | handler: node main.js 207 | image: functions/nodeinfo:burner 208 | labels: 209 | com.openfaas.scale.min: "2" 210 | com.openfaas.scale.max: "15" 211 | echo: 212 | handler: ./echo 213 | image: functions/faas-echo:latest 214 | ``` 215 | 216 | With the `com.openfaas.scale.min` label you can set the minimum number of running pods. 217 | With `com.openfaas.scale.max` you can set the maximum number of replicas for the autoscaler. 218 | By default OpenFaaS will keep a single pod running per function and under load it will scale up 219 | to a maximum of 20 pods. 220 | 221 | Deploy `nodeinfo` and `echo` on OpenFaaS: 222 | 223 | ```bash 224 | faas-cli deploy 225 | ``` 226 | 227 | The `deploy` command looks for a `stack.yml` file in the current directory and deploys all of the functions in the 228 | openfaas-fn namespace. 229 | 230 | Invoke the functions: 231 | 232 | ```bash 233 | echo -n "test" | faas-cli invoke echo --gateway=http:// 234 | echo -n "verbose" | faas-cli invoke nodeinfo --gateway=http:// 235 | ``` 236 | 237 | ### Monitoring OpenFaaS 238 | 239 | Let's run a load test with 10 function calls per second: 240 | 241 | ```bash 242 | #install hey 243 | go get -u github.com/rakyll/hey 244 | 245 | #do 1K requests rate limited at 10 QPS 246 | hey -n 1000 -q 10 -c 1 -m POST -d "verbose" http:///function/nodeinfo 247 | ``` 248 | 249 | In the Weave Cloud UI under Explore you'll see how OpenFaaS scales up the nodeinfo pods: 250 | 251 | ![scaling](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/pods-scaling.png) 252 | 253 | You can also monitor the scale up/down events with GCP Stackdrive Logs using this advanced filter: 254 | 255 | ```bash 256 | resource.type="container" 257 | resource.labels.cluster_name="demo" 258 | resource.labels.namespace_id="openfaas" 259 | logName:"gateway" 260 | textPayload: "alerts" 261 | ``` 262 | 263 | Weave Cloud extends Prometheus by providing a distributed, multi-tenant, horizontally scalable version of Prometheus. 264 | It hosts the scraped Prometheus metrics for you, so that you don’t have to worry about storage or backups. 265 | 266 | Weave Cloud comes with canned dashboards for Kubernetes that you can use to monitor a specific namespace: 267 | 268 | ![k8s-metrics](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/kube-dash.png) 269 | 270 | You can also make your own dashboards based on OpenFaaS specific metrics: 271 | 272 | ![openfaas-metrics](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/metrics.png) 273 | 274 | ### Create functions 275 | 276 | With the OpenFaaS CLI you can chose between using a programming language template where you only need to provide a 277 | handler file, or a Docker template that you can build yourself. There are many supported languages like 278 | Go, JS (node), Python, C# and Ruby. 279 | 280 | Let's create a function with Go that fetches the SSL/TLS certificate info for a given URL. 281 | 282 | First create a directory for your functions under `GOPATH`: 283 | 284 | ```bash 285 | mkdir -p $GOPATH/src/functions 286 | ``` 287 | 288 | Inside the `functions` dir use the CLI to create the `certinfo` function: 289 | 290 | ```bash 291 | cd $GOPATH/src/functions 292 | faas-cli new --lang go certinfo 293 | ``` 294 | 295 | Open `handler.go` in your favorite editor and add the certificate fetching code: 296 | 297 | ```go 298 | package function 299 | 300 | import ( 301 | "crypto/tls" 302 | "fmt" 303 | "net" 304 | "time" 305 | ) 306 | 307 | func Handle(req []byte) string { 308 | address := string(req) + ":443" 309 | ipConn, err := net.DialTimeout("tcp", address, 2*time.Second) 310 | if err != nil { 311 | return fmt.Sprintf("Dial error: %v", err) 312 | } 313 | defer ipConn.Close() 314 | conn := tls.Client(ipConn, &tls.Config{ 315 | InsecureSkipVerify: true, 316 | }) 317 | if err = conn.Handshake(); err != nil { 318 | return fmt.Sprintf("Handshake error: %v", err) 319 | } 320 | defer conn.Close() 321 | addr := conn.RemoteAddr() 322 | host, port, err := net.SplitHostPort(addr.String()) 323 | if err != nil { 324 | return fmt.Sprintf("Error: %v", err) 325 | } 326 | cert := conn.ConnectionState().PeerCertificates[0] 327 | 328 | return fmt.Sprintf("Host %v\nPort %v\nIssuer %v\nCommonName %v\nNotBefore %v\nNotAfter %v\nSANs %v\n", 329 | host, port, cert.Issuer.CommonName, cert.Subject.CommonName, cert.NotBefore, cert.NotAfter, cert.DNSNames) 330 | } 331 | ``` 332 | 333 | Next to `handler.go` create `handler_test.go` with the following content: 334 | 335 | ```go 336 | package function 337 | 338 | import ( 339 | "regexp" 340 | "testing" 341 | ) 342 | 343 | func TestHandleReturnsCorrectResponse(t *testing.T) { 344 | expected := "Google Internet Authority" 345 | resp := Handle([]byte("google.com")) 346 | 347 | r := regexp.MustCompile("(?m:" + expected + ")") 348 | if !r.MatchString(resp) { 349 | t.Fatalf("\nExpected: \n%v\nGot: \n%v", expected, resp) 350 | } 351 | } 352 | ``` 353 | 354 | Modify the `certinfo.yml` file and add your Docker Hub username to the image name: 355 | 356 | ```yaml 357 | provider: 358 | name: faas 359 | gateway: http://localhost:8080 360 | 361 | functions: 362 | certinfo: 363 | lang: go 364 | handler: ./certinfo 365 | image: stefanprodan/certinfo 366 | ``` 367 | 368 | Now let's build the function into a Docker image: 369 | 370 | ```bash 371 | faas-cli build -f certinfo.yml 372 | ``` 373 | 374 | This will check your code for proper formatting with `gofmt`, run `go build & test` and pack your binary into 375 | an alpine image. If everything goes well, you'll have a local Docker image named `username/certinfo:latest`. 376 | 377 | Push this image to Docker Hub. First create a public repository named `certinfo`, login to Docker Hub using 378 | docker CLI and then push the image: 379 | 380 | ```bash 381 | docker login 382 | faas-cli push -f certinfo.yml 383 | ``` 384 | 385 | Once the image is on Docker Hub you can deploy the function to your OpenFaaS GKE cluster: 386 | 387 | ```bash 388 | faas-cli deploy -f certinfo.yml --gateway=http:// 389 | ``` 390 | 391 | Invoke certinfo with: 392 | 393 | ```bash 394 | $ echo -n "www.openfaas.com" | faas-cli invoke certinfo --gateway= 395 | 396 | Host 147.75.74.69 397 | Port 443 398 | Issuer Let's Encrypt Authority X3 399 | CommonName www.openfaas.com 400 | NotBefore 2017-10-06 23:54:56 +0000 UTC 401 | NotAfter 2018-01-04 23:54:56 +0000 UTC 402 | SANs [www.openfaas.com] 403 | ``` 404 | 405 | Full source code of the certinfo function can be found on GitHub at [stefanprodan/openfaas-certinfo](https://github.com/stefanprodan/openfaas-certinfo). 406 | In the certinfo repo you can see how easy it is to do continuous deployments to Docker Hub with TravisCI for OpenFaaS functions. 407 | 408 | ### Conclusions 409 | 410 | Like most serverless frameworks, OpenFaaS empowers developers to build, ship and run code in the cloud. 411 | What OpenFaaS adds to this, is portability between dev and production environments with no vendor lock-in. 412 | OpenFaaS is a promising project and with over 64 contributors is a vibrant community. Even as a relatively young project, you 413 | can run it reliably in production backed by Kubernetes and Google Cloud. You can also use [Weave Cloud](http://cloud.weave.works) to monitor and alert on any issues in your OpenFaaS project. 414 | -------------------------------------------------------------------------------- /caddy/caddy-cfg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | name: caddy-config 6 | namespace: openfaas 7 | labels: 8 | app: caddy 9 | data: 10 | Caddyfile: | 11 | :80 { 12 | status 200 /healthz 13 | basicauth /system {$ADMIN_USER} {$ADMIN_PASSWORD} 14 | basicauth /ui {$ADMIN_USER} {$ADMIN_PASSWORD} 15 | proxy / gateway:8080 { 16 | transparent 17 | } 18 | 19 | errors stderr 20 | tls off 21 | } 22 | -------------------------------------------------------------------------------- /caddy/caddy-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: caddy 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: caddy 12 | template: 13 | metadata: 14 | labels: 15 | app: caddy 16 | spec: 17 | containers: 18 | - name: caddy 19 | image: stefanprodan/caddy:0.10.10 20 | imagePullPolicy: Always 21 | command: ["caddy", "-agree", "--conf", "/Caddyfile"] 22 | env: 23 | - name: ADMIN_USER 24 | valueFrom: 25 | secretKeyRef: 26 | name: basic-auth 27 | key: user 28 | - name: ADMIN_PASSWORD 29 | valueFrom: 30 | secretKeyRef: 31 | name: basic-auth 32 | key: password 33 | ports: 34 | - containerPort: 80 35 | protocol: TCP 36 | resources: 37 | limits: 38 | memory: 128Mi 39 | volumeMounts: 40 | - mountPath: /Caddyfile 41 | name: caddy-config 42 | subPath: Caddyfile 43 | volumes: 44 | - name: caddy-config 45 | configMap: 46 | name: caddy-config 47 | items: 48 | - key: Caddyfile 49 | path: Caddyfile 50 | mode: 0644 51 | -------------------------------------------------------------------------------- /caddy/caddy-lb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: caddy-lb 6 | namespace: openfaas 7 | annotations: 8 | prometheus.io.scrape: 'false' 9 | labels: 10 | app: caddy 11 | spec: 12 | type: LoadBalancer 13 | ports: 14 | - port: 80 15 | targetPort: 80 16 | protocol: TCP 17 | selector: 18 | app: caddy 19 | -------------------------------------------------------------------------------- /cluster-down.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | gcloud container clusters delete demo -z=europe-west3-a 8 | 9 | -------------------------------------------------------------------------------- /cluster-up.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | k8s_version=$(gcloud container get-server-config --format=json | jq -r '.validNodeVersions[0]') 8 | 9 | gcloud container clusters create demo \ 10 | --cluster-version=${k8s_version} \ 11 | --zone=europe-west3-a \ 12 | --additional-zones=europe-west3-b,europe-west3-c \ 13 | --num-nodes=1 \ 14 | --machine-type=n1-standard-1 \ 15 | --scopes=default,storage-rw 16 | 17 | gcloud container clusters get-credentials demo -z=europe-west3-a 18 | 19 | kubectl create clusterrolebinding "cluster-admin-$(whoami)" \ 20 | --clusterrole=cluster-admin \ 21 | --user="$(gcloud config get-value core/account)" 22 | 23 | -------------------------------------------------------------------------------- /functions/certinfo.yml: -------------------------------------------------------------------------------- 1 | provider: 2 | name: faas 3 | gateway: http://localhost:8080 4 | 5 | functions: 6 | certinfo: 7 | lang: go 8 | handler: ./certinfo 9 | image: stefanprodan/certinfo 10 | -------------------------------------------------------------------------------- /functions/promql.yml: -------------------------------------------------------------------------------- 1 | provider: 2 | name: faas 3 | gateway: http://localhost:8080 4 | 5 | functions: 6 | promql: 7 | handler: ./promq 8 | image: stefanprodan/openfaas-promq 9 | labels: 10 | com.openfaas.scale.min: "2" 11 | com.openfaas.scale.max: "15" 12 | limits: 13 | cpu: 80m 14 | memory: 128Mi 15 | requests: 16 | cpu: "10m" 17 | memory: "64Mi" 18 | -------------------------------------------------------------------------------- /functions/stack.yml: -------------------------------------------------------------------------------- 1 | provider: 2 | name: faas 3 | gateway: http://localhost:8080 4 | 5 | functions: 6 | nodeinfo: 7 | handler: node main.js 8 | image: functions/nodeinfo:burner 9 | labels: 10 | com.openfaas.scale.min: "2" 11 | com.openfaas.scale.max: "15" 12 | echo: 13 | handler: ./echo 14 | image: functions/faas-echo:latest 15 | -------------------------------------------------------------------------------- /functions/tweet.yml: -------------------------------------------------------------------------------- 1 | provider: 2 | name: faas 3 | gateway: http://localhost:8080 4 | 5 | functions: 6 | tweet: 7 | handler: ./tweet 8 | image: nicholasjackson/func_tweet 9 | environment_file: 10 | - credentials.yml 11 | -------------------------------------------------------------------------------- /gke-preemptible.md: -------------------------------------------------------------------------------- 1 | # Multi-stage Serverless on Kubernetes with OpenFaaS and GKE 2 | 3 | This is a step-by-step guide on setting up OpenFaaS on GKE with the following characteristics: 4 | * two OpenFaaS instances, one for staging and one for production use, isolated with network policies 5 | * a dedicated node pool for OpenFaaS long-running services 6 | * a dedicated node pool of preemptible VMs for OpenFaaS functions 7 | * autoscaling for functions and their underling infrastructure 8 | * secure OpenFaaS ingress with Let's Encrypt TLS and authentication 9 | 10 | ![openfaas-gke](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/gke-openfaas-envs.png) 11 | 12 | This setup can enable multiple teams to share the same CD pipeline with staging/production environments 13 | hosted on GKE and development taking place on a local environment such as Minikube or Docker for Mac. 14 | 15 | ### GKE cluster setup 16 | 17 | Create a cluster with two nodes and network policy enabled: 18 | 19 | ```bash 20 | k8s_version=$(gcloud container get-server-config --format=json | jq -r '.validNodeVersions[0]') 21 | 22 | gcloud container clusters create openfaas \ 23 | --cluster-version=${k8s_version} \ 24 | --zone=europe-west3-a \ 25 | --num-nodes=2 \ 26 | --machine-type=n1-standard-1 \ 27 | --no-enable-cloud-logging \ 28 | --disk-size=30 \ 29 | --enable-autorepair \ 30 | --enable-network-policy \ 31 | --scopes=gke-default,compute-rw,storage-rw 32 | ``` 33 | 34 | The above command will create a node pool named `default-pool` made of n1-standard-1 (vCPU: 1, RAM 3.75GB, DISK: 30GB) VMs. 35 | 36 | You will use the default pool to run the following OpenFaaS components: 37 | * Core services ([Gateway](https://github.com/openfaas/faas) and Kubernetes [Operator](https://github.com/openfaas-incubator/openfaas-operator)) 38 | * Async services ([NATS streaming](https://github.com/nats-io/nats-streaming-server) and [queue worker](https://github.com/openfaas/queue-worker)) 39 | * Monitoring and autoscaling services ([Prometheus](https://github.com/prometheus/prometheus) and [Alertmanager](https://github.com/prometheus/alertmanager)) 40 | 41 | Create a node pool of n1-highcpu-4 (vCPU: 4, RAM 3.60GB, DISK: 30GB) preemptible VMs with autoscaling enabled: 42 | 43 | ```bash 44 | gcloud container node-pools create fn-pool \ 45 | --cluster=openfaas \ 46 | --preemptible \ 47 | --node-version=${k8s_version} \ 48 | --zone=europe-west3-a \ 49 | --num-nodes=1 \ 50 | --enable-autoscaling --min-nodes=2 --max-nodes=4 \ 51 | --machine-type=n1-highcpu-4 \ 52 | --disk-size=30 \ 53 | --enable-autorepair \ 54 | --scopes=gke-default 55 | ``` 56 | 57 | [Preemptible VMs](https://cloud.google.com/preemptible-vms/) are up to 80% cheaper than regular instances 58 | but will be terminated and replaced after a maximum of 24 hours. 59 | In order to avoid all nodes to be terminated at the same time, wait for 30 minutes and scale up the fn pool to two nodes: 60 | 61 | ```bash 62 | gcloud container clusters resize openfaas \ 63 | --size=2 \ 64 | --node-pool=fn-pool \ 65 | --zone=europe-west3-a 66 | ``` 67 | 68 | When a VM is preempted it gets logged here: 69 | 70 | ```bash 71 | gcloud compute operations list | grep compute.instances.preempted 72 | ``` 73 | 74 | The above setup along with a GCP load balancer forwarding rule and a 30GB ingress traffic per month will yell the following costs: 75 | 76 | | Role | Type | Usage | Price per month | 77 | |------|------|-------|-----------------| 78 | | 2 x OpenFaaS Core Services | n1-standard-1 | 1460 total hours per month | $62.55 | 79 | | 2 x OpenFaaS Functions | n1-highcpu-4 | 1460 total hours per month | $53.44 | 80 | | Persistent disk | Storage | 120 GB | $5.76 | 81 | | Container Registry | Cloud Storage | 300 GB | $6.90 | 82 | | Forwarding rules | Forwarding rules | 1 | $21.90 | 83 | | Load Balancer ingress | Ingress | 30 GB | $0.30 | 84 | | Total | | | $150.84 | 85 | 86 | The cost estimation was generated with the [Google Cloud pricing calculator](https://cloud.google.com/products/calculator/) on 31 July 2018 and could change any time. 87 | 88 | ### GKE addons setup 89 | 90 | Set up credentials for `kubectl`: 91 | 92 | ```bash 93 | gcloud container clusters get-credentials europe -z=europe-west3-a 94 | ``` 95 | 96 | Create a cluster admin user: 97 | 98 | ```bash 99 | kubectl create clusterrolebinding "cluster-admin-$(whoami)" \ 100 | --clusterrole=cluster-admin \ 101 | --user="$(gcloud config get-value core/account)" 102 | ``` 103 | 104 | Install Helm CLI with Homebrew: 105 | 106 | ```bash 107 | brew install kubernetes-helm 108 | ``` 109 | 110 | Create a service account and a cluster role binding for Tiller: 111 | 112 | ```bash 113 | kubectl -n kube-system create sa tiller 114 | 115 | kubectl create clusterrolebinding tiller-cluster-rule \ 116 | --clusterrole=cluster-admin \ 117 | --serviceaccount=kube-system:tiller 118 | ``` 119 | 120 | Deploy Tiller in the kube-system namespace: 121 | 122 | ```bash 123 | helm init --skip-refresh --upgrade --service-account tiller 124 | ``` 125 | 126 | When exposing OpenFaaS on the internet you should enable HTTPS to encrypt all traffic. 127 | To do that you'll need the following tools: 128 | 129 | * [Heptio Contour](https://github.com/heptio/contour) as Kubernetes Ingress controller (or another ingress controller such as Nginx) 130 | * [JetStack cert-manager](https://github.com/jetstack/cert-manager) as Let's Encrypt provider 131 | 132 | Heptio Contour is an ingress controller based on [Envoy](https://www.envoyproxy.io) reverse proxy that supports dynamic configuration updates. 133 | Install Contour with: 134 | 135 | ```bash 136 | kubectl apply -f https://j.hept.io/contour-deployment-rbac 137 | ``` 138 | 139 | Find the Contour address with: 140 | 141 | ```yaml 142 | kubectl -n heptio-contour describe svc/contour | grep Ingress | awk '{ print $NF }' 143 | ``` 144 | 145 | Go to your DNS provider and create an `A` record for each OpenFaaS instance: 146 | 147 | ```bash 148 | $ host openfaas.example.com 149 | openfaas.example.com has address 35.197.248.216 150 | 151 | $ host openfaas-stg.example.com 152 | openfaas-stg.example.com has address 35.197.248.217 153 | ``` 154 | 155 | Install cert-manager with Helm: 156 | 157 | ```bash 158 | helm install --name cert-manager \ 159 | --namespace kube-system \ 160 | stable/cert-manager 161 | ``` 162 | 163 | Create a cluster issuer definition (replace `email@example.com` with a valid email address): 164 | 165 | ```yaml 166 | apiVersion: certmanager.k8s.io/v1alpha1 167 | kind: ClusterIssuer 168 | metadata: 169 | name: letsencrypt 170 | spec: 171 | acme: 172 | email: email@example.com 173 | http01: {} 174 | privateKeySecretRef: 175 | name: letsencrypt-cert 176 | server: https://acme-v02.api.letsencrypt.org/directory 177 | ``` 178 | 179 | Save the above resource as `letsencrypt-issuer.yaml` and then apply it: 180 | 181 | ```bash 182 | kubectl apply -f ./letsencrypt-issuer.yaml 183 | ``` 184 | 185 | ### Network policies setup 186 | 187 | ![network-policies](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/gke-network-policies.png) 188 | 189 | Create the OpenFaaS dev and prod namespaces: 190 | 191 | ```yaml 192 | apiVersion: v1 193 | kind: Namespace 194 | metadata: 195 | name: openfaas-stg 196 | labels: 197 | role: openfaas-system 198 | access: openfaas-system 199 | --- 200 | apiVersion: v1 201 | kind: Namespace 202 | metadata: 203 | name: openfaas-stg-fn 204 | --- 205 | apiVersion: v1 206 | kind: Namespace 207 | metadata: 208 | name: openfaas-prod 209 | labels: 210 | role: openfaas-system 211 | access: openfaas-system 212 | --- 213 | apiVersion: v1 214 | kind: Namespace 215 | metadata: 216 | name: openfaas-prod-fn 217 | ``` 218 | 219 | Save the above resource as `openfaas-ns.yaml` and then apply it: 220 | 221 | ```bash 222 | kubectl apply -f ./openfaas-ns.yaml 223 | ``` 224 | 225 | Allow ingress traffic from the `heptio-contour` namespace to both OpenFaaS environments: 226 | 227 | ```bash 228 | kubectl label namespace heptio-contour access=openfaas-system 229 | ``` 230 | 231 | Create network policies to isolate the OpenFaaS core services from the function namespaces: 232 | 233 | ```yaml 234 | kind: NetworkPolicy 235 | apiVersion: networking.k8s.io/v1 236 | metadata: 237 | name: openfaas-stg 238 | namespace: openfaas-stg 239 | spec: 240 | policyTypes: 241 | - Ingress 242 | podSelector: {} 243 | ingress: 244 | - from: 245 | - namespaceSelector: 246 | matchLabels: 247 | access: openfaas-system 248 | --- 249 | apiVersion: networking.k8s.io/v1 250 | kind: NetworkPolicy 251 | metadata: 252 | name: openfaas-stg-fn 253 | namespace: openfaas-stg-fn 254 | spec: 255 | policyTypes: 256 | - Ingress 257 | podSelector: {} 258 | ingress: 259 | - from: 260 | - namespaceSelector: 261 | matchLabels: 262 | role: openfaas-system 263 | --- 264 | kind: NetworkPolicy 265 | apiVersion: networking.k8s.io/v1 266 | metadata: 267 | name: openfaas-prod 268 | namespace: openfaas-prod 269 | spec: 270 | policyTypes: 271 | - Ingress 272 | podSelector: {} 273 | ingress: 274 | - from: 275 | - namespaceSelector: 276 | matchLabels: 277 | access: openfaas-system 278 | --- 279 | apiVersion: networking.k8s.io/v1 280 | kind: NetworkPolicy 281 | metadata: 282 | name: openfaas-prod-fn 283 | namespace: openfaas-prod-fn 284 | spec: 285 | policyTypes: 286 | - Ingress 287 | podSelector: {} 288 | ingress: 289 | - from: 290 | - namespaceSelector: 291 | matchLabels: 292 | role: openfaas-system 293 | ``` 294 | 295 | Save the above resource as `network-policies.yaml` and then apply it: 296 | 297 | ```bash 298 | kubectl apply -f ./network-policies.yaml 299 | ``` 300 | 301 | Note that the above configuration will prohibit functions from calling each other or from reaching the 302 | OpenFaaS core services. 303 | 304 | ### OpenFaaS staging setup 305 | 306 | Generate a random password and create an OpenFaaS credentials secret: 307 | 308 | ```bash 309 | stg_password=$(head -c 12 /dev/urandom | shasum | cut -d' ' -f1) 310 | 311 | kubectl -n openfaas-stg create secret generic basic-auth \ 312 | --from-literal=basic-auth-user=admin \ 313 | --from-literal=basic-auth-password=$stg_password 314 | ``` 315 | 316 | Create the staging configuration (replace `example.com` with your own domain): 317 | 318 | ```yaml 319 | functionNamespace: openfaas-stg-fn 320 | basic_auth: true 321 | operator: 322 | create: true 323 | createCRD: true 324 | ingress: 325 | enabled: true 326 | annotations: 327 | kubernetes.io/ingress.class: "contour" 328 | certmanager.k8s.io/cluster-issuer: "letsencrypt" 329 | contour.heptio.com/request-timeout: "30s" 330 | contour.heptio.com/num-retries: "3" 331 | contour.heptio.com/retry-on: "gateway-error" 332 | hosts: 333 | - host: openfaas-stg.example.com 334 | serviceName: gateway 335 | servicePort: 8080 336 | path: / 337 | tls: 338 | - secretName: openfaas-cert 339 | hosts: 340 | - openfaas-stg.example.com 341 | affinity: 342 | nodeAffinity: 343 | requiredDuringSchedulingIgnoredDuringExecution: 344 | nodeSelectorTerms: 345 | - matchExpressions: 346 | - key: cloud.google.com/gke-preemptible 347 | operator: DoesNotExist 348 | ``` 349 | 350 | Note that the OpenFaaS components will be running on the default pool due to the affinity constraint `cloud.google.com/gke-nodepool=default-pool`. 351 | 352 | Save the above file as `openfaas-stg.yaml` and install OpenFaaS staging instance from the project helm repository: 353 | 354 | ```bash 355 | helm repo add openfaas https://openfaas.github.io/faas-netes/ 356 | 357 | helm upgrade openfaas-stg --install openfaas/openfaas \ 358 | --namespace openfaas-stg \ 359 | -f openfaas-stg.yaml 360 | ``` 361 | 362 | In a couple of seconds cert-manager should fetch a certificate from LE: 363 | 364 | ``` 365 | kubectl -n kube-system logs deployment/cert-manager-cert-manager 366 | 367 | Certificate issued successfully 368 | ``` 369 | 370 | ### OpenFaaS production setup 371 | 372 | Generate a random password and create the basic-auth secret in the openfaas-prod namespace: 373 | 374 | ```bash 375 | password=$(head -c 12 /dev/urandom | shasum | cut -d' ' -f1) 376 | 377 | kubectl -n openfaas-prod create secret generic basic-auth \ 378 | --from-literal=basic-auth-user=admin \ 379 | --from-literal=basic-auth-password=$password 380 | ``` 381 | 382 | Create the production configuration (replace `example.com` with your own domain): 383 | 384 | ```yaml 385 | functionNamespace: openfaas-prod-fn 386 | basic_auth: true 387 | operator: 388 | create: true 389 | createCRD: false 390 | gateway: 391 | replicas: 2 392 | ingress: 393 | enabled: true 394 | annotations: 395 | kubernetes.io/ingress.class: "contour" 396 | certmanager.k8s.io/cluster-issuer: "letsencrypt" 397 | contour.heptio.com/request-timeout: "30s" 398 | contour.heptio.com/num-retries: "3" 399 | contour.heptio.com/retry-on: "gateway-error" 400 | hosts: 401 | - host: openfaas.example.com 402 | serviceName: gateway 403 | servicePort: 8080 404 | path: / 405 | tls: 406 | - secretName: openfaas-cert 407 | hosts: 408 | - openfaas.example.com 409 | affinity: 410 | nodeAffinity: 411 | requiredDuringSchedulingIgnoredDuringExecution: 412 | nodeSelectorTerms: 413 | - matchExpressions: 414 | - key: cloud.google.com/gke-preemptible 415 | operator: DoesNotExist 416 | podAntiAffinity: 417 | preferredDuringSchedulingIgnoredDuringExecution: 418 | - weight: 100 419 | podAffinityTerm: 420 | labelSelector: 421 | matchLabels: 422 | app: gateway 423 | release: openfaas-prod 424 | topologyKey: kubernetes.io/hostname 425 | ``` 426 | 427 | For production the OpenFaaS gateway is scaled to two replicas and with the pod anti-affinity rule we make sure that each replica will run on a different node. 428 | Note that `operator.createCRD` is set to false since the `functions.openfaas.com` custom resource definition is already present on the cluster. 429 | 430 | Save the above file as `openfaas-prod.yaml` and install OpenFaaS instance from the project helm repository: 431 | 432 | ```bash 433 | helm upgrade openfaas-prod --install openfaas/openfaas \ 434 | --namespace openfaas-prod \ 435 | -f openfaas-prod.yaml 436 | ``` 437 | 438 | ### OpenFaaS functions operations 439 | 440 | ![openfaas-operator](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/gke-openfaas-operator.png) 441 | 442 | Using the OpenFaaS CRD you can define functions as Kubernetes custom resource: 443 | 444 | ```yaml 445 | apiVersion: openfaas.com/v1alpha2 446 | kind: Function 447 | metadata: 448 | name: certinfo 449 | spec: 450 | name: certinfo 451 | image: stefanprodan/certinfo:latest 452 | labels: 453 | com.openfaas.scale.min: "2" 454 | com.openfaas.scale.max: "12" 455 | com.openfaas.scale.factor: "4" 456 | limits: 457 | cpu: "1000m" 458 | memory: "128Mi" 459 | requests: 460 | cpu: "10m" 461 | memory: "64Mi" 462 | constraints: 463 | - "cloud.google.com/gke-preemptible=true" 464 | ``` 465 | 466 | Note that this function will be running on the fn pool due to the affinity constraint `cloud.google.com/gke-preemptible=true`. 467 | 468 | Save the above resource as `certinfo.yaml` and use `kubectl` to deploy the function on both instances: 469 | 470 | ```bash 471 | kubectl -n openfaas-stg-fn apply -f certinfo.yaml 472 | kubectl -n openfaas-prod-fn apply -f certinfo.yaml 473 | ``` 474 | 475 | Verify both endpoints are live: 476 | 477 | ``` 478 | curl -d "openfaas-stg.example.com" https://openfaas-stg.example.com/function/certinfo 479 | 480 | Issuer Let's Encrypt Authority X3 481 | .... 482 | 483 | curl -d "openfaas.example.com" https://openfaas.example.com/function/certinfo 484 | 485 | Issuer Let's Encrypt Authority X3 486 | .... 487 | ``` 488 | 489 | To manage functions on Kubernetes you can use kubectl but for development you'll need the OpenFaaS CLI. 490 | You can install faas-cli and connect to the staging instance with: 491 | 492 | ```bash 493 | curl -sL https://cli.openfaas.com | sudo sh 494 | 495 | echo $stg_password | faas-cli login -u admin --password-stdin -g https://openfaas-stg.example.com 496 | ``` 497 | 498 | Using faas-cli and kubectl a development workflow would look like this: 499 | 500 | * Create a function from a code template `faas-cli new myfn --lang go --prefix gcr.io/project-id` 501 | * Implement the function handler 502 | * Build the function as a Docker image `faas-cli build -f myfn.yaml` 503 | * Run the function on your local cluster `faas-cli deploy -f myfn.yaml -g localhost:8080` 504 | * Push the image to GCP Container Registry `faas-cli push -f myfn.yml` 505 | * Generate the function Kubernetes custom resource `faas-cli generate --yaml myfn.yaml > myfn-k8s.yaml` 506 | * Deploy it on the staging environment `kubectl -n openfaas-stg-fn apply -f myfn-k8s.yaml` 507 | * Run integration tests on staging `cat test.json | faas-cli invoke myfn -g https://openfaas-stg.exmaple.com` 508 | * Promote the function to production `kubectl -n openfaas-prod-fn apply -f myfn-k8s.yaml` 509 | 510 | In a later post I'll show you how you can automate the CI and staging deployment with OpenFaaS Cloud 511 | and production promotions with Weave Flux Helm Operator. 512 | 513 | 514 | -------------------------------------------------------------------------------- /namespaces.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: openfaas 6 | --- 7 | apiVersion: v1 8 | kind: Namespace 9 | metadata: 10 | name: openfaas-fn 11 | 12 | -------------------------------------------------------------------------------- /openfaas-down.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | kubectl delete -f ./namespaces.yaml 8 | -------------------------------------------------------------------------------- /openfaas-tls/README.md: -------------------------------------------------------------------------------- 1 | # OpenFaaS HTTPS Ingress 2 | 3 | This is a step by step guide on setting up HTTPS for OpenFaaS Gateway with Google Cloud L7 load balancer 4 | and Let's Encrypt free TLS certificate. 5 | 6 | ![ingress-tls](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/ingress-tls.png) 7 | 8 | ### DNS Setup 9 | 10 | The first step in setting up the GCP load balancer is reserving a global public IP: 11 | 12 | ```bash 13 | gcloud compute addresses create openfaas-ip --global 14 | ``` 15 | 16 | Find out what IP address you've been assigned: 17 | 18 | ```bash 19 | gcloud compute addresses describe openfaas-ip --global 20 | ``` 21 | 22 | Use this IP to create a DNS A record for your `openfaas` sub domain. 23 | 24 | ### Let's Encrypt Setup 25 | 26 | We'll be using kube-lego to automate the Let's Encrypt certificate request and renewal. 27 | 28 | Create a file named `lego-cfg.yaml` with the following content: 29 | 30 | ```yaml 31 | kind: ConfigMap 32 | apiVersion: v1 33 | metadata: 34 | name: kube-lego 35 | namespace: openfaas 36 | data: 37 | lego.email: "contact@example.com" 38 | lego.url: "https://acme-v01.api.letsencrypt.org/directory" 39 | ``` 40 | 41 | Replace `contact@example.com` with a valid email address, Let's Encrypt will contact you 42 | if there is a problem with your certificate. 43 | 44 | Assuming you're running the OpenFaaS Gateway in the `openfaas` namespace, let's deploy the config with `kubectl`: 45 | 46 | ```bash 47 | kubectl apply -f ./lego-cfg.yaml 48 | ``` 49 | 50 | Next we need to create a service account and a cluster role binding for kube-lego to be able to operate: 51 | 52 | ```yaml 53 | apiVersion: v1 54 | kind: ServiceAccount 55 | metadata: 56 | name: kube-lego 57 | namespace: openfaas 58 | --- 59 | apiVersion: rbac.authorization.k8s.io/v1 60 | kind: ClusterRole 61 | metadata: 62 | name: kube-lego 63 | rules: 64 | - apiGroups: 65 | - extensions 66 | resources: 67 | - ingresses 68 | verbs: 69 | - list 70 | - get 71 | - create 72 | - update 73 | - delete 74 | - watch 75 | - apiGroups: 76 | - "" 77 | resources: 78 | - endpoints 79 | - services 80 | - secrets 81 | verbs: 82 | - get 83 | - create 84 | - update 85 | --- 86 | apiVersion: rbac.authorization.k8s.io/v1 87 | kind: ClusterRoleBinding 88 | metadata: 89 | name: kube-lego 90 | roleRef: 91 | apiGroup: rbac.authorization.k8s.io 92 | kind: ClusterRole 93 | name: kube-lego 94 | subjects: 95 | - kind: ServiceAccount 96 | name: kube-lego 97 | namespace: openfaas 98 | ``` 99 | 100 | Save the above YAML as `lego-rbac.yaml` and apply it: 101 | 102 | ```bash 103 | kubectl apply -f ./lego-rbac.yaml 104 | ``` 105 | 106 | Now let's create the kube-lego deployment file: 107 | 108 | ```yaml 109 | apiVersion: apps/v1beta2 110 | kind: Deployment 111 | metadata: 112 | name: kube-lego 113 | namespace: openfaas 114 | spec: 115 | replicas: 1 116 | selector: 117 | matchLabels: 118 | app: kube-lego 119 | template: 120 | metadata: 121 | labels: 122 | app: kube-lego 123 | spec: 124 | serviceAccountName: kube-lego 125 | containers: 126 | - name: kube-lego 127 | image: jetstack/kube-lego:0.1.5 128 | imagePullPolicy: Always 129 | ports: 130 | - containerPort: 8080 131 | env: 132 | - name: LEGO_LOG_LEVEL 133 | value: debug 134 | - name: LEGO_EMAIL 135 | valueFrom: 136 | configMapKeyRef: 137 | name: kube-lego 138 | key: lego.email 139 | - name: LEGO_URL 140 | valueFrom: 141 | configMapKeyRef: 142 | name: kube-lego 143 | key: lego.url 144 | - name: LEGO_NAMESPACE 145 | valueFrom: 146 | fieldRef: 147 | fieldPath: metadata.namespace 148 | - name: LEGO_POD_IP 149 | valueFrom: 150 | fieldRef: 151 | fieldPath: status.podIP 152 | readinessProbe: 153 | httpGet: 154 | path: /healthz 155 | port: 8080 156 | initialDelaySeconds: 5 157 | timeoutSeconds: 1 158 | ``` 159 | 160 | Save the above YAML as `lego-dep.yaml` and apply it: 161 | 162 | ```bash 163 | kubectl apply -f ./lego-dep.yaml 164 | ``` 165 | 166 | ### Reverse Proxy Setup 167 | 168 | We'll be using Caddy as a reverse proxy, health check and basic-auth provider for the OpenFaaS Gateway. 169 | 170 | First create the Caddy config file: 171 | 172 | ```yaml 173 | kind: ConfigMap 174 | apiVersion: v1 175 | metadata: 176 | name: caddy-tls-config 177 | namespace: openfaas 178 | labels: 179 | app: caddy-tls 180 | data: 181 | Caddyfile: | 182 | :80 { 183 | status 200 /healthz 184 | basicauth /ui {$ADMIN_USER} {$ADMIN_PASSWORD} 185 | basicauth /system {$ADMIN_USER} {$ADMIN_PASSWORD} 186 | proxy / gateway:8080 { 187 | transparent 188 | } 189 | 190 | errors stderr 191 | tls off 192 | } 193 | ``` 194 | 195 | Create the basic-auth secret and apply `caddy-cfg.yaml`: 196 | 197 | ```bash 198 | kubectl -n openfaas create secret generic basic-auth-tls \ 199 | --from-literal=user=admin \ 200 | --from-literal=password=admin 201 | 202 | kubectl apply -f ./caddy-cfg.yaml 203 | ``` 204 | 205 | Next let's create the Caddy deployment with a readiness probe pointing to the `/healthz` endpoint. 206 | The readiness probe will be used by the Ingress controller health checks. 207 | 208 | ```yaml 209 | apiVersion: apps/v1beta2 210 | kind: Deployment 211 | metadata: 212 | name: caddy-tls 213 | namespace: openfaas 214 | spec: 215 | replicas: 1 216 | selector: 217 | matchLabels: 218 | app: caddy-tls 219 | template: 220 | metadata: 221 | labels: 222 | app: caddy-tls 223 | spec: 224 | containers: 225 | - name: caddy-tls 226 | image: stefanprodan/caddy:0.10.10 227 | imagePullPolicy: Always 228 | command: ["caddy", "-agree", "--conf", "/Caddyfile"] 229 | env: 230 | - name: ADMIN_USER 231 | valueFrom: 232 | secretKeyRef: 233 | name: basic-auth-tls 234 | key: user 235 | - name: ADMIN_PASSWORD 236 | valueFrom: 237 | secretKeyRef: 238 | name: basic-auth-tls 239 | key: password 240 | ports: 241 | - containerPort: 80 242 | protocol: TCP 243 | readinessProbe: 244 | httpGet: 245 | path: /healthz 246 | port: 80 247 | initialDelaySeconds: 5 248 | timeoutSeconds: 1 249 | resources: 250 | limits: 251 | memory: 128Mi 252 | volumeMounts: 253 | - mountPath: /Caddyfile 254 | name: caddy-config 255 | subPath: Caddyfile 256 | volumes: 257 | - name: caddy-config 258 | configMap: 259 | name: caddy-tls-config 260 | items: 261 | - key: Caddyfile 262 | path: Caddyfile 263 | mode: 0644 264 | ``` 265 | 266 | Save the above YAML as `caddy-dep.yaml` and apply it: 267 | 268 | ```bash 269 | kubectl apply -f ./caddy-dep.yaml 270 | ``` 271 | 272 | Next we need to create a NodePort Service to serve as backend for the GCP Ingress controller: 273 | 274 | ```yaml 275 | apiVersion: v1 276 | kind: Service 277 | metadata: 278 | name: caddy-tls-svc 279 | namespace: openfaas 280 | annotations: 281 | prometheus.io.scrape: 'false' 282 | labels: 283 | app: caddy-tls 284 | spec: 285 | type: NodePort 286 | ports: 287 | - port: 80 288 | name: web 289 | nodePort: 30049 290 | selector: 291 | app: caddy-tls 292 | ``` 293 | 294 | Save the above YAML as `caddy-svc.yaml` and apply it: 295 | 296 | ```bash 297 | kubectl apply -f ./lego-svc.yaml 298 | ``` 299 | 300 | ### Ingress Setup 301 | 302 | Now it's time to create the Ingress definition using the static IP and the Caddy service as backend: 303 | 304 | ```yaml 305 | apiVersion: extensions/v1beta1 306 | kind: Ingress 307 | metadata: 308 | name: openfaas-ingress 309 | namespace: openfaas 310 | annotations: 311 | kubernetes.io/tls-acme: "true" 312 | kubernetes.io/ingress.class: "gce" 313 | kubernetes.io/ingress.global-static-ip-name: openfaas-ip 314 | prometheus.io.scrape: 'false' 315 | labels: 316 | app: caddy-tls 317 | spec: 318 | tls: 319 | - hosts: 320 | - openfaas.example.com 321 | secretName: openfaas-tls 322 | rules: 323 | - host: openfaas.example.com 324 | http: 325 | paths: 326 | - path: /* 327 | backend: 328 | serviceName: caddy-tls-svc 329 | servicePort: 80 330 | ``` 331 | 332 | Replace `openfaas.example.com` with you're own domain, save the YAML as `ingress-tls.yaml` and apply it: 333 | 334 | ```bash 335 | kubectl apply -f ./ingress-tls.yaml 336 | ``` 337 | 338 | It will take at least 10 minutes for the GCP load balancer to become healthy. You can check the Ingress status with: 339 | 340 | ```bash 341 | kubectl -n openfaas describe ingress openfaas-ingress 342 | ``` 343 | 344 | Once the Ingress is up, kube-lego will attach a new backend to the load balancer and will request a certificate. 345 | Kube-lego will create a secret named `openfaas-tls` that will contain the Let's Encrypt certificate, from there 346 | the GCP load balancer will load the certificate and you will be able to access the OpenFaaS 347 | at `https://openfaas.exmaple.com`. 348 | 349 | ![ingress-tls](https://github.com/stefanprodan/openfaas-gke/blob/master/screens/ingress-stats.png) 350 | 351 | -------------------------------------------------------------------------------- /openfaas-tls/caddy-cfg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | name: caddy-tls-config 6 | namespace: openfaas 7 | labels: 8 | app: caddy-tls 9 | data: 10 | Caddyfile: | 11 | :80 { 12 | status 200 /healthz 13 | basicauth /system {$ADMIN_USER} {$ADMIN_PASSWORD} 14 | basicauth /ui {$ADMIN_USER} {$ADMIN_PASSWORD} 15 | proxy / gateway:8080 { 16 | transparent 17 | } 18 | 19 | errors stderr 20 | tls off 21 | } 22 | -------------------------------------------------------------------------------- /openfaas-tls/caddy-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: caddy-tls 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: caddy-tls 12 | template: 13 | metadata: 14 | labels: 15 | app: caddy-tls 16 | spec: 17 | containers: 18 | - name: caddy-tls 19 | image: stefanprodan/caddy:0.10.10 20 | imagePullPolicy: Always 21 | command: ["caddy", "-agree", "--conf", "/Caddyfile"] 22 | env: 23 | - name: ADMIN_USER 24 | valueFrom: 25 | secretKeyRef: 26 | name: basic-auth 27 | key: user 28 | - name: ADMIN_PASSWORD 29 | valueFrom: 30 | secretKeyRef: 31 | name: basic-auth 32 | key: password 33 | ports: 34 | - containerPort: 80 35 | protocol: TCP 36 | readinessProbe: 37 | httpGet: 38 | path: /healthz 39 | port: 80 40 | initialDelaySeconds: 1 41 | resources: 42 | limits: 43 | memory: 128Mi 44 | volumeMounts: 45 | - mountPath: /Caddyfile 46 | name: caddy-config 47 | subPath: Caddyfile 48 | volumes: 49 | - name: caddy-config 50 | configMap: 51 | name: caddy-tls-config 52 | items: 53 | - key: Caddyfile 54 | path: Caddyfile 55 | mode: 0644 56 | -------------------------------------------------------------------------------- /openfaas-tls/caddy-svc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: caddy-tls-svc 6 | namespace: openfaas 7 | annotations: 8 | prometheus.io.scrape: 'false' 9 | labels: 10 | app: caddy-tls 11 | spec: 12 | type: NodePort 13 | ports: 14 | - port: 80 15 | name: web 16 | nodePort: 30049 17 | selector: 18 | app: caddy-tls 19 | -------------------------------------------------------------------------------- /openfaas-tls/ingress-tls.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: extensions/v1beta1 3 | kind: Ingress 4 | metadata: 5 | name: openfaas-ingress 6 | namespace: openfaas 7 | annotations: 8 | kubernetes.io/tls-acme: "true" 9 | kubernetes.io/ingress.class: "gce" 10 | kubernetes.io/ingress.global-static-ip-name: openfaas-ip 11 | prometheus.io.scrape: 'false' 12 | labels: 13 | app: caddy-tls 14 | spec: 15 | tls: 16 | - hosts: 17 | - openfaas.weavedx.com 18 | secretName: openfaas-tls 19 | rules: 20 | - host: openfaas.weavedx.com 21 | http: 22 | paths: 23 | - path: /* 24 | backend: 25 | serviceName: caddy-tls-svc 26 | servicePort: 80 27 | -------------------------------------------------------------------------------- /openfaas-tls/lego-cfg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | name: kube-lego 6 | namespace: openfaas 7 | data: 8 | lego.email: "stefan@weave.works" 9 | lego.url: "https://acme-v01.api.letsencrypt.org/directory" 10 | -------------------------------------------------------------------------------- /openfaas-tls/lego-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: kube-lego 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: kube-lego 12 | template: 13 | metadata: 14 | labels: 15 | app: kube-lego 16 | spec: 17 | serviceAccountName: kube-lego 18 | containers: 19 | - name: kube-lego 20 | image: jetstack/kube-lego:0.1.5 21 | imagePullPolicy: Always 22 | ports: 23 | - containerPort: 8080 24 | env: 25 | - name: LEGO_LOG_LEVEL 26 | value: debug 27 | - name: LEGO_EMAIL 28 | valueFrom: 29 | configMapKeyRef: 30 | name: kube-lego 31 | key: lego.email 32 | - name: LEGO_URL 33 | valueFrom: 34 | configMapKeyRef: 35 | name: kube-lego 36 | key: lego.url 37 | - name: LEGO_NAMESPACE 38 | valueFrom: 39 | fieldRef: 40 | fieldPath: metadata.namespace 41 | - name: LEGO_POD_IP 42 | valueFrom: 43 | fieldRef: 44 | fieldPath: status.podIP 45 | readinessProbe: 46 | httpGet: 47 | path: /healthz 48 | port: 8080 49 | initialDelaySeconds: 5 50 | timeoutSeconds: 1 51 | -------------------------------------------------------------------------------- /openfaas-tls/lego-rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: kube-lego 6 | namespace: openfaas 7 | --- 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | name: kube-lego 12 | rules: 13 | - apiGroups: 14 | - extensions 15 | resources: 16 | - ingresses 17 | verbs: 18 | - list 19 | - get 20 | - create 21 | - update 22 | - delete 23 | - watch 24 | - apiGroups: 25 | - "" 26 | resources: 27 | - endpoints 28 | - services 29 | - secrets 30 | verbs: 31 | - get 32 | - create 33 | - update 34 | --- 35 | apiVersion: rbac.authorization.k8s.io/v1 36 | kind: ClusterRoleBinding 37 | metadata: 38 | name: kube-lego 39 | roleRef: 40 | apiGroup: rbac.authorization.k8s.io 41 | kind: ClusterRole 42 | name: kube-lego 43 | subjects: 44 | - kind: ServiceAccount 45 | name: kube-lego 46 | namespace: openfaas 47 | -------------------------------------------------------------------------------- /openfaas-up.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | get_gateway_ip() { 8 | kubectl -n openfaas describe service caddy-lb | grep Ingress | awk '{ print $NF }' 9 | } 10 | 11 | # validate inputs 12 | if [ -z "$basic_auth_user" ]; then 13 | echo "basic_auth_user is required" 14 | exit 1 15 | fi 16 | 17 | if [ -z "$basic_auth_password" ]; then 18 | echo "basic_auth_password is required" 19 | exit 1 20 | fi 21 | 22 | # create namespaces 23 | kubectl apply -f ./namespaces.yaml 24 | 25 | # create basic-auth secrets 26 | kubectl -n openfaas create secret generic basic-auth \ 27 | --from-literal=user=${basic_auth_user} \ 28 | --from-literal=password=${basic_auth_password} 29 | 30 | # deploy OpenFaaS 31 | kubectl apply -f ./openfaas 32 | 33 | # deploy Caddy LB 34 | kubectl apply -f ./caddy 35 | 36 | # wait for the public IP to assigned 37 | until [[ "$(get_gateway_ip)" ]] 38 | do sleep 1; 39 | echo -n "."; 40 | done 41 | echo "." 42 | gateway_ip=$(get_gateway_ip) 43 | echo "OpenFaaS Gateway IP: ${gateway_ip}" 44 | 45 | # save OpenFaaS credentials 46 | echo ${basic_auth_password} | faas-cli login -u ${basic_auth_user} --password-stdin --gateway=http://${gateway_ip} 47 | 48 | -------------------------------------------------------------------------------- /openfaas/alertmanager-cfg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | labels: 6 | app: alertmanager 7 | name: alertmanager-config 8 | namespace: openfaas 9 | data: 10 | alertmanager.yml: | 11 | route: 12 | group_by: ['alertname', 'cluster', 'service'] 13 | group_wait: 5s 14 | group_interval: 10s 15 | repeat_interval: 30s 16 | receiver: scale-up 17 | routes: 18 | - match: 19 | service: gateway 20 | receiver: scale-up 21 | severity: major 22 | inhibit_rules: 23 | - source_match: 24 | severity: 'critical' 25 | target_match: 26 | severity: 'warning' 27 | equal: ['alertname', 'cluster', 'service'] 28 | receivers: 29 | - name: 'scale-up' 30 | webhook_configs: 31 | - url: http://gateway.openfaas:8080/system/alert 32 | send_resolved: true 33 | 34 | -------------------------------------------------------------------------------- /openfaas/alertmanager-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: alertmanager 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: alertmanager 12 | template: 13 | metadata: 14 | labels: 15 | app: alertmanager 16 | spec: 17 | containers: 18 | - name: alertmanager 19 | image: prom/alertmanager:v0.15.0-rc.0 20 | imagePullPolicy: Always 21 | command: 22 | - alertmanager 23 | - --config.file=/alertmanager.yml 24 | - --storage.path=/alertmanager 25 | ports: 26 | - containerPort: 9093 27 | protocol: TCP 28 | resources: 29 | limits: 30 | memory: 128Mi 31 | volumeMounts: 32 | - mountPath: /alertmanager.yml 33 | name: alertmanager-config 34 | subPath: alertmanager.yml 35 | volumes: 36 | - name: alertmanager-config 37 | configMap: 38 | name: alertmanager-config 39 | items: 40 | - key: alertmanager.yml 41 | path: alertmanager.yml 42 | mode: 0644 43 | 44 | -------------------------------------------------------------------------------- /openfaas/alertmanager-svc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: alertmanager 6 | namespace: openfaas 7 | annotations: 8 | prometheus.io.scrape: 'false' 9 | labels: 10 | app: alertmanager 11 | spec: 12 | type: ClusterIP 13 | ports: 14 | - port: 9093 15 | protocol: TCP 16 | targetPort: 9093 17 | selector: 18 | app: alertmanager 19 | -------------------------------------------------------------------------------- /openfaas/gateway-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: gateway 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: gateway 12 | template: 13 | metadata: 14 | labels: 15 | app: gateway 16 | spec: 17 | containers: 18 | - name: gateway 19 | image: functions/gateway:0.7.8 20 | imagePullPolicy: Always 21 | env: 22 | - name: faas_prometheus_host 23 | value: "prometheus.openfaas" 24 | - name: functions_provider_url 25 | value: "http://faas-netesd.openfaas:8080/" 26 | - name: faas_nats_address 27 | value: "nats.openfaas" 28 | - name: faas_nats_port 29 | value: "4222" 30 | - name: direct_functions 31 | value: "true" 32 | - name: direct_functions_suffix 33 | value: "openfaas-fn" 34 | - name: write_timeout 35 | value: "60s" 36 | - name: read_timeout 37 | value: "60s" 38 | - name: upstream_timeout 39 | value: "55s" 40 | ports: 41 | - containerPort: 8080 42 | protocol: TCP 43 | resources: 44 | limits: 45 | memory: 1024Mi 46 | -------------------------------------------------------------------------------- /openfaas/gateway-svc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: gateway 6 | namespace: openfaas 7 | labels: 8 | app: gateway 9 | spec: 10 | type: ClusterIP 11 | ports: 12 | - port: 8080 13 | protocol: TCP 14 | targetPort: 8080 15 | selector: 16 | app: gateway 17 | -------------------------------------------------------------------------------- /openfaas/nats-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: nats 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: nats 12 | template: 13 | metadata: 14 | labels: 15 | app: nats 16 | annotations: 17 | prometheus.io.scrape: 'false' 18 | spec: 19 | containers: 20 | - name: nats 21 | image: nats-streaming:0.6.0 22 | imagePullPolicy: Always 23 | ports: 24 | - containerPort: 4222 25 | protocol: TCP 26 | - containerPort: 8222 27 | protocol: TCP 28 | command: ["/nats-streaming-server"] 29 | args: 30 | - --store 31 | - memory 32 | - --cluster_id 33 | - faas-cluster 34 | resources: 35 | limits: 36 | memory: 512Mi 37 | -------------------------------------------------------------------------------- /openfaas/nats-svc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: nats 6 | namespace: openfaas 7 | annotations: 8 | prometheus.io.scrape: 'false' 9 | labels: 10 | app: nats 11 | spec: 12 | type: ClusterIP 13 | ports: 14 | - port: 4222 15 | protocol: TCP 16 | targetPort: 4222 17 | selector: 18 | app: nats 19 | -------------------------------------------------------------------------------- /openfaas/netesd-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: faas-netesd 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: faas-netesd 12 | template: 13 | metadata: 14 | labels: 15 | app: faas-netesd 16 | annotations: 17 | prometheus.io.scrape: 'false' 18 | spec: 19 | serviceAccountName: faas-controller 20 | containers: 21 | - name: faas-netesd 22 | image: functions/faas-netesd:0.4.6 23 | imagePullPolicy: Always 24 | env: 25 | - name: function_namespace 26 | value: openfaas-fn 27 | - name: write_timeout 28 | value: "60" 29 | - name: read_timeout 30 | value: "60" 31 | ports: 32 | - containerPort: 8080 33 | protocol: TCP 34 | resources: 35 | limits: 36 | memory: 1024Mi 37 | -------------------------------------------------------------------------------- /openfaas/netesd-rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: faas-controller 6 | namespace: openfaas 7 | --- 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | name: faas-controller 12 | rules: 13 | - apiGroups: 14 | - "" 15 | resources: 16 | - services 17 | verbs: 18 | - get 19 | - list 20 | - watch 21 | - create 22 | - delete 23 | - update 24 | - apiGroups: 25 | - "" 26 | resources: 27 | - secrets 28 | verbs: 29 | - get 30 | - list 31 | - watch 32 | - apiGroups: 33 | - extensions 34 | resources: 35 | - deployments 36 | verbs: 37 | - get 38 | - list 39 | - watch 40 | - create 41 | - delete 42 | - update 43 | --- 44 | apiVersion: rbac.authorization.k8s.io/v1 45 | kind: ClusterRoleBinding 46 | metadata: 47 | name: faas-controller 48 | roleRef: 49 | apiGroup: rbac.authorization.k8s.io 50 | kind: ClusterRole 51 | name: faas-controller 52 | subjects: 53 | - kind: ServiceAccount 54 | name: faas-controller 55 | namespace: openfaas 56 | --- 57 | apiVersion: rbac.authorization.k8s.io/v1 58 | kind: ClusterRoleBinding 59 | metadata: 60 | name: faas-controller-fn 61 | roleRef: 62 | apiGroup: rbac.authorization.k8s.io 63 | kind: ClusterRole 64 | name: faas-controller 65 | subjects: 66 | - kind: ServiceAccount 67 | name: faas-controller 68 | namespace: openfaas-fn 69 | -------------------------------------------------------------------------------- /openfaas/netesd-svc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: faas-netesd 6 | namespace: openfaas 7 | annotations: 8 | prometheus.io.scrape: 'false' 9 | labels: 10 | app: faas-netesd 11 | spec: 12 | type: ClusterIP 13 | ports: 14 | - port: 8080 15 | protocol: TCP 16 | targetPort: 8080 17 | selector: 18 | app: faas-netesd 19 | -------------------------------------------------------------------------------- /openfaas/prometheus-cfg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | labels: 6 | app: prometheus 7 | name: prometheus-config 8 | namespace: openfaas 9 | data: 10 | prometheus.yml: | 11 | global: 12 | scrape_interval: 15s 13 | evaluation_interval: 15s 14 | external_labels: 15 | monitor: 'faas-monitor' 16 | rule_files: 17 | - 'alert.rules.yml' 18 | scrape_configs: 19 | - job_name: 'prometheus' 20 | scrape_interval: 5s 21 | static_configs: 22 | - targets: ['localhost:9090'] 23 | - job_name: "gateway" 24 | scrape_interval: 5s 25 | dns_sd_configs: 26 | - names: ['gateway'] 27 | port: 8080 28 | type: A 29 | refresh_interval: 5s 30 | alerting: 31 | alertmanagers: 32 | - static_configs: 33 | - targets: 34 | - alertmanager:9093 35 | alert.rules.yml: | 36 | groups: 37 | - name: openfaas 38 | rules: 39 | - alert: service_down 40 | expr: up == 0 41 | - alert: APIHighInvocationRate 42 | expr: sum(rate(gateway_function_invocation_total{code="200"}[10s])) BY (function_name) 43 | > 5 44 | for: 5s 45 | labels: 46 | service: gateway 47 | severity: major 48 | value: '{{$value}}' 49 | annotations: 50 | description: High invocation total on {{ $labels.instance }} 51 | summary: High invocation total on {{ $labels.instance }} 52 | 53 | -------------------------------------------------------------------------------- /openfaas/prometheus-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: prometheus 6 | namespace: openfaas 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: prometheus 12 | template: 13 | metadata: 14 | labels: 15 | app: prometheus 16 | spec: 17 | containers: 18 | - name: prometheus 19 | image: prom/prometheus:v2.2.0 20 | imagePullPolicy: Always 21 | command: 22 | - prometheus 23 | - --config.file=/etc/prometheus/prometheus.yml 24 | ports: 25 | - containerPort: 9090 26 | protocol: TCP 27 | resources: 28 | limits: 29 | memory: 1Gi 30 | volumeMounts: 31 | - mountPath: /etc/prometheus/prometheus.yml 32 | name: prometheus-config 33 | subPath: prometheus.yml 34 | - mountPath: /etc/prometheus/alert.rules.yml 35 | name: prometheus-config 36 | subPath: alert.rules.yml 37 | volumes: 38 | - name: prometheus-config 39 | configMap: 40 | name: prometheus-config 41 | items: 42 | - key: prometheus.yml 43 | path: prometheus.yml 44 | mode: 0644 45 | - key: alert.rules.yml 46 | path: alert.rules.yml 47 | mode: 0644 48 | -------------------------------------------------------------------------------- /openfaas/prometheus-svc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: prometheus 6 | namespace: openfaas 7 | labels: 8 | app: prometheus 9 | spec: 10 | type: ClusterIP 11 | ports: 12 | - port: 9090 13 | protocol: TCP 14 | targetPort: 9090 15 | selector: 16 | app: prometheus 17 | -------------------------------------------------------------------------------- /openfaas/queue-worker-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta2 3 | kind: Deployment 4 | metadata: 5 | name: queue-worker 6 | namespace: openfaas 7 | spec: 8 | replicas: 3 9 | selector: 10 | matchLabels: 11 | app: queue-worker 12 | template: 13 | metadata: 14 | labels: 15 | app: queue-worker 16 | annotations: 17 | prometheus.io.scrape: 'false' 18 | spec: 19 | containers: 20 | - name: queue-worker 21 | image: functions/queue-worker:0.4.3 22 | imagePullPolicy: Always 23 | env: 24 | - name: faas_function_suffix 25 | value: ".openfaas-fn" 26 | - name: faas_gateway_address 27 | value: "gateway.openfaas" 28 | - name: faas_nats_address 29 | value: "nats.openfaas" 30 | - name: early_ack 31 | value: "true" 32 | - name: ack_wait 33 | value: "120s" 34 | - name: max_inflight 35 | value: "1" 36 | - name: faas_print_body 37 | value: "true" 38 | resources: 39 | limits: 40 | memory: 128Mi 41 | -------------------------------------------------------------------------------- /screens/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/banner.jpg -------------------------------------------------------------------------------- /screens/gke-network-policies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/gke-network-policies.png -------------------------------------------------------------------------------- /screens/gke-openfaas-costs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/gke-openfaas-costs.png -------------------------------------------------------------------------------- /screens/gke-openfaas-envs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/gke-openfaas-envs.png -------------------------------------------------------------------------------- /screens/gke-openfaas-operator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/gke-openfaas-operator.png -------------------------------------------------------------------------------- /screens/gke-operator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/gke-operator.png -------------------------------------------------------------------------------- /screens/gke-pools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/gke-pools.png -------------------------------------------------------------------------------- /screens/ingress-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/ingress-stats.png -------------------------------------------------------------------------------- /screens/ingress-tls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/ingress-tls.png -------------------------------------------------------------------------------- /screens/kube-dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/kube-dash.png -------------------------------------------------------------------------------- /screens/metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/metrics.png -------------------------------------------------------------------------------- /screens/nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/nodes.png -------------------------------------------------------------------------------- /screens/pods-scaling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/pods-scaling.png -------------------------------------------------------------------------------- /screens/scaling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanprodan/openfaas-gke/149b1fdbcaf6dc0652e2df11ea0aed3ca4e7162f/screens/scaling.png --------------------------------------------------------------------------------