Безсерверні обчислення на основі OpenWhisk, частина 4

Безсерверні обчислення на основі OpenWhisk, частина 4

Ця стаття закінчує цикл перекладних нотаток про OpenWhisk від автора Priti Desai. Сьогодні розглянемо процес розгортання OpenWhisk поверх Kubernetes із виправленими командами для працездатності із актуальними версіями додатків. Також буде описано процес запуску функцій OpenWhisk з використанням Knative та TektonCD у Kubernetes з використанням середовища виконання Nodejs.

Розгортаємо OpenWhisk на Kubernetes

За кілька днів я провела експеримент із розгортання OpenWhisk у Kubernetes для створення простого та швидкого полігону для відпрацювання завдань. А оскільки я новачок у Kubernetes — гадаю, що півтора дня було витрачено на успішне розгортання. У в цьому Репозиторії є дуже зрозумілими інструкціями для розгортання OpenWhisk в Kubernetes. Тут будуть інструкції для розгортання, зроблені для Mac (я також робитиму все на Linux, тому що віддаю перевагу Linux. - прим. перекладача).

  1. Встановлюємо пакетний менеджер asdfпісля чого автоматично виправляємо ~/.bash_profile або його аналог так:

$ brew install asdf
$ [ -s "/usr/local/opt/asdf/asdf.sh" ] && . /usr/local/opt/asdf/asdf.sh
$ source ~/.bash_profile

[На Linux цей крок не потрібний, хоча brew є. - прим. перекладача]

  1. Додаємо плагіни minikube и kubelet:

$ asdf plugin-add kubectl
$ asdf plugin-add minikube

[Знову ж таки пропускаємо цей крок на Linux. - прим. перекладача]

  1. Ставимо minikube та kubelet:

$ asdf install kubectl 1.9.0
$ asdf global kubectl 1.9.0
$ asdf install minikube 0.25.2
$ asdf global minikube 0.25.2

[ставляться конкретні версії, але я перевіряв все на останніх доступних версіях для Linux; підозрюю, що можна сміливо ставити останній. - прим. перекладача]

На Linux цей крок робиться приблизно так (все ставиться в ~/bin, який у мене прописаний у PATH, прим. перекладача):

$ curl -L0 minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && mv minikube ~/bin/
$ curl -L0 https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl ~/bin/

  1. Створюємо віртуальну машину minikube (має бути попередньо встановлений VirtualBox):

$ minikube start --cpus 2 --memory 4096 --kubernetes-version=v1.9.0 --extra-config=apiserver.Authorization.Mode=RBAC

[У мене все працює із командою minikube start , без параметрів та зі значеннями за замовчуванням. - прим. перекладача]

$ minikube start
  minikube v1.5.2 on Debian 8.11
  Automatically selected the 'virtualbox' driver
  Downloading VM boot image ...
    > minikube-v1.5.1.iso.sha256: 65 B / 65 B [--------------] 100.00% ? p/s 0s
    > minikube-v1.5.1.iso: 143.76 MiB / 143.76 MiB [-] 100.00% 5.63 MiB p/s 26s
  Creating virtualbox VM (CPUs=2, Memory=4096MB, Disk=20000MB) ...
  Preparing Kubernetes v1.16.2 on Docker '18.09.9' ...
  Downloading kubelet v1.16.2
  Downloading kubeadm v1.16.2
  Pulling images ...
  Launching Kubernetes ...  Waiting for: apiserver
  Done! kubectl is now configured to use "minikube"

  1. Перемикаємо мережу в Docker у нерозбірливий режим:

$ minikube ssh -- sudo ip link set docker0 promisc on

  1. Створюємо namespace і помічаємо робочий вузол:

$ kubectl create namespace openwhisk
$ kubectl label nodes --all openwhisk-role=invoker

  1. Отримуємо вміст репозиторію та перевизначаємо тип для ingress у файлі mycluster.yaml:

$ git clone https://github.com/apache/incubator-openwhisk-deploy-kube.git
$ cd incubator-openwhisk-deploy-kube/
$ cat << "EOF" > mycluster.yaml
whisk:
    ingress:
        type: NodePort
            api_host_name: 192.168.99.100
            api_host_port: 31001
