前置知识:Kubernetes 一小时轻松入门
1 使用 Multipass 创建虚拟机集群
本文的 Kubernetes 集群中包含四台虚拟机。其中包括一台 master 节点和两台 worker 节点,以及一个用于持久化存储的 NFS 服务器。它们的配置如下:
| 虚拟机名称 | CPU 核心数 | 内存容量 | 硬盘空间 | 
|---|
| master | 2 | 6GB | 50GB | 
| worker1 | 2 | 6GB | 20GB | 
| worker2 | 2 | 6GB | 20GB | 
| storage | 2 | 4GB | 50GB | 
OpenWhisk 对节点配置的最低要求
1
  | sudo snap install multipass
  | 
1.2 创建虚拟机
1
2
3
4
  | multipass launch --name master --cpus 2 --memory 6G --disk 50G
multipass launch --name worker1 --cpus 2 --memory 6G --disk 20G
multipass launch --name worker2 --cpus 2 --memory 6G --disk 20G
multipass launch --name storage --cpus 2 --memory 4G --disk 50G
  | 
查看创建结果:
1
2
3
4
5
  | Name                    State             IPv4             Image
master                  Running           10.251.200.141   Ubuntu 24.04 LTS
storage                 Running           10.251.200.186   Ubuntu 24.04 LTS
worker1                 Running           10.251.200.142   Ubuntu 24.04 LTS
worker2                 Running           10.251.200.168   Ubuntu 24.04 LTS
  | 
其他可能用到的命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  | # 查看虚拟机资源使用情况
multipass info <instance-name>
# 将虚拟机移动至回收站
multipass delete <instance-name>
# 将虚拟机移出回收站
multipass recover <instance-name>
# 销毁虚拟机
multipass delete --purge <instance-name>
# 销毁所有虚拟机
multipass delete --purge --all
  | 
1.3 在 master 节点中安装 K3s
从宿主机连接到 master 节点:
执行 K3s 安装脚本:
1
2
3
4
  | curl -sfL https://get.k3s.io | sh -
# 使用国内镜像
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
  | 
1.4 将 worker 节点加入集群
在宿主机中获取 master 节点的 IP 地址和 K3s 的 token:
1
2
  | MASTER_IP=$(multipass info master | grep IPv4 | awk '{print $2}')
TOKEN=$(multipass exec master sudo cat /var/lib/rancher/k3s/server/node-token)
 | 
在所有 worker 节点上执行 K3s 安装脚本:
1
2
3
4
5
6
7
8
  | for index in 1 2; do
    multipass exec worker${index} -- bash -c "curl -sfL https://get.k3s.io | K3S_URL=https://${MASTER_IP}:6443 K3S_TOKEN=${TOKEN} sh -"
done
# 使用国内镜像
for index in 1 2; do
    multipass exec worker${index} -- bash -c "curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_URL=https://${MASTER_IP}:6443 K3S_TOKEN=${TOKEN} sh -"
done
 | 
查看集群节点状态:
1
  | multipass exec master sudo kubectl get nodes
  | 
1
2
3
4
  | NAME      STATUS   ROLES                  AGE     VERSION
master    Ready    control-plane,master   10m     v1.29.4+k3s1
worker1   Ready    <none>                 2m12s   v1.29.4+k3s1
worker2   Ready    <none>                 2m4s    v1.29.4+k3s1
  | 
1.5 搭建 NFS 服务器
参考文档
从宿主机连接到 storage 节点:
1
  | multipass shell storage
  | 
安装 NFS 服务:
1
  | sudo apt install nfs-kernel-server
  | 
创建 Kubernetes 集群数据存储目录:
1
  | sudo mkdir /var/nfs/kubedata -p
  | 
将目录的拥有者设置为 nobody:
1
  | sudo chown nobody: /var/nfs/kubedata
  | 
启用 NFS 服务:
1
2
  | sudo systemctl enable nfs-server.service
sudo systemctl start nfs-server.service
  | 
编辑 /etc/exports 文件:
在文件末尾添加集群数据存储目录的配置:
1
  | /var/nfs/kubedata *(rw,sync,no_subtree_check,no_root_squash,no_all_squash)
  | 
应用配置文件:
1
  | exporting *:/var/nfs/kubedata
  | 
2 安装 NFS 客户端
为 Kubernetes 集群中的所有节点安装 NFS 客户端:
1
2
3
  | multipass exec master -- bash -c "sudo apt install nfs-common -y"
