├── .gitignore ├── 01-knative-serving.sh ├── README.md ├── apps ├── helloworld-go │ ├── .ko.yaml │ ├── README.md │ ├── go.mod │ ├── helloworld.go │ └── service.yaml └── helloworld-nodejs │ ├── .dockerignore │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── service.yaml ├── images ├── htop-pi.png └── ubuntu-server.png └── template.env /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | local/ -------------------------------------------------------------------------------- /01-knative-serving.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | serving_version=${serving_version:-latest} 6 | knative_net_contour_version=${knative_net_contour_version:-latest} 7 | set -u 8 | 9 | n=0 10 | until [ $n -ge 2 ]; do 11 | kubectl apply -f https://storage.googleapis.com/knative-nightly/serving/${serving_version}/serving-crds.yaml && break 12 | n=$[$n+1] 13 | sleep 5 14 | done 15 | kubectl wait --for=condition=Established --all crd 16 | 17 | n=0 18 | until [ $n -ge 2 ]; do 19 | kubectl apply -f https://storage.googleapis.com/knative-nightly/serving/latest/serving-core.yaml && break 20 | n=$[$n+1] 21 | sleep 5 22 | done 23 | kubectl wait pod --timeout=-1s --for=condition=Ready -n knative-serving -l '!job-name' 24 | 25 | n=0 26 | until [ $n -ge 2 ]; do 27 | kubectl apply -f https://storage.googleapis.com/knative-nightly/net-contour/${knative_net_contour_version}/contour.yaml && break 28 | n=$[$n+1] 29 | sleep 5 30 | done 31 | kubectl wait --for=condition=Established --all crd 32 | kubectl wait pod --timeout=-1s --for=condition=Ready -n contour-external -l '!job-name' 33 | kubectl wait pod --timeout=-1s --for=condition=Ready -n contour-internal -l '!job-name' 34 | 35 | n=0 36 | until [ $n -ge 2 ]; do 37 | kubectl apply -f https://storage.googleapis.com/knative-nightly/net-contour/${knative_net_contour_version}/net-contour.yaml && break 38 | n=$[$n+1] 39 | sleep 5 40 | done 41 | kubectl wait pod --timeout=-1s --for=condition=Ready -n knative-serving -l '!job-name' 42 | 43 | kubectl patch configmap/config-network \ 44 | --namespace knative-serving \ 45 | --type merge \ 46 | --patch '{"data":{"ingress.class":"contour.ingress.networking.knative.dev"}}' 47 | 48 | EXTERNAL_IP="$(kubectl get svc envoy -n contour-external -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')" 49 | echo EXTERNAL_IP==$EXTERNAL_IP 50 | 51 | KNATIVE_DOMAIN="$EXTERNAL_IP.nip.io" 52 | echo KNATIVE_DOMAIN=$KNATIVE_DOMAIN 53 | 54 | kubectl patch configmap -n knative-serving config-domain -p "{\"data\": {\"$KNATIVE_DOMAIN\": \"\"}}" 55 | 56 | 57 | cat <${BOOT_DRIVE}/network-config 62 | version: 2 63 | ethernets: 64 | eth0: 65 | match: 66 | driver: bcmgenet smsc95xx lan78xx 67 | set-name: eth0 68 | dhcp4: true 69 | optional: true 70 | wifis: 71 | wlan0: 72 | dhcp4: true 73 | optional: true 74 | access-points: 75 | ${WIFI_SSID}: 76 | password: "${WIFI_PASSWORD}" 77 | EOF 78 | ``` 79 | 80 | ### Boot up 81 | 82 | Umount/Eject SD Card from your computer, insert into raspberry pi and power on the raspberry pi. 83 | 84 | You can discover the IP via your router, or plug a monitor and keyboard and use the command `ip a` to get the ip address. 85 | 86 | You can also use a network scan 87 | ```sh 88 | nmap -sn 192.168.7.0/24 89 | ``` 90 | 91 | This would be something like `192.168.x.x` in my case is `192.168.7.101` 92 | 93 | Update the file `.env` 94 | ``` 95 | IP=192.168.7.101 96 | echo IP=$IP >>.env 97 | ``` 98 | 99 | ### Setup ssh 100 | 101 | Login and change the default password `ubuntu` to something different 102 | ```bash 103 | source .env 104 | ssh ubuntu@$IP 105 | ``` 106 | 107 | Check if you have a local ssh, if not then create a new one with `ssh-keygen` 108 | ```bash 109 | ls ~/.ssh/id_rsa* 110 | ``` 111 | 112 | If you have more than one ssh key you can use `-i` to be sure it picks the correct one. 113 | ```bash 114 | source .env 115 | ssh-copy-id -i $HOME/.ssh/id_rsa ubuntu@$IP 116 | ``` 117 | 118 | Now you can ssh into the pi without a password 119 | ```bash 120 | source .env 121 | ssh ubuntu@$IP uname -m 122 | ``` 123 | It should print `aarch64` to indicate arm64 124 | 125 | I recommend to change the hostname of the pi from the default `ubuntu` before you install kubernetes to something useful like `pi4` 126 | ```bash 127 | source .env 128 | NEW_HOSTNAME=pi4 129 | ssh ubuntu@$IP "sudo hostnamectl set-hostname ${NEW_HOSTNAME}; sudo sed -i.bak s/localhost/${NEW_HOSTNAME}/g /etc/hosts" 130 | ``` 131 | 132 | ## Install Kubernetes 133 | 134 | - Install the [k3sup](https://github.com/alexellis/k3sup#download-k3sup-tldr) command line tool, check that you have latest version I'm using `0.9.7` 135 | ```bash 136 | k3sup version 137 | ``` 138 | 139 | - Run the following command to install k3s on the pi as a master node. 140 | ```bash 141 | source .env 142 | k3sup install \ 143 | --ip $IP \ 144 | --user ubuntu \ 145 | --merge \ 146 | --local-path $HOME/.kube/config \ 147 | --context knative-pi \ 148 | --k3s-channel latest \ 149 | --k3s-extra-args '--disable=traefik' 150 | ``` 151 | 152 | - The `--ip` specifies the IP Address to ssh in to the pi 153 | - The `--user` specifies the user to ssh as 154 | - The `--merge` specified to merge the kubeconfig of the new cluster into an existing kubeconfig file 155 | - The `--local-path` specifies which file to write the kubeconfig file, in our case specify an existing one to merge in the new config 156 | - The `--context` specifies the context for the cluster when you use `kubectl` or `kn` 157 | - The `--k3s-channel` specifies which version of kubernetes to install 158 | - The `--k3s-extra-args` with `--disable=traefik` is to avoid the installation of `traefik` as we are going to use `knative` networking 159 | 160 | - If you ever need to recover the kubeconfig from the cluster you can use the flag `--skip-install1` 161 | ```bash 162 | source .env 163 | k3sup install \ 164 | --ip $IP \ 165 | --user ubuntu \ 166 | --merge \ 167 | --local-path $HOME/.kube/config \ 168 | --context knative-pi \ 169 | --skip-install 170 | ``` 171 | 172 | ## Add worker nodes 173 | 174 | - To add worker nodes use the `join` command, `$AGENT_IP` is the ip of the next raspberry ip, and `$IP` is the IP of the first pi acting as master node. 175 | 176 | - Update `.env` file with AGENT_IP 177 | ```bash 178 | AGENT_IP=192.168.7.103 179 | echo AGENT_IP=$AGENT_IP >>.env 180 | ``` 181 | 182 | ```bash 183 | source .env 184 | k3sup join \ 185 | --ip $AGENT_IP \ 186 | --server-ip $IP \ 187 | --user ubuntu \ 188 | --k3s-channel latest 189 | ``` 190 | 191 | - You con set a role for the worker node: 192 | ```bash 193 | NODE=pi-worker 194 | kubectl label node ${NODE} node-role.kubernetes.io/worker=true 195 | ``` 196 | 197 | ## Verify Kubernetes installed 198 | 199 | 1. switch your context using [kubectx](https://github.com/ahmetb/kubectx) 200 | ```bash 201 | kubectx knative-pi 202 | ``` 203 | 1. List the nodes 204 | ```bash 205 | kubectl get nodes -o wide 206 | ``` 207 | 3. The output should look like this 208 | ``` 209 | NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME 210 | ubuntu Ready master 54m v1.19.3+k3s2 192.168.7.218 Ubuntu 20.10 5.8.0-1006-raspi containerd://1.4.0-k3s1 211 | ``` 212 | 213 | ## Install Knative Serving 214 | 215 | TLDR; `./01-knative-serving.sh` 216 | 217 | I will be using the pre-release build and [install instructions](https://knative.dev/development/install/any-kubernetes-cluster/) 218 | 219 | 1. Install Knative Serving 220 | ```bash 221 | kubectl apply -f https://storage.googleapis.com/knative-nightly/serving/latest/serving-crds.yaml 222 | kubectl wait --for=condition=Established --all crd 223 | kubectl apply -f https://storage.googleapis.com/knative-nightly/serving/latest/serving-core.yaml 224 | kubectl wait pod --timeout=-1s --for=condition=Ready -n knative-serving -l '!job-name' 225 | ``` 226 | 1. Install Contour `1.10` that uses arm enable envoy with `1.16` 227 | ```bash 228 | kubectl apply -f https://storage.googleapis.com/knative-nightly/net-contour/latest/contour.yaml 229 | kubectl wait --for=condition=Established --all crd 230 | kubectl wait pod --timeout=-1s --for=condition=Ready -n contour-external -l '!job-name' 231 | kubectl wait pod --timeout=-1s --for=condition=Ready -n contour-internal -l '!job-name' 232 | ``` 233 | 1. Install the Knative Network Controller: 234 | ```bash 235 | kubectl apply --filename https://storage.googleapis.com/knative-nightly/net-contour/latest/net-contour.yaml 236 | kubectl wait pod --timeout=-1s --for=condition=Ready -n knative-serving -l '!job-name' 237 | ``` 238 | 1. To configure Knative Serving to use previous installed Network Controller by default: 239 | ```bash 240 | kubectl patch configmap/config-network \ 241 | --namespace knative-serving \ 242 | --type merge \ 243 | --patch '{"data":{"ingress.class":"contour.ingress.networking.knative.dev"}}' 244 | ``` 245 | 1. Set the environment variable `EXTERNAL_IP` to External IP Address of the Worker Node 246 | ```bash 247 | EXTERNAL_IP="$(kubectl get svc envoy -n contour-external -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')" 248 | echo EXTERNAL_IP==$EXTERNAL_IP 249 | ``` 250 | 1. Set the environment variable `KNATIVE_DOMAIN` as the DNS domain using `nip.io` 251 | ```bash 252 | KNATIVE_DOMAIN="$EXTERNAL_IP.nip.io" 253 | echo KNATIVE_DOMAIN=$KNATIVE_DOMAIN 254 | ``` 255 | Double check DNS is resolving 256 | ```bash 257 | dig $KNATIVE_DOMAIN 258 | ``` 259 | 1. Configure DNS for Knative Serving 260 | ```bash 261 | kubectl patch configmap -n knative-serving config-domain -p "{\"data\": {\"$KNATIVE_DOMAIN\": \"\"}}" 262 | ``` 263 | 1. Verify that Knative is Installed properly all pods should be in `Running` state and `contour-external` service configured. 264 | ```bash 265 | kubectl get pods -n knative-serving 266 | kubectl get pods,svc -n contour-external 267 | ``` 268 | 269 | ## Deploy Knative Application 270 | 271 | Deploy using Knative CLI [kn](https://github.com/knative/client): 272 | ```bash 273 | kn service create hello --port 8080 --image csantanapr/helloworld-go:latest 274 | ``` 275 | 276 | **Optional:** Deploy a Knative Service using a yaml manifest: 277 | ```bash 278 | cat < { 5 | console.log('Hello world received a request.'); 6 | 7 | const target = process.env.TARGET || 'World from Node.js'; 8 | res.send(`Hello ${target}!`); 9 | }); 10 | 11 | const port = process.env.PORT || 8080; 12 | app.listen(port, () => { 13 | console.log('Hello world listening on port', port); 14 | }); 15 | -------------------------------------------------------------------------------- /apps/helloworld-nodejs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "knative-serving-helloworld", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "~2.1.24", 13 | "negotiator": "0.6.2" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "body-parser": { 22 | "version": "1.19.0", 23 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/body-parser/-/body-parser-1.19.0.tgz", 24 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 25 | "requires": { 26 | "bytes": "3.1.0", 27 | "content-type": "~1.0.4", 28 | "debug": "2.6.9", 29 | "depd": "~1.1.2", 30 | "http-errors": "1.7.2", 31 | "iconv-lite": "0.4.24", 32 | "on-finished": "~2.3.0", 33 | "qs": "6.7.0", 34 | "raw-body": "2.4.0", 35 | "type-is": "~1.6.17" 36 | } 37 | }, 38 | "bytes": { 39 | "version": "3.1.0", 40 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/bytes/-/bytes-3.1.0.tgz", 41 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 42 | }, 43 | "content-disposition": { 44 | "version": "0.5.3", 45 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/content-disposition/-/content-disposition-0.5.3.tgz", 46 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 47 | "requires": { 48 | "safe-buffer": "5.1.2" 49 | } 50 | }, 51 | "content-type": { 52 | "version": "1.0.4", 53 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/content-type/-/content-type-1.0.4.tgz", 54 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 55 | }, 56 | "cookie": { 57 | "version": "0.4.0", 58 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/cookie/-/cookie-0.4.0.tgz", 59 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 60 | }, 61 | "cookie-signature": { 62 | "version": "1.0.6", 63 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/cookie-signature/-/cookie-signature-1.0.6.tgz", 64 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 65 | }, 66 | "debug": { 67 | "version": "2.6.9", 68 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/debug/-/debug-2.6.9.tgz", 69 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 70 | "requires": { 71 | "ms": "2.0.0" 72 | } 73 | }, 74 | "depd": { 75 | "version": "1.1.2", 76 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/depd/-/depd-1.1.2.tgz", 77 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 78 | }, 79 | "destroy": { 80 | "version": "1.0.4", 81 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/destroy/-/destroy-1.0.4.tgz", 82 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 83 | }, 84 | "ee-first": { 85 | "version": "1.1.1", 86 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/ee-first/-/ee-first-1.1.1.tgz", 87 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 88 | }, 89 | "encodeurl": { 90 | "version": "1.0.2", 91 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/encodeurl/-/encodeurl-1.0.2.tgz", 92 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 93 | }, 94 | "escape-html": { 95 | "version": "1.0.3", 96 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/escape-html/-/escape-html-1.0.3.tgz", 97 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 98 | }, 99 | "etag": { 100 | "version": "1.8.1", 101 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/etag/-/etag-1.8.1.tgz", 102 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 103 | }, 104 | "express": { 105 | "version": "4.17.1", 106 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/express/-/express-4.17.1.tgz", 107 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 108 | "requires": { 109 | "accepts": "~1.3.7", 110 | "array-flatten": "1.1.1", 111 | "body-parser": "1.19.0", 112 | "content-disposition": "0.5.3", 113 | "content-type": "~1.0.4", 114 | "cookie": "0.4.0", 115 | "cookie-signature": "1.0.6", 116 | "debug": "2.6.9", 117 | "depd": "~1.1.2", 118 | "encodeurl": "~1.0.2", 119 | "escape-html": "~1.0.3", 120 | "etag": "~1.8.1", 121 | "finalhandler": "~1.1.2", 122 | "fresh": "0.5.2", 123 | "merge-descriptors": "1.0.1", 124 | "methods": "~1.1.2", 125 | "on-finished": "~2.3.0", 126 | "parseurl": "~1.3.3", 127 | "path-to-regexp": "0.1.7", 128 | "proxy-addr": "~2.0.5", 129 | "qs": "6.7.0", 130 | "range-parser": "~1.2.1", 131 | "safe-buffer": "5.1.2", 132 | "send": "0.17.1", 133 | "serve-static": "1.14.1", 134 | "setprototypeof": "1.1.1", 135 | "statuses": "~1.5.0", 136 | "type-is": "~1.6.18", 137 | "utils-merge": "1.0.1", 138 | "vary": "~1.1.2" 139 | } 140 | }, 141 | "finalhandler": { 142 | "version": "1.1.2", 143 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/finalhandler/-/finalhandler-1.1.2.tgz", 144 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 145 | "requires": { 146 | "debug": "2.6.9", 147 | "encodeurl": "~1.0.2", 148 | "escape-html": "~1.0.3", 149 | "on-finished": "~2.3.0", 150 | "parseurl": "~1.3.3", 151 | "statuses": "~1.5.0", 152 | "unpipe": "~1.0.0" 153 | } 154 | }, 155 | "forwarded": { 156 | "version": "0.1.2", 157 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/forwarded/-/forwarded-0.1.2.tgz", 158 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 159 | }, 160 | "fresh": { 161 | "version": "0.5.2", 162 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/fresh/-/fresh-0.5.2.tgz", 163 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 164 | }, 165 | "http-errors": { 166 | "version": "1.7.2", 167 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/http-errors/-/http-errors-1.7.2.tgz", 168 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 169 | "requires": { 170 | "depd": "~1.1.2", 171 | "inherits": "2.0.3", 172 | "setprototypeof": "1.1.1", 173 | "statuses": ">= 1.5.0 < 2", 174 | "toidentifier": "1.0.0" 175 | } 176 | }, 177 | "iconv-lite": { 178 | "version": "0.4.24", 179 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/iconv-lite/-/iconv-lite-0.4.24.tgz", 180 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 181 | "requires": { 182 | "safer-buffer": ">= 2.1.2 < 3" 183 | } 184 | }, 185 | "inherits": { 186 | "version": "2.0.3", 187 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/inherits/-/inherits-2.0.3.tgz", 188 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 189 | }, 190 | "ipaddr.js": { 191 | "version": "1.9.1", 192 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 193 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 194 | }, 195 | "media-typer": { 196 | "version": "0.3.0", 197 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/media-typer/-/media-typer-0.3.0.tgz", 198 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 199 | }, 200 | "merge-descriptors": { 201 | "version": "1.0.1", 202 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 203 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 204 | }, 205 | "methods": { 206 | "version": "1.1.2", 207 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/methods/-/methods-1.1.2.tgz", 208 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 209 | }, 210 | "mime": { 211 | "version": "1.6.0", 212 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/mime/-/mime-1.6.0.tgz", 213 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 214 | }, 215 | "mime-db": { 216 | "version": "1.44.0", 217 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/mime-db/-/mime-db-1.44.0.tgz", 218 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 219 | }, 220 | "mime-types": { 221 | "version": "2.1.27", 222 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/mime-types/-/mime-types-2.1.27.tgz", 223 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 224 | "requires": { 225 | "mime-db": "1.44.0" 226 | } 227 | }, 228 | "ms": { 229 | "version": "2.0.0", 230 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/ms/-/ms-2.0.0.tgz", 231 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 232 | }, 233 | "negotiator": { 234 | "version": "0.6.2", 235 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/negotiator/-/negotiator-0.6.2.tgz", 236 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 237 | }, 238 | "on-finished": { 239 | "version": "2.3.0", 240 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/on-finished/-/on-finished-2.3.0.tgz", 241 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 242 | "requires": { 243 | "ee-first": "1.1.1" 244 | } 245 | }, 246 | "parseurl": { 247 | "version": "1.3.3", 248 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/parseurl/-/parseurl-1.3.3.tgz", 249 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 250 | }, 251 | "path-to-regexp": { 252 | "version": "0.1.7", 253 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 254 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 255 | }, 256 | "proxy-addr": { 257 | "version": "2.0.6", 258 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/proxy-addr/-/proxy-addr-2.0.6.tgz", 259 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", 260 | "requires": { 261 | "forwarded": "~0.1.2", 262 | "ipaddr.js": "1.9.1" 263 | } 264 | }, 265 | "qs": { 266 | "version": "6.7.0", 267 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/qs/-/qs-6.7.0.tgz", 268 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 269 | }, 270 | "range-parser": { 271 | "version": "1.2.1", 272 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/range-parser/-/range-parser-1.2.1.tgz", 273 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 274 | }, 275 | "raw-body": { 276 | "version": "2.4.0", 277 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/raw-body/-/raw-body-2.4.0.tgz", 278 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 279 | "requires": { 280 | "bytes": "3.1.0", 281 | "http-errors": "1.7.2", 282 | "iconv-lite": "0.4.24", 283 | "unpipe": "1.0.0" 284 | } 285 | }, 286 | "safe-buffer": { 287 | "version": "5.1.2", 288 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/safe-buffer/-/safe-buffer-5.1.2.tgz", 289 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 290 | }, 291 | "safer-buffer": { 292 | "version": "2.1.2", 293 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/safer-buffer/-/safer-buffer-2.1.2.tgz", 294 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 295 | }, 296 | "send": { 297 | "version": "0.17.1", 298 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/send/-/send-0.17.1.tgz", 299 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 300 | "requires": { 301 | "debug": "2.6.9", 302 | "depd": "~1.1.2", 303 | "destroy": "~1.0.4", 304 | "encodeurl": "~1.0.2", 305 | "escape-html": "~1.0.3", 306 | "etag": "~1.8.1", 307 | "fresh": "0.5.2", 308 | "http-errors": "~1.7.2", 309 | "mime": "1.6.0", 310 | "ms": "2.1.1", 311 | "on-finished": "~2.3.0", 312 | "range-parser": "~1.2.1", 313 | "statuses": "~1.5.0" 314 | }, 315 | "dependencies": { 316 | "ms": { 317 | "version": "2.1.1", 318 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/ms/-/ms-2.1.1.tgz", 319 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 320 | } 321 | } 322 | }, 323 | "serve-static": { 324 | "version": "1.14.1", 325 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/serve-static/-/serve-static-1.14.1.tgz", 326 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 327 | "requires": { 328 | "encodeurl": "~1.0.2", 329 | "escape-html": "~1.0.3", 330 | "parseurl": "~1.3.3", 331 | "send": "0.17.1" 332 | } 333 | }, 334 | "setprototypeof": { 335 | "version": "1.1.1", 336 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/setprototypeof/-/setprototypeof-1.1.1.tgz", 337 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 338 | }, 339 | "statuses": { 340 | "version": "1.5.0", 341 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/statuses/-/statuses-1.5.0.tgz", 342 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 343 | }, 344 | "toidentifier": { 345 | "version": "1.0.0", 346 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/toidentifier/-/toidentifier-1.0.0.tgz", 347 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 348 | }, 349 | "type-is": { 350 | "version": "1.6.18", 351 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/type-is/-/type-is-1.6.18.tgz", 352 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 353 | "requires": { 354 | "media-typer": "0.3.0", 355 | "mime-types": "~2.1.24" 356 | } 357 | }, 358 | "unpipe": { 359 | "version": "1.0.0", 360 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/unpipe/-/unpipe-1.0.0.tgz", 361 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 362 | }, 363 | "utils-merge": { 364 | "version": "1.0.1", 365 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/utils-merge/-/utils-merge-1.0.1.tgz", 366 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 367 | }, 368 | "vary": { 369 | "version": "1.1.2", 370 | "resolved": "https://nexus-tools.kp-coe-poc-cluster-0143c5dd31acd8e030a1d6e0ab1380e3-0000.us-east.containers.appdomain.cloud/repository/npm-all/vary/-/vary-1.1.2.tgz", 371 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 372 | } 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /apps/helloworld-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "knative-serving-helloworld", 3 | "version": "1.0.0", 4 | "description": "Simple hello world sample in Node", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "author": "", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "express": "^4.17.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apps/helloworld-nodejs/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: serving.knative.dev/v1 2 | kind: Service 3 | metadata: 4 | name: helloworld-nodejs 5 | namespace: default 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - image: docker.io/{username}/helloworld-nodejs 11 | env: 12 | - name: TARGET 13 | value: "Node.js Sample v1" 14 | -------------------------------------------------------------------------------- /images/htop-pi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csantanapr/knative-pi/b9d7bd5b64aa91b1d61013e2a1f9380af2dc7792/images/htop-pi.png -------------------------------------------------------------------------------- /images/ubuntu-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csantanapr/knative-pi/b9d7bd5b64aa91b1d61013e2a1f9380af2dc7792/images/ubuntu-server.png -------------------------------------------------------------------------------- /template.env: -------------------------------------------------------------------------------- 1 | BOOT_DRIVE=/Volumes/system-boot/ 2 | WIFI_SSID=SSID 3 | WIFI_PASSWORD=PASSWORD 4 | IP=IP 5 | AGENT_IP=AGENT_IP --------------------------------------------------------------------------------