nginx:
    httpsNodePort: 31001
EOF

  1. Встановлюємо Helm та проводимо розгортання за його допомогою:

$ brew install kubernetes-helm
$ helm init # init Helm Tiller, не нужно на Helm v3+
$ kubectl get pods -n kube-system # verify that tiller-deploy is in the running state, не нужно на helm v3+
$ kubectl create clusterrolebinding tiller-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
$ helm install ./openwhisk/helm/ --namespace=openwhisk -f mycluster.yaml

[На Linux з останніми версіями (була доступна v3.0.1) трохи по-іншому. - прим. перекладача]

$ curl -L0 https://get.helm.sh/helm-v3.0.1-linux-amd64.tar.gz | tar -xzvf - linux-amd64/helm --strip-components=1; sudo mv helm /usr/local/bin
$ kubectl create clusterrolebinding tiller-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
$ helm install ./openwhisk/helm/ --namespace=openwhisk --generate-name -f mycluster.yaml

  1. Перевіряємо, що все піднялося (STATUS = Running або Completed):

$ kubectl get pods -n openwhisk
NAME                                                              READY   STATUS      RESTARTS   AGE
openwhisk-1576070780-alarmprovider-6868dc694-plvpf                1/1     Running     1          1d5h
openwhisk-1576070780-apigateway-8d56f4979-825hf                   1/1     Running     1          1d5h
openwhisk-1576070780-cloudantprovider-544bb46596-9scph            1/1     Running     1          1d5h
openwhisk-1576070780-controller-0                                 1/1     Running     2          1d5h
openwhisk-1576070780-couchdb-7fd7f6c7cc-42tw6                     1/1     Running     1          1d5h
openwhisk-1576070780-gen-certs-z9nsb                              0/1     Completed   0          1d5h
openwhisk-1576070780-init-couchdb-r2vmt                           0/1     Completed   0          1d5h
openwhisk-1576070780-install-packages-27dtr                       0/1     Completed   0          1d4h
openwhisk-1576070780-invoker-0                                    1/1     Running     1          1d5h
openwhisk-1576070780-kafka-0                                      1/1     Running     1          1d5h
openwhisk-1576070780-kafkaprovider-f8b4cf4fc-7z4gt                1/1     Running     1          1d5h
openwhisk-1576070780-nginx-6dbdbf69bc-5x76n                       1/1     Running     1          1d5h
openwhisk-1576070780-redis-cfd8756f4-hkrt6                        1/1     Running     1          1d5h
openwhisk-1576070780-wskadmin                                     1/1     Running     1          1d5h
openwhisk-1576070780-zookeeper-0                                  1/1     Running     1          1d5h
wskopenwhisk-1576070780-invoker-00-1-prewarm-nodejs10             1/1     Running     0          61s
wskopenwhisk-1576070780-invoker-00-2-prewarm-nodejs10             1/1     Running     0          61s
wskopenwhisk-1576070780-invoker-00-3-whisksystem-invokerhealtht   1/1     Running     0          59s

  1. Налаштовуємо wsk для роботи:

$ wsk property set --apihost 192.168.99.100:31001
$ wsk property set --auth 23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP

перевіряємо:

$ wsk -i list
Entities in namespace: default
packages
actions
triggers
rules

Проблеми та їх вирішення

getsockopt: connection refused

$ wsk -i list
error: Unable to obtain the list of entities for namespace 'default': Get http://192.168.99.100:31001/api/v1/namespaces/_/actions?limit=0&skip=0: dial tcp 192.168.99.100:31001: getsockopt: connection refused

Перевіряємо, що контейнери в namespace openwhisk у статусі Running, т.к. іноді воно падає з помилками CreateContainerConfigError.

Invoker still initializing — Init:1/2

Процес скачування різноманітних середовищ виконання може тривати багато часу. Для прискорення можна вказати скорочений мінімальний список у файлі mycluster.yaml:

whisk:
  runtimes: "runtimes-minimal-travis.json"

Контейнер з ім'ям -install-packages- вивалюється в Error