multipass exec worker1 -- bash -c "sudo apt install nfs-common -y"
multipass exec worker2 -- bash -c "sudo apt install nfs-common -y"
  | 
否则在创建 NFS Dynamic Storage 时,节点无法挂载 NFS 服务器的共享目录。
3 安装 Kubernetes 集群的包管理工具 Helm
从宿主机连接到 master 节点:
使用 snap 安装 Helm:
1
  | sudo snap install helm --classic
  | 
4 安装 OpenWhisk Command-line Interface (wsk CLI)
从宿主机连接到 master 节点:
下载并安装 wsk CLI 二进制文件:
1
2
3
4
  | mkdir ~/downloads && cd ~/downloads
wget https://github.com/apache/openwhisk-cli/releases/download/latest/OpenWhisk_CLI-latest-linux-amd64.tgz
tar -xvf OpenWhisk_CLI-latest-linux-amd64.tgz
sudo mv wsk /usr/local/bin/wsk
  | 
5 为 Kubernetes 集群部署 NFS Dynamic Storage
参考文档中 deployment.yaml 文件所使用的 quay.io/external_storage/nfs-client-provisioner 镜像已停止维护。Pod 运行时会报错 unexpected error getting claim reference: selfLink was empty, can’t make reference 。selfLink 字段在 Kubernetes 1.20 版本中被废弃。
根据官方文档,使用 NFS subdir 为 Kubernetes 集群提供 NFS Dynamic Storage 。
使用 Helm Chart 安装 NFS Subdirectory External Provisioner
参考文档
从宿主机连接到 master 节点:
添加 Helm Chart 仓库:
1
2
  | sudo helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
sudo helm repo update
  | 
以名称 openwhisk-nfs 部署 NFS Subdirectory External Provisioner,并指定 NFS 服务器的 IP 地址和共享目录:
1
2
3
  | sudo helm --kubeconfig /etc/rancher/k3s/k3s.yaml install openwhisk-nfs nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
    --set nfs.server=10.251.200.186 \
    --set nfs.path=/var/nfs/kubedata
 | 
在 K3s 中,需要使用 --kubeconfig 参数指定 kubeconfig 文件的路径,使得 Helm 能够访问集群。
安装成功后显示信息:
1
2
3
4
5
6
  | NAME: openwhisk-nfs
LAST DEPLOYED: Wed May  8 18:15:14 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
  | 
检查资源创建结果
1
  | sudo kubectl get clusterrole,clusterrolebinding,role,rolebinding | grep nfs
  | 
1
2
3
4
  | clusterrole.rbac.authorization.k8s.io/openwhisk-nfs-nfs-subdir-external-provisioner-runner                   2024-05-08T10:15:14Z
clusterrolebinding.rbac.authorization.k8s.io/run-openwhisk-nfs-nfs-subdir-external-provisioner        ClusterRole/openwhisk-nfs-nfs-subdir-external-provisioner-runner     112s
role.rbac.authorization.k8s.io/leader-locking-openwhisk-nfs-nfs-subdir-external-provisioner   2024-05-08T10:15:14Z
rolebinding.rbac.authorization.k8s.io/leader-locking-openwhisk-nfs-nfs-subdir-external-provisioner   Role/leader-locking-openwhisk-nfs-nf-subdir-external-provisioner   112s
  | 
1
  | sudo kubectl get storageclass
  | 
1
2
3
  | NAME                   PROVISIONER                                                   RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path                                         Delete          WaitForFirstConsumer   false                  7h16m
nfs-client             cluster.local/openwhisk-nfs-nfs-subdir-external-provisioner   Delete          Immediate              true                   3m26s
  | 
1
2
  | NAME                                                             READY   STATUS    RESTARTS   AGE
openwhisk-nfs-nfs-subdir-external-provisioner-54846ffcfb-26j8r   1/1     Running   0          5m35s
  | 
其他可能用到的命令
1
2
  | # 卸载 NFS Subdirectory External Provisioner
sudo helm --kubeconfig /etc/rancher/k3s/k3s.yaml uninstall openwhisk-nfs
  | 
