Published: Dec 21, 2023 by Isaac Johnson
OpenFunction is a a cloud-native Function as a Service framework in the same realm as KNative and OpenFaaS. It’s a more recent offering with releases starting in May 2021 from the author Benjamin Huo of Kubesphere.
Let’s dig into this Apache 2.0 licenses CNCF Sandbox Project
Installation
We’ll start by adding the Helm repo and updating
$ helm repo add openfunction https://openfunction.github.io/charts/
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "openfunction" chart repository
...Successfully got an update from the "adwerx" chart repository
...Successfully got an update from the "longhorn" chart repository
...Successfully got an update from the "opencost" chart repository
...Successfully got an update from the "actions-runner-controller" chart repositoryn.com):
...Successfully got an update from the "ngrok" chart repositoryokup helm.epsagon.com on 172.22.64.1:53: no such host
...Successfully got an update from the "jfelten" chart repositoryitory
...Successfully got an update from the "zabbix-community" chart repository
...Successfully got an update from the "azure-samples" chart repository
...Successfully got an update from the "rook-release" chart repository
...Successfully got an update from the "confluentinc" chart repository
...Successfully got an update from the "nfs" chart repositorytory
...Successfully got an update from the "rhcharts" chart repositoryry
...Successfully got an update from the "btungut" chart repositoryository
...Successfully got an update from the "akomljen-charts" chart repository
...Successfully got an update from the "hashicorp" chart repositoryry
...Successfully got an update from the "portainer" chart repository
...Successfully got an update from the "sonarqube" chart repositoryepository
...Unable to get an update from the "freshbrewed" chart repository (https://harbor.freshbrewed.science/chartrepo/library):
...Succefailed to fetch https://harbor.freshbrewed.science/chartrepo/library/index.yaml : 404 Not Found
...Unable to get an update from the "myharbor" chart repository (https://harbor.freshbrewed.science/chartrepo/library):
...Succefailed to fetch https://harbor.freshbrewed.science/chartrepo/library/index.yaml : 404 Not Found
...Successfully got an update from the "dapr" chart repositoryrt repository
...Successfully got an update from the "kuma" chart repositoryt repository
...Successfully got an update from the "nginx-stable" chart repositorytps://harbor.freshbrewed.science/chartrepo/library):
...Successfully got an update from the "gitea-charts" chart repositoryibrary/index.yaml : 404 Not Found
...Successfully got an update from the "lifen-charts" chart repository://harbor.freshbrewed.science/chartrepo/library):
...Successfully got an update from the "castai-helm" chart repository
...Successfully got an update from the "open-telemetry" chart repository
...Successfully got an update from the "novum-rgi-helm" chart repository
...Successfully got an update from the "uptime-kuma" chart repository
...Successfully got an update from the "kube-state-metrics" chart repository
...Unable to get an update from the "epsagon" chart repository (https://helm.epsagon.com):
...SucceGet "https://helm.epsagon.com/index.yaml": dial tcp: lookup helm.epsagon.com on 172.22.64.1:53: no such host
...Successfully got an update from the "signoz" chart repository
...Successfully got an update from the "elastic" chart repositoryy
...Successfully got an update from the "openzipkin" chart repository
...Successfully got an update from the "kiwigrid" chart repository
...Successfully got an update from the "kubecost" chart repository
...Successfully got an update from the "sumologic" chart repository
...Successfully got an update from the "harbor" chart repository
...Successfully got an update from the "crossplane-stable" chart repository
...Successfully got an update from the "rancher-latest" chart repository
...Successfully got an update from the "incubator" chart repository
...Successfully got an update from the "datadog" chart repository
...Successfully got an update from the "gitlab" chart repository
...Successfully got an update from the "newrelic" chart repository
...Successfully got an update from the "argo-cd" chart repository
...Successfully got an update from the "grafana" chart repository
...Successfully got an update from the "bitnami" chart repository
...Successfully got an update from the "prometheus-community" chart repository
Update Complete. ⎈Happy Helming!⎈
I’m starting to think my blogging has amassed perhaps a bit too many chart repos…
We can now install OpenFunction into a new namespace
$ helm install openfunction openfunction/openfunction -n openfunction --create-namespace
W1208 16:45:19.684408 24437 warnings.go:70] The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1208 16:45:19.701421 24437 warnings.go:70] The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1208 16:45:48.569363 24437 warnings.go:70] The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1208 16:45:48.630311 24437 warnings.go:70] The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
NAME: openfunction
LAST DEPLOYED: Fri Dec 8 16:45:08 2023
NAMESPACE: openfunction
STATUS: deployed
REVISION: 1
TEST SUITE: None
This is my test cluster which is generally newer than production which would explain the Helm complaints on v1alpha2 gateways
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
builder-macbookpro2 Ready <none> 50d v1.27.6+k3s1
isaac-macbookpro Ready <none> 50d v1.27.6+k3s1
anna-macbookair Ready control-plane,master 50d v1.27.6+k3s1
If we want to add in the Revision Controller, which is optional, we can do that too
$ helm upgrade openfunction openfunction/openfunction -n openfunction --set revisionController.enable=true
Release "openfunction" has been upgraded. Happy Helming!
NAME: openfunction
LAST DEPLOYED: Fri Dec 8 16:49:10 2023
NAMESPACE: openfunction
STATUS: deployed
REVISION: 2
TEST SUITE: None
This installed quite a lot.
We have a contour gateway:
$ kubectl get gateway --all-namespaces
NAMESPACE NAME CLASS ADDRESS PROGRAMMED AGE
projectcontour contour contour 4m19s
And a slew of new namespaces
$ kubectl get ns
NAME STATUS AGE
default Active 50d
kube-system Active 50d
kube-public Active 50d
kube-node-lease Active 50d
punq Active 50d
immich Active 39d
openfunction Active 4m56s
projectcontour Active 4m55s
tekton-pipelines Active 4m29s
dapr-system Active 4m29s
shipwright-build Active 4m29s
keda Active 4m29s
knative-serving Active 4m29s
We can verify it’s running
$ kubectl get pods -n openfunction
NAME READY STATUS RESTARTS AGE
openfunction-controller-manager-7fcbdb6bf9-2hzp6 2/2 Running 0 8m47s
openfunction-revision-controller-867b9c74f4-9gwgq 1/1 Running 0 4m57s
Setup
I first need to create a docker cred that we can use to push and pull images.
$ kubectl create secret docker-registry push-secret --docker-server=harbor.freshbrewed.sc
ience --docker-username=forgejo --docker-password=nottherealpassword\!\!
secret/push-secret created
Next we create a GIT credential for our repo
$ cat forgejoPass.yaml
apiVersion: v1
kind: Secret
metadata:
name: git-repo-secret
annotations:
build.shipwright.io/referenced.secret: "true"
type: kubernetes.io/basic-auth
stringData:
username: isaac
password: xxxxxxxx
$ kubectl apply -f forgejoPass.yaml
secret/git-repo-secret created
I’m now going to push the samples to Forgejo
builder@DESKTOP-QADGF36:~/Workspaces$ git clone https://github.com/OpenFunction/samples.git
Cloning into 'samples'...
remote: Enumerating objects: 2411, done.
remote: Counting objects: 100% (852/852), done.
remote: Compressing objects: 100% (324/324), done.
remote: Total 2411 (delta 622), reused 609 (delta 521), pack-reused 1559
Receiving objects: 100% (2411/2411), 4.66 MiB | 7.53 MiB/s, done.
Resolving deltas: 100% (1179/1179), done.
I’ll make fork into my Forgejo by first creating a repo
I’ll just push a repo
builder@DESKTOP-QADGF36:~/Workspaces/samples$ git remote add origin2 https://forgejo.freshbrewed.science/isaac/openfuncsamples.git
builder@DESKTOP-QADGF36:~/Workspaces/samples$ git push -u origin2 main
Enumerating objects: 1996, done.
Counting objects: 100% (1996/1996), done.
Delta compression using up to 16 threads
Compressing objects: 100% (996/996), done.
Writing objects: 100% (1996/1996), 4.52 MiB | 3.60 MiB/s, done.
Total 1996 (delta 942), reused 1952 (delta 918)
remote: Resolving deltas: 100% (942/942), done.
remote: . Processing 1 references
remote: Processed 1 references in total
To https://forgejo.freshbrewed.science/isaac/openfuncsamples.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin2'.
Launching a Function
We can now launch a basic helloworld sample
$ cat mySample.yaml
apiVersion: core.openfunction.io/v1beta1
kind: Function
metadata:
name: function-sample
spec:
version: "v2.0.0"
image: "freshbrewedprivate/sample-go-func:v1"
imageCredentials:
name: push-secret
build:
builder: openfunction/builder-go:latest
env:
FUNC_NAME: "HelloWorld"
FUNC_CLEAR_SOURCE: "true"
srcRepo:
url: "https://forgejo.freshbrewed.science/isaac/openfuncsamples.git"
sourceSubPath: "functions/knative/hello-world-go"
revision: "main"
credentials:
name: git-repo-secret
serving:
template:
containers:
- name: function # DO NOT change this
imagePullPolicy: IfNotPresent
runtime: "knative"
$ kubectl apply -f mySample.yaml
function.core.openfunction.io/function-sample created
We can now see it building
$ kubectl get functions.core.openfunction.io
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING ADDRESS AGE
function-sample Building builder-l2h64 3m19s
It was taking some time so I checked back in the morn and saw it failed
$ kubectl get functions.core.openfunction.io
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING ADDRESS AGE
function-sample Failed builder-l2h64 17h
Just getting the logs only helps to determine the pod name
$ kubectl describe functions.core.openfunction.io function-sample | tail -n 8
Build:
Build Duration: 4m13s
Message: buildrun step step-create failed in pod builder-l2h64-buildrun-wj48w-w2z7s-pod, for detailed information: kubectl --namespace default logs builder-l2h64-buildrun-wj48w-w2z7s-pod --container=step-create
Reason: Failed
Resource Hash: 17904119356002819818
Resource Ref: builder-l2h64
State: Failed
Events: <none>
It does hint at the container in error above. We can see there are four in total
$ kubectl get pod builder-l2h64-buildrun-wj48w-w2z7s-pod
NAME READY STATUS RESTARTS AGE
builder-l2h64-buildrun-wj48w-w2z7s-pod 0/4 Error 0 17h
$ kubectl get pod builder-l2h64-buildrun-wj48w-w2z7s-pod -o json | jq '.spec.containers[] | .name'
"step-source-default"
"step-prepare"
"step-create"
"step-results"
Since it says “step-create” is in err, let’s see the logs for that container in the pod
$ kubectl logs builder-l2h64-buildrun-wj48w-w2z7s-pod --container step-create
===> DETECTING
4 of 5 buildpacks participating
openfunction.go.of-functions-framework 0.6.0
google.go.build 0.9.0
google.go.clear_source 0.9.0
google.utils.label 0.0.1
===> ANALYZING
Previous image with name "freshbrewedprivate/sample-go-func:v1" not found
===> RESTORING
===> BUILDING
=== Go - OpenFunction Functions Framework (openfunction.go.of-functions-framework@0.6.0) ===
--------------------------------------------------------------------------------
Running "go run /cnb/buildpacks/openfunction.go.of-functions-framework/0.6.0/converter/get_package/main.go -dir /workspace/source/functions/knative/hello-world-go/serverless_function_source_code (GOCACHE=/tmp/serverless_function_app3331328171)"
{"name":"hello","imports":{"fmt":{},"github.com/OpenFunction/functions-framework-go/context":{},"github.com/OpenFunction/functions-framework-go/functions":{},"net/http":{}}}Done "go run /cnb/buildpacks/openfunction.go.of-functions-framewor..." (596.102417ms)
Found framework version v0.5.0
=== Go - Build (google.go.build@0.9.0) ===
--------------------------------------------------------------------------------
Running "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..."
/workspace/source/functions/knative/hello-world-go
Done "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..." (729.810902ms)
--------------------------------------------------------------------------------
Running "go build -o /layers/google.go.build/bin/main ./. (GOCACHE=/layers/google.go.build/gocache CGO_ENABLED=0)"
Done "go build -o /layers/google.go.build/bin/main ./. (GOCACHE=/l..." (19.660144235s)
=== Go - Clear Source (google.go.clear_source@0.9.0) ===
Clearing source
=== Utils - Label Image (google.utils.label@0.0.1) ===
function package: {"name":"hello","imports":{"fmt":{},"github.com/OpenFunction/functions-framework-go/context":{},"github.com/OpenFunction/functions-framework-go/functions":{},"net/http":{}}}===> EXPORTING
Adding layer 'google.go.build:bin'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Saving freshbrewedprivate/sample-go-func:v1...
*** Images (sha256:0ff9c9013ae07a4aa18b036a05ac7f9b0e2e32ff792b1207b10f9abd3108dec3):
freshbrewedprivate/sample-go-func:v1 - HEAD https://index.docker.io/v2/freshbrewedprivate/sample-go-func/blobs/sha256:1ae7dafa9034f094a95f86577b809637b83522ae2cce442874d41b113a67e6d1: unexpected status code 401 Unauthorized (HEAD responses have no body, use GET for details)
ERROR: failed to export: failed to write image to the following tags: [freshbrewedprivate/sample-go-func:v1: HEAD https://index.docker.io/v2/freshbrewedprivate/sample-go-func/blobs/sha256:1ae7dafa9034f094a95f86577b809637b83522ae2cce442874d41b113a67e6d1: unexpected status code 401 Unauthorized (HEAD responses have no body, use GET for details)]
Interesting, it tried to push to Dockerhub instead of my private CR:
https://index.docker.io/v2/freshbrewedprivate/sample-go-func/blobs/sha256:1ae7dafa9034f094a95f86577b809637b83522ae2cce442874d41b113a67e6d1
I realized the issue was that I needed to pack the “image” field with the full path or it would assume docker.io
.
image: harbor.freshbrewed.science/freshbrewedprivate/sample-go-func:v1
Editing the function in kubernetes, then triggered and build and deploy.
Now when i get the YAML I see the status and endpoints
$ kubectl get function function-sample -o yaml
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"core.openfunction.io/v1beta1","kind":"Function","metadata":{"annotations":{},"name":"function-sample","namespace":"default"},"spec":{"build":{"builder":"openfunction/builder-go:latest","env":{"FUNC_CLEAR_SOURCE":"true","FUNC_NAME":"HelloWorld"},"srcRepo":{"credentials":{"name":"git-repo-secret"},"revision":"main","sourceSubPath":"functions/knative/hello-world-go","url":"https://forgejo.freshbrewed.science/isaac/openfuncsamples.git"}},"image":"freshbrewedprivate/sample-go-func:v1","imageCredentials":{"name":"push-secret"},"serving":{"runtime":"knative","template":{"containers":[{"imagePullPolicy":"IfNotPresent","name":"function"}]}},"version":"v2.0.0"}}
creationTimestamp: "2023-12-08T23:14:13Z"
generation: 2
name: function-sample
namespace: default
resourceVersion: "4509924"
uid: ffe35158-3045-4f31-9276-b62528c1a868
spec:
build:
builder: openfunction/builder-go:latest
env:
FUNC_CLEAR_SOURCE: "true"
FUNC_NAME: HelloWorld
srcRepo:
credentials:
name: git-repo-secret
revision: main
sourceSubPath: functions/knative/hello-world-go
url: https://forgejo.freshbrewed.science/isaac/openfuncsamples.git
image: harbor.freshbrewed.science/freshbrewedprivate/sample-go-func:v1
imageCredentials:
name: push-secret
serving:
template:
containers:
- imagePullPolicy: IfNotPresent
name: function
resources: {}
triggers:
http:
port: 8080
route:
gatewayRef:
name: openfunction
namespace: openfunction
version: v2.0.0
workloadRuntime: OCIContainer
status:
addresses:
- type: External
value: http://function-sample.default.ofn.io/
- type: Internal
value: http://function-sample.default.svc.cluster.local/
build:
buildDuration: 3m57s
message: Succeeded
reason: Succeeded
resourceHash: "14463020583153908224"
resourceRef: builder-9cgms
state: Succeeded
revision:
imageDigest: sha256:0ff9c9013ae07a4aa18b036a05ac7f9b0e2e32ff792b1207b10f9abd3108dec3
route:
hosts:
- function-sample.default.ofn.io
- function-sample.default.svc.cluster.local
paths:
- type: PathPrefix
value: /
serving:
lastSuccessfulResourceRef: serving-vwczj
message: Running
reason: Running
resourceHash: "10343863681372965255"
resourceRef: serving-vwczj
service: serving-vwczj-ksvc-fmmls
state: Running
sources:
- git:
commitAuthor: Benjamin Huo
commitSha: 318ee2452fc1bb61a35b2c5016a8ab6fc29eef0c
name: default
The addresses might be hard to reach. We can test the internal but the external isn’t real
status:
addresses:
- type: External
value: http://function-sample.default.ofn.io/
- type: Internal
value: http://function-sample.default.svc.cluster.local/
I’ll try and connect
This cluster is a test cluster with Istio. Let’s respin with Traefik this time.
builder@LuiGi17:~/Workspaces/jekyll-blog/_posts$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
anna-macbookair Ready control-plane,master 10m v1.27.6+k3s1
builder-macbookpro2 Ready <none> 9m44s v1.27.6+k3s1
isaac-macbookpro Ready <none> 9m44s v1.27.6+k3s1
builder@LuiGi17:~/Workspaces/jekyll-blog/_posts$ kubectl get ingress --all-namespaces
No resources found
builder@LuiGi17:~/Workspaces/jekyll-blog/_posts$ kubectl get pods --all-namespaces | grep trae
kube-system helm-install-traefik-crd-pllrr 0/1 Completed 0 10m
kube-system helm-install-traefik-nm4lg 0/1 Completed 1 10m
kube-system svclb-traefik-12bb1adc-9hm8q 2/2 Running 0 10m
kube-system traefik-64f55bb67d-hq59x 1/1 Running 0 10m
kube-system svclb-traefik-12bb1adc-6mq2w 2/2 Running 0 10m
kube-system svclb-traefik-12bb1adc-5h87p 2/2 Running 0 10m
I’ll re-install OpenFunction with helm
$ helm install openfunction openfunction/openfunction -n openfunction --set revisionController.enable=true --create-namespace
W1212 22:00:37.091442 172573 warnings.go:70] The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1212 22:00:37.169330 172573 warnings.go:70] The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1212 22:01:12.932392 172573 warnings.go:70] The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1212 22:01:12.988751 172573 warnings.go:70] The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
NAME: openfunction
LAST DEPLOYED: Tue Dec 12 22:00:23 2023
NAMESPACE: openfunction
STATUS: deployed
REVISION: 1
TEST SUITE: None
I’ll add back the important pieces like the GIT credentials and Harbor cred
builder@LuiGi17:~/Workspaces/openFunction$ kubectl apply -f forgejoPass.yaml
secret/git-repo-secret created
$ kubectl create secret docker-registry push-secret --docker-server=harbor.freshbre
wed.science --docker-username=forgejo --docker-password=NotTheRealPassword\!
Now I can try again
builder@LuiGi17:~/Workspaces/openFunction$ cat mySample.yaml
apiVersion: core.openfunction.io/v1beta1
kind: Function
metadata:
name: function-sample
spec:
version: "v2.0.0"
image: "harbor.freshbrewed.science/freshbrewedprivate/sample-go-func:v2"
imageCredentials:
name: push-secret
build:
builder: openfunction/builder-go:latest
env:
FUNC_NAME: "HelloWorld"
FUNC_CLEAR_SOURCE: "true"
srcRepo:
url: "https://forgejo.freshbrewed.science/isaac/openfuncsamples.git"
sourceSubPath: "functions/knative/hello-world-go"
revision: "main"
credentials:
name: git-repo-secret
serving:
template:
containers:
- name: function # DO NOT change this
imagePullPolicy: IfNotPresent
runtime: "knative"
builder@LuiGi17:~/Workspaces/openFunction$ kubectl apply -f mySample.yaml
function.core.openfunction.io/function-sample created
It looks like I made some mistake in the auth
n$ kubectl get pod builder-p5zkx-buildrun-f7xbt-7562m-pod
NAME READY STATUS RESTARTS AGE
builder-p5zkx-buildrun-f7xbt-7562m-pod 0/4 Error 0 2m29s
$ kubectl logs builder-p5zkx-buildrun-f7xbt-7562m-pod
Defaulted container "step-source-default" out of: step-source-default, step-prepare, step-create, step-results, prepare (init)
2023/12/14 01:43:48 Info: ssh (/usr/bin/ssh): OpenSSH_8.0p1, OpenSSL 1.1.1k FIPS 25 Mar 2021
2023/12/14 01:43:48 Info: git (/usr/bin/git): git version 2.31.1
2023/12/14 01:43:48 Info: git-lfs (/usr/bin/git-lfs): git-lfs/2.13.3 (GitHub; linux amd64; go 1.17.5)
2023/12/14 01:43:48 /usr/bin/git clone -h
2023/12/14 01:43:48 /usr/bin/git submodule -h
2023/12/14 01:43:48 /usr/bin/git clone --quiet --no-tags --single-branch --branch main --depth 1 -c credential.helper=store --file /tmp/cred-helper-file2155860431 -- https://forgejo.freshbrewed.science/isaac/openfuncsamples.git /workspace/source
2023/12/14 01:43:49 remote: Verify
fatal: Authentication failed for 'https://forgejo.freshbrewed.science/isaac/openfuncsamples.git/' (exit code 128)
I escaped the password unneccesarily. I fixed the password and tried again
We can see it build and complete
Now this is pretty interesting. I had just refreshed the cluster. There shouldn’t be too much there…
$ kubectl get svc --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 22h
kube-system kube-dns ClusterIP 10.43.0.10 <none> 53/UDP,53/TCP,9153/TCP 22h
kube-system metrics-server ClusterIP 10.43.139.244 <none> 443/TCP 22h
kube-system traefik LoadBalancer 10.43.24.35 192.168.1.13,192.168.1.159,192.168.1.206 80:32382/TCP,443:30693/TCP 22h
dapr-system dapr-placement-server ClusterIP None <none> 50005/TCP,8201/TCP 21h
dapr-system dapr-sidecar-injector ClusterIP 10.43.134.173 <none> 443/TCP 21h
openfunction openfunction-webhook-service ClusterIP 10.43.174.53 <none> 443/TCP 21h
knative-serving default-domain-service ClusterIP 10.43.198.127 <none> 80/TCP 21h
knative-serving controller ClusterIP 10.43.3.33 <none> 9090/TCP,8008/TCP 21h
projectcontour contour ClusterIP 10.43.60.211 <none> 8001/TCP 21h
knative-serving domainmapping-webhook ClusterIP 10.43.133.233 <none> 9090/TCP,8008/TCP,443/TCP 21h
dapr-system dapr-webhook ClusterIP 10.43.70.213 <none> 443/TCP 21h
keda keda-operator ClusterIP 10.43.97.170 <none>
9666/TCP 21h
keda keda-operator-metrics-apiserver ClusterIP 10.43.79.81 <none>
443/TCP,8080/TCP 21h
tekton-pipelines tekton-pipelines-controller ClusterIP 10.43.135.228 <none>
9090/TCP,8008/TCP,8080/TCP 21h
knative-serving webhook ClusterIP 10.43.175.149 <none>
9090/TCP,8008/TCP,443/TCP 21h
dapr-system dapr-sentry ClusterIP 10.43.240.216 <none>
80/TCP 21h
dapr-system dapr-api ClusterIP 10.43.44.206 <none>
80/TCP 21h
knative-serving activator-service ClusterIP 10.43.139.192 <none>
9090/TCP,8008/TCP,80/TCP,81/TCP 21h
openfunction openfunction-controller-manager-metrics-service ClusterIP 10.43.126.72 <none>
8443/TCP 21h
tekton-pipelines tekton-pipelines-webhook ClusterIP 10.43.234.237 <none>
9090/TCP,8008/TCP,443/TCP,8080/TCP 21h
projectcontour contour-envoy LoadBalancer 10.43.135.195 <pending>
80:32112/TCP,443:32502/TCP 21h
knative-serving autoscaler ClusterIP 10.43.7.56 <none>
9090/TCP,8008/TCP,8080/TCP 21h
keda keda-admission-webhooks ClusterIP 10.43.32.15 <none>
443/TCP 21h
knative-serving autoscaler-bucket-00-of-01 ClusterIP 10.43.146.196 <none>
8080/TCP 21h
openfunction gateway ExternalName <none> contour-envoy.projectcontour.svc.cluster.local 80/TCP 21h
default serving-t54c9-ksvc-c5xfm-v200-private ClusterIP 10.43.249.252 <none>
80/TCP,9090/TCP,9091/TCP,8022/TCP,8012/TCP 5m9s
default serving-t54c9-ksvc-c5xfm-v200 ClusterIP 10.43.90.246 <none>
80/TCP 5m9s
default serving-t54c9-ksvc-c5xfm ClusterIP None <none>
80/TCP 5m1s
default function-sample ExternalName <none> gateway.openfunction.svc.cluster.local
I’m not sure if that is quite viewable as a text table, but the number of services seemed a lot
So then let’s find the service URLs, which should be the same
$ kubectl get function function-sample -o json | jq .status.route.hosts[]
"function-sample.default.ofn.io"
"function-sample.default.svc.cluster.local"
I fired up a shell and tried again, but luck
root@my-shell:/# wget http://function-sample.default.svc.cluster.local
--2023-12-14 02:04:07-- http://function-sample.default.svc.cluster.local/
Resolving function-sample.default.svc.cluster.local (function-sample.default.svc.cluster.local)... 10.43.135.195
Connecting to function-sample.default.svc.cluster.local (function-sample.default.svc.cluster.local)|10.43.135.195|:80... failed: Connection refused.
root@my-shell:/# wget http://function-sample.default.svc.cluster.local
--2023-12-14 02:04:11-- http://function-sample.default.svc.cluster.local/
Resolving function-sample.default.svc.cluster.local (function-sample.default.svc.cluster.local)... 10.43.135.195
Connecting to function-sample.default.svc.cluster.local (function-sample.default.svc.cluster.local)|10.43.135.195|:80... failed: Connection refused.
root@my-shell:/# curl -O http://function-sample.default.svc.cluster.local
curl: Remote file name has no length!
curl: (23) Failed writing received data to disk/application
root@my-shell:/# curl -O http://function-sample.default.svc.cluster.local
curl: Remote file name has no length!
curl: (23) Failed writing received data to disk/application
Let me try a different sample.
I’ll need to install the pack
CLI which comes from BuildPacks
$ brew install buildpacks/tap/pack
I can now build the buildpack
$ pack build func-helloworld-go --builder openfunction/builder-go:v2.4.0-1.17 --env FUNC_NAME="HelloWorld" --env FUNC_CLEAR_SOURCE=true
v2.4.0-1.17: Pulling from openfunction/builder-go
47d17572643b: Pull complete
b69d4a399026: Pull complete
3c2cba919283: Pull complete
1632a81579ce: Pull complete
4cd5b698a987: Pull complete
d4f838d4cf95: Pull complete
6ef24a7a5aea: Pull complete
7ed6c3b6bba9: Pull complete
357fefdf9bc9: Pull complete
733c34a8a537: Pull complete
093b93186394: Pull complete
fd77c1508b78: Pull complete
1bf97eb692a3: Pull complete
aa95a14c5d42: Pull complete
09dd98da6b83: Pull complete
7938e8415fc0: Pull complete
3ba32ee46a69: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:a9b4c1df1b35cde0ca88e92f0b2376d372bfb9fbaac9bfce785c2ee5d429066c
Status: Downloaded newer image for openfunction/builder-go:v2.4.0-1.17
v2.4.0-1.17: Pulling from openfunctiondev/buildpacks-run-go
aa49f28a0db9: Pull complete
3d89ead22a45: Pull complete
Digest: sha256:726b67ac4b9cf220f9cf64f7ea9f42a5c06659b3dee96297ee8266aba32a6361
Status: Downloaded newer image for openfunctiondev/buildpacks-run-go:v2.4.0-1.17
0.13.2: Pulling from buildpacksio/lifecycle
e8614d09b7be: Pull complete
ee78fc634fdc: Pull complete
Digest: sha256:b7f2b9f44525ed0e962bdf5be186a266e36adc502b3dc0595dd2aac7f2b92e75
Status: Downloaded newer image for buildpacksio/lifecycle:0.13.2
===> ANALYZING
[analyzer] Previous image with name "func-helloworld-go" not found
===> DETECTING
If you aren’t in a sample repo, this will crash out with an error about no buildpacks:
[detector] ERROR: No buildpack groups passed detection.
[detector] ERROR: Please check that you are running against the correct path.
[detector] ERROR: failed to detect: no buildpacks participating
ERROR: failed to build: executing lifecycle: failed with status code: 20
But if we are in a samples repo
builder@LuiGi17:~/Workspaces$ git clone https://github.com/OpenFunction/samples.git
Cloning into 'samples'...
remote: Enumerating objects: 2411, done.
remote: Counting objects: 100% (852/852), done.
remote: Compressing objects: 100% (324/324), done.
remote: Total 2411 (delta 622), reused 609 (delta 521), pack-reused 1559
Receiving objects: 100% (2411/2411), 4.66 MiB | 1.41 MiB/s, done.
Resolving deltas: 100% (1179/1179), done.
builder@LuiGi17:~/Workspaces$ cd samples/
builder@LuiGi17:~/Workspaces/samples$ cd functions/knative/hello-world-go/
Then it works
builder@LuiGi17:~/Workspaces/samples/functions/knative/hello-world-go$ pack build func-helloworld-go --builder openfunction/builder-go:v2.4.0-1.17 --env FUNC_NAME="HelloWorld" --env FUNC_CLEAR_SOURCE=true
v2.4.0-1.17: Pulling from openfunction/builder-go
Digest: sha256:a9b4c1df1b35cde0ca88e92f0b2376d372bfb9fbaac9bfce785c2ee5d429066c
Status: Image is up to date for openfunction/builder-go:v2.4.0-1.17
v2.4.0-1.17: Pulling from openfunctiondev/buildpacks-run-go
Digest: sha256:726b67ac4b9cf220f9cf64f7ea9f42a5c06659b3dee96297ee8266aba32a6361
Status: Image is up to date for openfunctiondev/buildpacks-run-go:v2.4.0-1.17
0.13.2: Pulling from buildpacksio/lifecycle
Digest: sha256:b7f2b9f44525ed0e962bdf5be186a266e36adc502b3dc0595dd2aac7f2b92e75
Status: Image is up to date for buildpacksio/lifecycle:0.13.2
===> ANALYZING
[analyzer] Previous image with name "func-helloworld-go" not found
===> DETECTING
[detector] 4 of 5 buildpacks participating
[detector] openfunction.go.of-functions-framework 0.6.0
[detector] google.go.build 0.9.0
[detector] google.go.clear_source 0.9.0
[detector] google.utils.label 0.0.1
===> RESTORING
===> BUILDING
[builder] === Go - OpenFunction Functions Framework (openfunction.go.of-functions-framework@0.6.0) ===
[builder] --------------------------------------------------------------------------------
[builder] Running "go run /cnb/buildpacks/openfunction.go.of-functions-framework/0.6.0/converter/get_package/main.go -dir /workspace/serverless_function_source_code (GOCACHE=/tmp/serverless_function_app3505450428)"
[builder] {"name":"hello","imports":{"fmt":{},"github.com/OpenFunction/functions-framework-go/context":{},"github.com/OpenFunction/functions-framework-go/functions":{},"net/http":{}}}Done "go run /cnb/buildpacks/openfunction.go.of-functions-framewor..." (514.152005ms)
[builder] Found framework version v0.5.0
[builder] === Go - Build (google.go.build@0.9.0) ===
[builder] --------------------------------------------------------------------------------
[builder] Running "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..."
[builder] /workspace
[builder] Done "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..." (769.651385ms)
[builder] --------------------------------------------------------------------------------
[builder] Running "go build -o /layers/google.go.build/bin/main ./. (GOCACHE=/layers/google.go.build/gocache CGO_ENABLED=0)"
[builder] Done "go build -o /layers/google.go.build/bin/main ./. (GOCACHE=/l..." (9.662469444s)
[builder] === Go - Clear Source (google.go.clear_source@0.9.0) ===
[builder] Clearing source
[builder] === Utils - Label Image (google.utils.label@0.0.1) ===
[builder] function package: {"name":"hello","imports":{"fmt":{},"github.com/OpenFunction/functions-framework-go/context":{},"github.com/OpenFunction/functions-framework-go/functions":{},"net/http":{}}}
===> EXPORTING
[exporter] Adding layer 'google.go.build:bin'
[exporter] Adding 1/1 app layer(s)
[exporter] Adding layer 'launcher'
[exporter] Adding layer 'config'
[exporter] Adding layer 'process-types'
[exporter] Adding label 'io.buildpacks.lifecycle.metadata'
[exporter] Adding label 'io.buildpacks.build.metadata'
[exporter] Adding label 'io.buildpacks.project.metadata'
[exporter] Setting default process type 'web'
[exporter] Saving func-helloworld-go...
[exporter] *** Images (80a32bf5a475):
[exporter] func-helloworld-go
[exporter] Adding cache layer 'openfunction.go.of-functions-framework:functions-framework'
Successfully built image func-helloworld-go
Now let’s push that to our Private CR
builder@LuiGi17:~/Workspaces/samples/functions/knative/hello-world-go$ docker tag func-helloworld-go:latest harbor.freshbrewed.science/freshbrewedprivate/sample-go-func:v3
builder@LuiGi17:~/Workspaces/samples/functions/knative/hello-world-go$ docker push harbor.freshbrewed.science/freshbrewedprivate/sample-go-func:v3
The push refers to repository [harbor.freshbrewed.science/freshbrewedprivate/sample-go-func]
83d85471d9f8: Pushed
a86763bbd83f: Pushed
957a2c8ae307: Pushed
5506412630d7: Pushed
2c7256d0680c: Pushed
db1c3f3a541e: Layer already exists
30ffe6ef068e: Layer already exists
v3: digest: sha256:d815ce56bf22f61460288c3edb08b2f180a2d2c5df555af948ca8a15f009fee3 size: 1777
Since we built and pushed it ourselves, we can run the sample without the build block
builder@LuiGi17:~/Workspaces/samples/functions/knative/hello-world-go$ cat runTest.yaml
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
name: function-sample
spec:
image: "harbor.freshbrewed.science/freshbrewedprivate/sample-go-func:v3"
version: "v3.0.0"
imageCredentials:
name: push-secret
serving:
template:
containers:
- name: function # DO NOT change this
imagePullPolicy: IfNotPresent
triggers:
http:
port: 8080
builder@LuiGi17:~/Workspaces/samples/functions/knative/hello-world-go$ kubectl apply -f runTest.yaml
function.core.openfunction.io/function-sample created
with the service back it still doesnt work
root@my-shell:/# curl http://function-sample.default.svc.cluster.local/OpenFunction
curl: (7) Failed to connect to function-sample.default.svc.cluster.local port 80 after 10 ms: Connection refused
root@my-shell:/# curl http://function-sample.default.svc.cluster.local/OpenFunction
curl: (7) Failed to connect to function-sample.default.svc.cluster.local port 80 after 9 ms: Connection refused
root@my-shell:/# curl http://function-sample.default.svc.cluster.local/
curl: (7) Failed to connect to function-sample.default.svc.cluster.local port 80 after 10 ms: Connection refused
I ran a few options without success.
However, at the very least I can run with docker
$ docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name func-helloworld-go -p 8080:8080 func-helloworld-go
I1214 02:44:55.836924 1 framework.go:214] Plugins for pre-hook stage:
I1214 02:44:55.836975 1 framework.go:222] Plugins for post-hook stage:
I1214 02:44:55.836983 1 framework.go:144] no 'FUNCTION_TARGET' is provided, register all the functions in the registry
I1214 02:44:55.836988 1 framework.go:147] registering function: HelloWorld on path: /{greeting}
I1214 02:44:55.837019 1 knative.go:48] Knative Function serving http: listening on port 8080
builder@LuiGi17:~$ wget http://localhost:8080/OpenFunction
--2023-12-13 20:45:38-- http://localhost:8080/OpenFunction
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 21 [text/plain]
Saving to: ‘OpenFunction’
OpenFunction 100%[======================================================================>] 21 --.-KB/s in 0s
2023-12-13 20:45:38 (2.78 MB/s) - ‘OpenFunction’ saved [21/21]
builder@LuiGi17:~$ cat OpenFunction
Hello, OpenFunction!
AKS
Let’s pivot and use a full Kubernetes stack in Azure. Perhaps some of these troubles come from using a very new on-prem K3s without a fully integrated external load balancer.
I’ll create a Resource Group, SP and set aside it’s creds
isaac [ ~ ]$ az group create --name openfunrg --location centralus
{
"id": "/subscriptions/738dcfa0-0af6-4806-ab1d-a3dd7b0823e1/resourceGroups/openfunrg",
"location": "centralus",
"managedBy": null,
"name": "openfunrg",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}
isaac [ ~ ]$ az ad sp create-for-rbac -n idjaksupg01sp --skip-assignment --output json > my_sp.json
WARNING: Option '--skip-assignment' has been deprecated and will be removed in a future release.
WARNING: Found an existing application instance: (id) 34fede26-2ae7-4ccd-9c29-3bc220b9784a. We will patch it.
WARNING: The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
isaac [ ~ ]$ export SP_PASS=`cat my_sp.json | jq -r .password`
isaac [ ~ ]$ export SP_ID=`cat my_sp.json | jq -r .appId`
Next I’ll create a Cluster using those creds
isaac [ ~ ]$ az aks create --resource-group openfunrg --name idjaksopenfun --location centralus --node-count 3 --enable-cluster-autoscaler --min-count 2 --max-count 4 --generate-ssh-keys --network-plugin azure --network-policy azure --service-principal $SP_ID --client-secret $SP_PASS
SSH key files '/home/isaac/.ssh/id_rsa' and '/home/isaac/.ssh/id_rsa.pub' have been generated under ~/.ssh to allow SSH access to the VM. If using machines without permanent storage like Azure Cloud Shell without an attached file share, back up your keys to a safe location
docker_bridge_cidr is not a known attribute of class <class 'azure.mgmt.containerservice.v2023_10_01.models._models_py3.ContainerServiceNetworkProfile'> and will be ignored
/ Running ..
I can now log in and see some nodes are up and ready to serve traffic
isaac [ ~ ]$ az aks get-credentials -n idjaksopenfun -g openfunrg --admin
Merged "idjaksopenfun-admin" as current context in /home/isaac/.kube/config
isaac [ ~ ]$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-nodepool1-31922335-vmss000000 Ready agent 4m4s v1.27.7
aks-nodepool1-31922335-vmss000001 Ready agent 4m4s v1.27.7
aks-nodepool1-31922335-vmss000002 Ready agent 4m4s v1.27.7
Since I’m using an Azure Cloud Shell, I’ll need to add the Helm repo and update before installing
isaac [ ~ ]$ helm repo add openfunction https://openfunction.github.io/charts/
"openfunction" has been added to your repositories
isaac [ ~ ]$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "openfunction" chart repository
Update Complete. ⎈Happy Helming!⎈
I can now install OpenFunction into the cluster with Helm
isaac [ ~ ]$ helm install openfunction openfunction/openfunction -n openfunction --set revisionController.enable=true --create-namespace
W1214 12:41:35.769178 2418 warnings.go:70] The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1214 12:41:36.043967 2418 warnings.go:70] The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1214 12:41:59.655475 2418 warnings.go:70] The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
W1214 12:41:59.690314 2418 warnings.go:70] The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1.
NAME: openfunction
LAST DEPLOYED: Thu Dec 14 12:41:10 2023
NAMESPACE: openfunction
STATUS: deployed
REVISION: 1
TEST SUITE: None
and I can see all that was created
I’ll pivot a bit this time and use DockerHub over my private CR
isaac [ ~ ]$ REGISTRY_SERVER=https://index.docker.io/v1/ REGISTRY_USER=idjohnson REGISTRY_PASSWORD=asdfasdf-asdfsadf-asdfasdf-asdfasdf
isaac [ ~ ]$ kubectl create secret docker-registry push-secret \
--docker-server=$REGISTRY_SERVER \
--docker-username=$REGISTRY_USER \
--docker-password=$REGISTRY_PASSWORD
secret/push-secret created
And creds for my private Git repo
isaac [ ~ ]$ cat forgejoPassword.yaml
apiVersion: v1
kind: Secret
metadata:
name: git-repo-secret
annotations:
build.shipwright.io/referenced.secret: "true"
type: kubernetes.io/basic-auth
stringData:
username: isaac
password: NotMyPasswordHereEither
isaac [ ~ ]$ kubectl apply -f forgejoPassword.yaml
secret/git-repo-secret created
I’ll clone the repo down then just change the image to use my Dockerhub path on the image:
line
isaac [ ~/samples/functions/knative/hello-world-go ]$ vi function-sample.yaml
isaac [ ~/samples/functions/knative/hello-world-go ]$ cat function-sample.yaml
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
name: function-sample
spec:
version: "v2.0.0"
image: "idjohnson/sample-go-func:v7"
imageCredentials:
name: push-secret
build:
builder: openfunction/builder-go:latest
env:
FUNC_NAME: "HelloWorld"
FUNC_CLEAR_SOURCE: "true"
# # Use FUNC_GOPROXY to set the goproxy if failed to fetch go modules
# FUNC_GOPROXY: "https://goproxy.cn"
srcRepo:
url: "https://github.com/OpenFunction/samples.git"
sourceSubPath: "functions/knative/hello-world-go"
revision: "main"
serving:
template:
containers:
- name: function # DO NOT change this
imagePullPolicy: IfNotPresent
triggers:
http:
port: 8080
I’ll apply the sample file:
I can now see services running
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
function-sample ExternalName <none> gateway.openfunction.svc.cluster.local 80/TCP 91s
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 35m
serving-qrnvd-ksvc-ppznb ClusterIP None <none> 80/TCP 92s
serving-qrnvd-ksvc-ppznb-v200 ClusterIP 10.0.163.249 <none> 80/TCP 99s
serving-qrnvd-ksvc-ppznb-v200-private ClusterIP 10.0.220.122 <none> 80/TCP,9090/TCP,9091/TCP,8022/TCP,8012/TCP 99s
Much as before, I see the same URLs exposed
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl get function
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING ADDRESS AGE
function-sample Succeeded Running builder-v7v8v serving-qrnvd http://function-sample.default.svc.cluster.local/ 6m13s
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl get function -o json | jq .status.route.hosts[]
jq: error (at <stdin>:119): Cannot iterate over null (null)
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl get function function-sample -o json | jq .status.route.hosts[]
"function-sample.default.ofn.io"
"function-sample.default.svc.cluster.local"
I can’t really expose the function directly
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl expose service function-sample --port=8000 --target-port=80 --name=func-sample-80
error: couldn't retrieve selectors via --selector flag or introspection: the service has no pod selector set
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl expose service gateway -n openfunction --port=8000 --target-port=80 --name=gateway-80
error: couldn't retrieve selectors via --selector flag or introspection: the service has no pod selector set
I’ll fire up an ephemeral shell
isaac [ ~/samples/functions/knative/hello-world-go ]$ kubectl run my-shell --rm -i --tty --image ubuntu -- bash
If you don't see a command prompt, try pressing enter.
root@my-shell:/#
Then install curl and wget and try the internal url
root@my-shell:/# apt update && apt install -y wget curl
Get:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
Get:3 http://security.ubuntu.com/ubuntu jammy-security/multiverse amd64 Packages [44.0 kB]
Get:4 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [1572 kB]
Get:5 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1036 kB]
Get:6 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [1325 kB]
Get:7 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
Get:8 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [109 kB]
Get:9 http://archive.ubuntu.com/ubuntu jammy/restricted amd64 Packages [164 kB]
Get:10 http://archive.ubuntu.com/ubuntu jammy/multiverse amd64 Packages [266 kB]
Get:11 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages [1792 kB]
Get:12 http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages [17.5 MB]
Get:13 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1304 kB]
Get:14 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [1602 kB]
Get:15 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [1598 kB]
Get:16 http://archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 Packages [49.8 kB]
Get:17 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [28.1 kB]
Get:18 http://archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [50.4 kB]
Fetched 28.9 MB in 3s (8716 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
3 packages can be upgraded. Run 'apt list --upgradable' to see them.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
ca-certificates libbrotli1 libcurl4 libldap-2.5-0 libldap-common libnghttp2-14 libpsl5 librtmp1 libsasl2-2 libsasl2-modules libsasl2-modules-db libssh-4 openssl publicsuffix
Suggested packages:
libsasl2-modules-gssapi-mit | libsasl2-modules-gssapi-heimdal libsasl2-modules-ldap libsasl2-modules-otp libsasl2-modules-sql
The following NEW packages will be installed:
ca-certificates curl libbrotli1 libcurl4 libldap-2.5-0 libldap-common libnghttp2-14 libpsl5 librtmp1 libsasl2-2 libsasl2-modules libsasl2-modules-db libssh-4 openssl publicsuffix wget
0 upgraded, 16 newly installed, 0 to remove and 3 not upgraded.
Need to get 3353 kB of archives.
After this operation, 8132 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 openssl amd64 3.0.2-0ubuntu1.12 [1182 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 ca-certificates all 20230311ubuntu0.22.04.1 [155 kB]
...
Setting up ca-certificates (20230311ubuntu0.22.04.1) ...
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 78.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.34.0 /usr/local/share/perl/5.34.0 /usr/lib/x86_64-linux-gnu/perl5/5.34 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.34 /usr/share/perl/5.34 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)
debconf: falling back to frontend: Teletype
Updating certificates in /etc/ssl/certs...
137 added, 0 removed; done.
Setting up libcurl4:amd64 (7.81.0-1ubuntu1.15) ...
Setting up curl (7.81.0-1ubuntu1.15) ...
Processing triggers for libc-bin (2.35-0ubuntu3.4) ...
Processing triggers for ca-certificates (20230311ubuntu0.22.04.1) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
root@my-shell:/#
This time the curl works
root@my-shell:/# curl http://function-sample.default.svc.cluster.local/OpenFunction
Hello, OpenFunction!
So at least in the cluster works
Before we wrap AKS, to save costs, I’ll remove the AKS cluster and Resource Group
isaac [ ~/samples/functions/knative/hello-world-go ]$ az aks delete -n idjaksopenfun -g openfunrg
Are you sure you want to perform this operation? (y/n): y
| Running ..
isaac [ ~/samples/functions/knative/hello-world-go ]$ az group delete -n openfunrg
Are you sure you want to perform this operation? (y/n): y
/ Running ..
Images
Let’s take a moment to check the images that were built.
We can see these are actually quite small, just a few Mb. Running a quick scan only found 11 issues, none critical
Summary
OpenFunction is a fascinating product. It claims to do a lot of things, but we barely scratched the surface of its capabilities. As you can see from the architecture diagram, it relies on a bunch of other open source systems and frameworks to work.
I find it a bit overkill for my needs. I tried to set up a test cluster, but it failed miserably. It also spawned too many things for me to use it in my production cluster.
The function framework used for the images was decent and launching through docker seemed like a nice way to get started with python or go code. However, given the weight and hassle, I think I’ll stick with KNative or OpenFaaS.