Просто наростіть таймати для liveness тестів.

Установка OpenWhisk поверх Knative

Priti Desai проводила установку поверх кластера в хмарі IBM, а також на звичайному minikube, використовуючи Knative Build та BuildTemplates. Я також буду встановлювати поверх minukube, за мотивами того, як це було описано у нашому блозі раніше – з використанням останніх версій ПЗ. Оскільки Knative Build і BuildTemplates офіційно оголошені застарілими, використовуватиму рекомендовану заміну у вигляді Tekton Pipelines. Подальша частина статті написана після прочитання документації Tekton Pipelines, але заснована на ідеях Priti. Для роботи буде потрібний доступ до деякої Docker Registry — я, як і оригінальна авторка, використовуватиму DockerHub.

$ curl -L0 https://github.com/solo-io/gloo/releases/download/v1.2.10/glooctl-linux-amd64; chmod +x glooctl-linux-amd64; mv glooctl-linux-amd64 ~/bin
$ glooctl install knative
$ kubectl get pods -n knative-serving
NAME                              READY   STATUS    RESTARTS   AGE
activator-77fc555665-rvrst        1/1     Running   0          2m23s
autoscaler-5c98b7c9b6-x8hh4       1/1     Running   0          2m21s
autoscaler-hpa-5cfd4f6845-w87kq   1/1     Running   0          2m22s
controller-7fd74c8f67-tprm8       1/1     Running   0          2m19s
webhook-74847bb77c-txr2g          1/1     Running   0          2m17s
$ kubectl get pods -n gloo-system
NAME                                      READY   STATUS    RESTARTS   AGE
discovery-859d7fbc9c-8xhvh                1/1     Running   0          51s
gloo-545886d9c6-85mwt                     1/1     Running   0          51s
ingress-67d4996d75-lkkmw                  1/1     Running   0          50s
knative-external-proxy-767dfd656c-wwv2z   1/1     Running   0          50s
knative-internal-proxy-6fdddcc6b5-7vqd8   1/1     Running   0          51s

Безсерверні обчислення на основі OpenWhisk, частина 4
Складання та робота OpenWhisk поверх Knative

  1. Отримуємо вміст цього репозиторію:

$ git clone https://github.com/tektoncd/catalog/
$ cd catalog/openwhisk

  1. Виставляємо у вигляді змінних оточення дані для доступу до Registry та зберігаємо їх у вигляді секрету Kubernetes:

$ export DOCKER_USERNAME=<your docker hub username>
$ export DOCKER_PASSWORD=<your docker hub password>
$ sed -e 's/${DOCKER_USERNAME}/'"$DOCKER_USERNAME"'/' -e 's/${DOCKER_PASSWORD}/'"$DOCKER_PASSWORD"'/' docker-secret.yaml.tmpl > docker-secret.yaml
$ kubectl apply -f docker-secret.yaml

перевіряємо:

$ kubectl get secret
NAME                    TYPE                                  DATA      AGE
dockerhub-user-pass     kubernetes.io/basic-auth              2         21s

  1. Створюємо обліковий запис для збирання оточень:

$ kubectl apply -f service-account.yaml

перевіряємо:

$ kubectl get serviceaccount/openwhisk-runtime-builder
NAME                        SECRETS   AGE
openwhisk-runtime-builder   2         31m

  1. Створюємо завдання для збирання образу для OpenWhisk

$ kubectl apply -f openwhisk.yaml
task.tekton.dev/openwhisk created

  1. Запускаємо завдання для збирання образу (на прикладі NodeJS):

Створюємо файл taskrun.yaml із вмістом:

# Git Pipeline Resource for OpenWhisk NodeJS Runtime
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
    name: openwhisk-nodejs-runtime-git
spec:
    type: git
    params:
        - name: revision
          value: master
        - name: url
          value: https://github.com/apache/openwhisk-runtime-nodejs.git
---

# Image Pipeline Resource for OpenWhisk NodeJS Sample Application
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
    name: openwhisk-nodejs-helloworld-image
spec:
    type: image
    params:
        - name: url
          value: docker.io/${DOCKER_USERNAME}/openwhisk-nodejs-helloworld