6 部署 OpenWhisk
从宿主机连接到 master 节点:
6.1 为集群中的节点添加标签
在部署 OpenWhisk 之前,需要指明哪些节点运行 OpenWhisk 的控制面板(如:controller、kafka、zookeeper 和 CouchDB),哪些节点执行函数调用。
通过给节点添加标签来指明节点的角色:
1
2
3
  | sudo kubectl label node master openwhisk-role=core
sudo kubectl label node worker1 openwhisk-role=invoker
sudo kubectl label node worker2 openwhisk-role=invoker
  | 
使用 sudo kubectl describe nodes <node-name> 命令查看节点的标签。
6.2 编写安装配置文件 mycluster.yaml
参考文档
mycluster.yaml 配置了 Kubernetes 集群的 Ingress 服务的地址和端口号(默认 31001 ),用于 wsk CLI 连接 OpenWhisk 服务。
1
2
3
4
5
6
7
8
9
10
11
12
  | whisk:
  ingress:
    type: NodePort
    apiHostName: 10.251.200.141
    apiHostPort: 31001
nginx:
  httpsNodePort: 31001
invoker:
  containerFactory:
    impl: "kubernetes"
 | 
将上述内容写入 ~/kubeyaml/mycluster.yaml 文件中。
6.3 配置 wsk CLI
配置 wsk CLI 的 apihost 为 Ingress 服务的地址和端口号,auth 为 OpenWhisk 的 guest 用户的默认 token :
1
2
  | sudo wsk property set --apihost 10.251.200.141:31001
sudo wsk property set --auth 23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP
  | 
6.4 使用 Helm 部署 OpenWhisk
Helm Repository 中的 OpenWhisk Chart 使用的 npm 镜像版本过低,会导致安装失败。因此使用 GitHub 上的 OpenWhisk Chart 安装。
1
2
3
4
  | cd ~
git clone https://github.com/apache/openwhisk-deploy-kube.git
cd openwhisk-deploy-kube
sudo helm --kubeconfig /etc/rancher/k3s/k3s.yaml install owdev ./helm/openwhisk -n openwhisk --create-namespace -f ~/kubeyaml/mycluster.yaml
  | 
在 K3s 中,需要使用 --kubeconfig 参数指定 kubeconfig 文件的路径,使得 Helm 能够访问集群。
安装成功后显示信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  | NAME: owdev
LAST DEPLOYED: Wed May  8 18:26:12 2024
NAMESPACE: openwhisk
STATUS: deployed
REVISION: 1
NOTES:
Apache OpenWhisk
Copyright 2016-2021 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
To configure your wsk cli to connect to it, set the apihost property
using the command below:
  $ wsk property set --apihost 10.251.200.141:31001
Your release is named owdev.
To learn more about the release, try:
  $ helm status owdev
  $ helm get owdev
Once the 'owdev-install-packages' Pod is in the Completed state, your OpenWhisk deployment is ready to be used.
Once the deployment is ready, you can verify it using:
  $ helm test owdev --cleanup
  | 
此时可以使用命令 sudo kubectl get pvc,pv -A 查看 NFS Dynamic Storage 的创建结果。STATUS 为 Bound 时表示创建成功。
使用命令 sudo kubectl get pods -n openwhisk --watch 查看集群容器部署的状态。当 install-packages Pod 的状态为 Completed 时,OpenWhisk 部署完成。
使用命令 sudo wsk -i package list /whisk.system 查看安装好的 OpenWhisk 包。-i 选项用于跳过 SSL 证书验证。
1
2
3
4
5
6
7
8
  | packages
/whisk.system/messaging                                                shared
/whisk.system/alarms                                                   shared
/whisk.system/websocket                                                shared
/whisk.system/utils                                                    shared
/whisk.system/samples                                                  shared
/whisk.system/slack                                                    shared
/whisk.system/github                                                   shared
  | 
其他可能用到的命令
1
2
3
4
5
6
  | # 查看 OpenWhisk 全部资源状态
sudo kubectl get all -n openwhisk
sudo kubectl get all -o wide -n openwhisk
# 卸载 OpenWhisk
sudo helm --kubeconfig /etc/rancher/k3s/k3s.yaml uninstall owdev -n openwhisk
  | 
7 函数部署示例
OpenWhisk 文档
从宿主机连接到 master 节点:
创建用于存储函数的目录:
1
  | mkdir ~/functions && cd ~/functions
  | 
