Deploying OpenWhisk on IBM Cloud Private (ICP)

Overview

IBM Cloud Private (ICP) provides the core infrastructure needed to provision a production-quality OpenWhisk installation. This document outlines ICP-specific steps needed to provision that installation, and calls out shortcuts that could be taken for development-grade installation.

Initial setup

Creating the Kubernetes Cluster

Follow IBM Cloud Private instructions to provision your cluster. Include GlusterFS provisioning, add dynamic NFS provisioning, or be prepared to provision volumes manually for OpenWhisk (see here).

Configuring OpenWhisk

Configuring Image Security

IBM Cloud Private includes a provision for filtering the images that are allowed to be deployed into a particular namespace. One could disable this capability for the OpenWhisk namespace, but initally it is best to define a policy for the namespace: (In this case we assume the namespace is openwhisk)

apiVersion: securityenforcement.admission.cloud.ibm.com/v1beta1
kind: ImagePolicy
metadata:
  name: openwhisk-image-policy
  namespace: openwhisk
spec:
  repositories:
  - name: docker.io/openwhisk/*
    policy:
      va:
        enabled: false
  - name: docker.io/apache/couchdb:*
    policy:
      va:
        enabled: false
  - name: docker.io/nginx:*
    policy:
      va:
        enabled: false
  - name: docker.io/redis:*
    policy:
      va:
        enabled: false
  - name: docker.io/zookeeper:*
    policy:
      va:
        enabled: false
  - name: docker.io/wurstmeister/kafka:*
    policy:
      va:
        enabled: false

Configuring Ingress

An IBM Cloud Private cluster has full support for TLS and can be configured with additional annotations to fine tune ingress performance.

A prerequisite for OpenWhisk TLS access via Ingress as currently configured is a Fully Qualified Domain Name (FQDN) that can be resolved correctly from within OpenWhisk and points to the SSL Ingress point, usually your load balancer or proxy node.

You will also need to create a TLS certificate to be used by the Ingress controller for your domain. The YAML to create in Kubernetes is (substituting the real values for <your fqdn>):

apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: openwhisk-tls-secret-1
  namespace: openwhisk
spec:
  commonName: <your fqdn>
  dnsNames:
  - <your fqdn>
  issuerRef:
    kind: ClusterIssuer
    name: icp-ca-issuer
  secretName: openwhisk-tls-secret-1

Putting it all together

Now define mycluster.yaml as below (substituting the real values for <your fqdn>).

whisk:
  ingress:
    apiHostName: <your fqdn>
    apiHostPort: 443
    apiHostProto: https
    type: Standard
    domain: <your fqdn>
    tls:
      enabled: true
      secretenabled: true
      createsecret: false
      secretname: openwhisk-tls-secret-1
    annotations:
      # A blocking request is held open by the controller for slightly more than 60 seconds
      # before it is responded to with HTTP status code 202 (accepted) and closed.
      # Set to 75s to be on the safe side.
      # See https://console.bluemix.net/docs/containers/cs_annotations.html#proxy-connect-timeout
      # See http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout
      nginx.ingress.kubernetes.io/proxy-read-timeout: "75s"

      # Allow up to 50 MiB body size to support creation of large actions and large
      # parameter sizes.
      # See https://console.bluemix.net/docs/containers/cs_annotations.html#client-max-body-size
      # See http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size
      nginx.ingress.kubernetes.io/client-max-body-size: "size=50m"

      # Add the request_id, generated by nginx, to the request against the controllers. This id will be used as tid there.
      # Note that the serviceName includes the argument to --name from the helm deploy command. (owdev in this example)
      # https://console.bluemix.net/docs/containers/cs_annotations.html#proxy-add-headers
      nginx.ingress.kubernetes.io/proxy-add-headers: |
        serviceName=owdev-controller {
          'X-Request-ID' $request_id;
        }

k8s:
  persistence:
    hasDefaultStorageClass: false
    explicitStorageClass: openwhisk

ICP does not (by default) provide a properly configured DefaultStorageClass, instead you need to tell the Helm chart to use a storage class you've defined (see Creating the Kubernetes Cluster above).

Don‘t want to deal with Ingress (or can’t create an FQDN)?

An alternative to the Ingress-based access model is to use a NodePort. Use the IP address of any worker node in the cluster to define mycluster.yaml as

whisk:
  ingress:
    type: NodePort
    apiHostName: YOUR_WORKERS_PUBLIC_IP_ADDR
    apiHostPort: 31001

nginx:
  httpsNodePort: 31001

k8s:
  persistence:
    hasDefaultStorageClass: false
    explicitStorageClass: openwhisk

ICP does not (by default) provide a properly configured DefaultStorageClass, instead you need to tell the Helm chart to use a storage class you've defined (see Creating the Kubernetes Cluster above).

Hints and Tips

On IBM Cloud Private clusters, you can configure OpenWhisk to integrate with platform logging and monitoring services following the general instructions for enabling these services for pods deployed on Kubernetes.