---

# Task Run to build NodeJS image with the action source
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
    name: openwhisk-nodejs-helloworld
spec:
    serviceAccountName: openwhisk-runtime-builder
    taskRef:
        name: openwhisk
    inputs:
        resources:
            - name: runtime-git
              resourceRef:
                name: openwhisk-nodejs-runtime-git
        params:
            - name: DOCKERFILE
              value: "./runtime-git/core/nodejs10Action/knative/Dockerfile"
            - name: OW_ACTION_NAME
              value: "nodejs-helloworld"
            - name: OW_ACTION_CODE
              value: "function main() {return {payload: 'Hello World!'};}"
            - name: OW_PROJECT_URL
              value: ""
    outputs:
        resources:
            - name: runtime-image
              resourceRef:
                name: openwhisk-nodejs-helloworld-image
---

Застосовуємо актуальні дані для цього файлу:

$ sed 's/${DOCKER_USERNAME}/'"$DOCKER_USERNAME"'/' -i taskrun.yaml

Застосовуємо:

$ kubectl apply -f taskrun.yaml
pipelineresource.tekton.dev/openwhisk-nodejs-runtime-git created
pipelineresource.tekton.dev/openwhisk-nodejs-helloworld-image created
taskrun.tekton.dev/openwhisk-nodejs-helloworld created

Перевірка роботи полягає у отриманні імені pod`а, перегляду його статусу. Також можна переглянути журнал виконання кожного кроку, наприклад:

$ kubectl get taskrun
NAME                          SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
openwhisk-nodejs-helloworld   True        Succeeded   5m15s       44s
$ kubectl get pod openwhisk-nodejs-helloworld-pod-4640d3
NAME                                     READY   STATUS      RESTARTS   AGE
openwhisk-nodejs-helloworld-pod-4640d3   0/6     Completed   0          5m20s
$ kubectl logs openwhisk-nodejs-helloworld-pod-4640d3 -c step-git-source-openwhisk-nodejs-runtime-git-r8vhr
{"level":"info","ts":1576532931.5880227,"logger":"fallback-logger","caller":"logging/config.go:69","msg":"Fetch GitHub commit ID from kodata failed: open /var/run/ko/refs/heads/master: no such file or directory"}
{"level":"info","ts":1576532936.538926,"logger":"fallback-logger","caller":"git/git.go:81","msg":"Successfully cloned https://github.com/apache/openwhisk-runtime-nodejs.git @ master in path /workspace/runtime-git"}
{"level":"warn","ts":1576532936.5395331,"logger":"fallback-logger","caller":"git/git.go:128","msg":"Unexpected error: creating symlink: symlink /tekton/home/.ssh /root/.ssh: file exists"}
{"level":"info","ts":1576532936.8202565,"logger":"fallback-logger","caller":"git/git.go:109","msg":"Successfully initialized and updated submodules in path /workspace/runtime-git"}

Після виконання у нас в Registry з'явиться образ, який можна розгорнути за допомогою утиліти kn, призначеної для роботи з Knative сервісами, наприклад:

kn service create nodejs-helloworld --image docker.io/${DOCKER_USERNAME}/openwhisk-nodejs-helloworld
Service 'nodejs-helloworld' successfully created in namespace 'default'.
Waiting for service 'nodejs-helloworld' to become ready ... OK

Service URL:
http://nodejs-helloworld.default.example.com

У разі використання Gloo перевірити працездатність можна так:

$ curl -H "Host: nodejs-helloworld.default.example.com" -X POST $(glooctl proxy url --name knative-external-proxy)
{"OK":true}
$ curl -H "Host: nodejs-helloworld.default.example.com" -X POST $(glooctl proxy url --name knative-external-proxy)
{"payload":"Hello World!"}

Інші статті циклу

Безсерверні обчислення на основі OpenWhisk, частина 1
Безсерверні обчислення на основі OpenWhisk, частина 2
Безсерверні обчислення на основі OpenWhisk, частина 3
Безсерверні обчислення на основі OpenWhisk, частина 4

Джерело: habr.com

Додати коментар або відгук