7.1 通过 wsk CLI 调用函数
创建 Node.js 函数 hello_cli.js:
1
2
3
4
  | function main(params) {
    var name = params.name || 'World';
    return {payload: 'Hello, ' + name + '!'};
}
 | 
使用 wsk CLI 部署函数:
1
  | sudo wsk -i action create hellocli hello_cli.js
  | 
调用函数:
1
  | sudo wsk -i action invoke hellocli --result
  | 
1
2
3
  | {
    "payload": "Hello, World!"
}
 | 
传递参数:
1
  | sudo wsk -i action invoke hellocli --result --param name JavaScript
  | 
1
2
3
  | {
    "payload": "Hello, JavaScript!"
}
 | 
7.2 通过 web URL 调用函数
参考文档
创建 Python 函数 hello_web.py:
1
2
3
4
5
6
  | def main(args):
    return {
        "statusCode": 200,
        "headers": { "Content-Type": "application/json" },
        "body": args
    }
 | 
使用 wsk CLI 部署函数:
1
  | sudo wsk -i action create helloweb hello_web.py --web true
  | 
获取函数的 web URL:
1
  | sudo wsk -i action get helloweb --url
  | 
1
  | https://10.251.200.141:31001/api/v1/web/guest/default/helloweb
  | 
在宿主机中使用 curl 命令调用函数,-k 选项用于跳过 SSL 证书验证:
1
  | curl -k https://10.251.200.141:31001/api/v1/web/guest/default/helloweb
  | 
1
2
3
4
5
6
7
8
9
  | {
  "__ow_headers": {
    "accept": "*/*",
    "host": "controllers",
    "user-agent": "curl/7.81.0"
  },
  "__ow_method": "get",
  "__ow_path": ""
}
 | 
传递参数:
1
  | curl -k https://10.251.200.141:31001/api/v1/web/guest/default/helloweb?name=Python
  | 
1
2
3
4
5
6
7
8
9
10
  | {
  "__ow_headers": {
    "accept": "*/*",
    "host": "controllers",
    "user-agent": "curl/7.81.0"
  },
  "__ow_method": "get",
  "__ow_path": "",
  "name": "Python"
}
 | 
8 运维相关
8.1 关闭虚拟机
关闭顺序:worker1 -> worker2 -> master -> storage
1
2
3
4
  | multipass stop worker1
multipass stop worker2
multipass stop master
multipass stop storage
  | 
8.2 启动虚拟机
启动顺序:storage -> master -> worker1 -> worker2
1
2
3
4
  | multipass start storage
multipass start master
multipass start worker1
multipass start worker2
  | 
9 wsk CLI 常用命令
9.1 函数相关
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  | # 列出所有函数
sudo wsk -i action list
# 创建函数
sudo wsk -i action create <action_name> <action_file>
sudo wsk -i action create <action_name> <action_zip> --kind <available_runtime>
# --kind 可选的参数在 https://github.com/apache/openwhisk-deploy-kube/blob/master/helm/openwhisk/runtimes.json 中配置
# 删除函数
sudo wsk -i action delete <action_name>
# 更新函数
sudo wsk -i action update <action_name> <action_file> --docker openwhisk/action-python-v3.11
# --docker 选项可以指定函数的运行环境(必须在 Docker Hub 上存在)
# 调用函数
sudo wsk -i action invoke --result <action_name> --param <key1> <value1> ...
  | 
9.2 调用相关
1
2
3
4
5
6
7
8
9
10
11
  | # 列出所有函数调用
sudo wsk -i activation list
# 获取函数调用的详细信息
sudo wsk -i activation get <request_id>
# 获取函数调用的结果
sudo wsk -i activation result <request_id>
# 获取函数调用的日志
sudo wsk -i activation logs <request_id>
  | 
9.3 利用 virtualenv 打包 Python 函数和依赖
参考文档:
将 __main__.py 和 requirements.txt 所在的目录挂载到 openwhisk/action-python-v3.12 容器的 /tmp 目录下,然后利用容器的环境创建 virtualenv 文件夹并安装 requirements.txt 中的依赖:
1
  | sudo docker run --rm -v "$(pwd):/tmp" --entrypoint "/bin/bash" openwhisk/action-python-v3.12 -c "cd /tmp && virtualenv virtualenv && source virtualenv/bin/activate && pip install -r requirements.txt"
  | 
然后将文件夹内的内容打包成 zip 文件:
1
  | zip -r ../<action_name>.zip .
  |