基于K3s部署kubeedge

在边缘计算云原生领域,Rancher开源的k3s侧重于在边缘运行完整的k8s集群,而华为开源的kubeedge则是在边缘运行可以脱机的k8s节点。刚好手上有aliyun和腾讯云上各一台配置比较差的虚拟机,平时用来跑下基本的k8s服务,做个调试验证用的,一跑应用就卡死,内存严重不足。这场景似乎与边缘计算资源局限的窘境很类似;于是,大胆的想像在其中一台机器上跑k3s,同时用其作为kubeedge的k8s server侧;在另外一台上跑kubeedge的edge节点,组成一个集群。

K3S

k3s就不介绍了,具体可以参考其首页; 另外,这里是项目的Readme信息。可以关注一下其架构图,图上将server和agent分开,我们今天部署的方式是将server和仅有的一个agent部署到同一个服务器上。

Linux如何翻墙

为啥突然讲到linux翻墙?是因为这几天我发现在阿里和腾讯云的服务器上下载github的资源特别慢,几次通过脚本安装k3s都提示超时,实在是崩溃了!于是在linux上设置了ss client,然后速度飕飕的….

我是使用shadowsocks,这里默认你已经有墙外的shadowsocks服务器。主要告诉你如何在linux上配置ss的client,解决下载镜像以及一些限制资源较慢的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 安装ss
pip install shadowsocks

# 设置配置文件
cat /etc/shadowsocks.json
{
"server":"x.x.x.x", # 替换为你的ss server
"server_port":0, # 替换为你的ss server port
"local_address": "127.0.0.1",
"local_port":10800,
"password":"password", # 密码
"timeout":300,
"method":"aes-256-cfb",
"workers": 5
}
# 启动服务
sslocal -c /etc/shadowsocks.json -d start

# 设置代理
export http_proxy=socks5://127.0.0.1:10800
export https_proxy=socks5://127.0.0.1:10800

快速安装

1
2
3
4
5
6
7
8
9
10
# 自动安装(有时候墙内特别慢,会timeout,建议先翻墙)
curl -sfL https://get.k3s.io | sh -

# 如果已经下载了k3s,可以手动启动

# 服务端,Kubeconfig 位于 /etc/rancher/k3s/k3s.yaml
k3s server &

# agent端, NODE_TOKEN 位于 /var/lib/rancher/k3s/server/node-token
k3s agent --server https://myserver:6443 --token ${NODE_TOKEN}

k3s参数科普

  • 指定启动参数
1
2
3
4
5
6
7
k3s server --disable-agent
k3s server --no-deploy traefik
k3s server --no-deploy servicelb
k3s server --no-deploy coredns

k3s agent -u ${SERVER_URL} -t ${NODE_TOKEN} --no-flannel &
k3s agent -s ${SERVER_URL} -t ${NODE_TOKEN} --docker &
  • 指定k8s参数
1
2
3
4
5
6
7
8
9
10
11
# Adding extra argument can be done by passing the following flags to server or agent:

--kube-apiserver-arg value
--kube-scheduler-arg value
--kube-controller-arg value
--kubelet-arg value
--kube-proxy-arg value

#For example to add the following arguments -v=9 and log-file=/tmp/kubeapi.log to the kube-apiserver, you should pass the following:

k3s server --kube-apiserver-arg v=9 --kube-apiserver-arg log-file=/tmp/kubeapi.log

kubeedge场景配置

通过上面的参数配置介绍,结合kubeedge的需求,以及我的机器的配置有限,裁减掉一些没用的服务,最终的启动文件如下:

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
30
# cat /etc/systemd/system/k3s.service
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
After=network-online.target

[Service]
Type=notify
EnvironmentFile=/etc/systemd/system/k3s.service.env
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
server \
--no-deploy traefik \ # 没用,干掉
--docker \ # 之所以选择使用docker的原因是发现当前k3s集成的containerd有报错,没时间去慢慢查询;另外,docker处理镜像比较方便
--no-deploy servicelb \ # 没用,干掉
#--kube-apiserver-arg insecure-bind-address=0.0.0.0 \
#--kube-apiserver-arg insecure-port=8080

KillMode=process
Delegate=yes
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always

[Install]
WantedBy=multi-user.target

记得修改之后需要执行systemctl daemon-reload来生效。

pause镜像问题

由于k3s默认是使用containerd,而非docker的;而且containerd的sock文件与docker的containerd的sock文件不一样,所以通过docker拉取pause镜像的方式行不通(我在上一步的启动参数中指定了使用docker,如果你要想尝试继续使用containerd,就会遇到该问题)。这里需要这样操作:

1
2
3
4
5
6
7
8
9
10
11
# 先在安装了docker的机器上拉取镜像
$ docker pull ljchen/k8s_gcr_io_pause:3.1

# tag为k3s中pause image的label
$ docker tag ljchen/k8s_gcr_io_pause:3.1 k8s.gcr.io/pause:3.1

# 保存镜像为tar包
$ docker save k8s.gcr.io/pause:3.1 -o pause.tar

# 在k3s机器上,load该tar包(注意这里指定的address)
$ ctr --address=/run/k3s/containerd/containerd.sock cri load pause.tar

kubeedge

kubedege是华为开源的一个边缘计算的项目,下面是其架构图(后续再慢慢分析,今天只讲部署)。

首先需要将kubeedge项目拉取到本地,因为需要在该项目上构建镜像。

1
2
3
4
$ mkdir -p $GOPATH/src/github.com/kubeedge
$ cd $GOPATH/src/github.com/kubeedge

$ git clone https://github.com/kubeedge/kubeedge.git

完了之后,建议直接checkout到v1.0.0上来,其他版本之前有做过一些测试,发现不少问题。本文主要基于v1.0.0来操作。

cloud端

cloud端直接部署到k3s之上,主要是controller服务。

构建镜像

如果使用的不是v1.0.0版本,或者希望自己构建,可以执行以下操作。

1
2
$ cd $GOPATH/src/github.com/kubeedge/kubeedge
$ make cloudimage

如果只是希望部署,可以使用我已经构建好的镜像 ljchen/kubeedge_edgecontroller:v1.0.0

准备yaml

生成证书信息到secret中。

1
2
3
4
5
$ cd build/cloud; ls
01-namespace.yaml 03-clusterrole.yaml 05-configmap.yaml 07-deployment.yaml Dockerfile README_zh.md
02-serviceaccount.yaml 04-clusterrolebinding.yaml 08-service.yaml README.md

$ ../tools/certgen.sh buildSecret | tee ./06-secret.yaml

另外更改deployment的yaml镜像名称为ljchen/kubeedge_edgecontroller:v1.0.0,或者你自己构建的镜像。

最后就是执行yaml文件来部署cloud。

1
$ for resource in $(ls *.yaml); do kubectl create -f $resource; done

问题诊断

查看kubeedge命名空间下的deployment/edgecontroller的日志,会发现很多报错;这里涉及到两个地方需要做修改。

  • 报证书错误,当前证书无法用在kubernetes.default.svc.cluster.local
    需要手动修改configmap/edgecontroller,删除服务后面的cluster.local

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    apiVersion: v1
    items:
    - apiVersion: v1
    data:
    controller.yaml: |
    controller:
    kube:
    master: https://kubernetes.default.svc:443 # 这里
    kubeconfig: /etc/kubeedge/cloud/kubeconfig.yaml
    namespace: ""
    content_type: "application/vnd.kubernetes.protobuf"
    qps: 5
    burst: 10
    node_update_frequency: 10
  • 发现controller报没有权限操作services和endpoints,需要在对应的role中添加

    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
    30
    31
    32
    33
    34
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    creationTimestamp: "2019-07-12T07:11:27Z"
    labels:
    k8s-app: kubeedge
    kubeedge: edgecontroller
    name: edgecontroller
    resourceVersion: "4847"
    selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/edgecontroller
    uid: 43c656b8-a474-11e9-b3d9-00163e149cf2
    rules:
    - apiGroups:
    - ""
    resources:
    - nodes
    - nodes/status
    - configmaps
    - pods
    - pods/status
    - secrets
    - services # 这里services
    - endpoints # 这里endpoints
    verbs:
    - get
    - list
    - watch
    - update
    - apiGroups:
    - ""
    resources:
    - pods
    verbs:
    - delete
  • edgecontroller服务无法被edge访问

    由于edgecontroller是clusterIP类型,无法被集群外的edge访问到,这里可以直接在部署前或者部署之后手动修改service的类型为nodePort类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    apiVersion: v1
    kind: Service
    metadata:
    name: edgecontroller
    namespace: kubeedge
    labels:
    k8s-app: kubeedge
    kubeedge: edgecontroller
    spec:
    type: NodePort
    ports:
    - port: 10000
    name: cloudhub
    selector:
    k8s-app: kubeedge
    kubeedge: edgecontroller

edge端

edge端通过与edgecontroller通信来上报上报状态,以及获取k8s配置并执行。这里主要讲述通过脚本部署的方式,具体部署流程如下。官方文档见这里

准备镜像

首先是镜像准备,如果你希望自己构建镜像,请执行以下脚本。如果不想再构建,可以直接使用我构建好的镜像: ljchen/kubeedge_edgecore:v1.0.0

1
2
3
4
5
6
7
# 检查环境是否ready
$ cd $GOPATH/src/github.com/kubeedge/kubeedge/build/edge
$ ./run_daemon.sh prepare

# 构建镜像
$ cd $GOPATH/src/github.com/kubeedge/kubeedge
$ make edgeimage

拷贝证书信息

您需要去拷贝edge certs文件包括edge.crt和edge.key到您想要部署edge part的k8s节点上的/etc/kubeedge/certs/文件夹中。这里我是直接将cloud端主机上的/etc/kubeedge/目录打包并scp到edge端主机上解压的。

cloudhub信息

由于edge端是通过cloudhub来访问k8s api-server的,edge端的edgehub会与cloudhub进行websocket通信,需要确保该目标服务器端口可以被访问。该端口的查看方式如下:

1
2
3
$ kce get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
edgecontroller NodePort 10.43.161.49 <none> 10000:30744/TCP 2d3h

就是edgecontroller的10000端口映射到主机nodePort的端口号。

启动脚本

1
2
3
4
5
6
7
8
9
$GOPATH/src/github.com/kubeedge/kubeedge/build/edge/run_daemon.sh only_run_edge  \
image="kubeedge/edgecore:v1.0.0" \
cloudhub=${k3s-server-IP}:30744 \
edgename=edgenode \
arch=amd64 \
qemu_arch=x86_64 \
certpath=/etc/kubeedge/certs \
certfile=/etc/kubeedge/certs/edge.crt \
keyfile=/etc/kubeedge/certs/edge.key

创建node节点

在k3s服务器节点上通过以下yaml文件来创建一个node,保存为node.yaml之后,执行kubectl apply -f node.yaml

1
2
3
4
5
6
7
apiVersion: v1
kind: Node
metadata:
name: edgenode
labels:
name: edge-node
node-role.kubernetes.io/edge: "" # 切忌!必须带上这个label,否则你就慢慢查问题吧

然后,查看node状态可以看到edge已经上报状态到k3s了。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
$ kc get nodes
NAME STATUS ROLES AGE VERSION
aliyun-vm Ready master 3d7h v1.14.3-k3s.1
edgenode Ready edge 3h26m v1.10.9-kubeedge-v1.0.0

$ kc describe node edgenode
Name: edgenode
Roles: edge
Labels: name=edge-node
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Node","metadata":{"annotations":{},"labels":{"name":"edge-node"},"name":"edgenode"}}
node.alpha.kubernetes.io/ttl: 0
CreationTimestamp: Mon, 15 Jul 2019 18:18:37 +0800
Taints: <none>
Unschedulable: false
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
Ready True Mon, 15 Jul 2019 21:45:01 +0800 Mon, 15 Jul 2019 21:45:01 +0800 EdgeReady edge is posting ready status
Addresses:
InternalIP: 172.18.0.2
Hostname: bc9fc8d547f7
Capacity:
cpu: 1
memory: 991Mi
pods: 110
Allocatable:
cpu: 1
memory: 891Mi
pods: 110
System Info:
Machine ID:
System UUID:
Boot ID:
Kernel Version: 3.10.0-862.14.4.el7.x86_64
OS Image: Alpine Linux v3.10
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://3.10.0
Kubelet Version: v1.10.9-kubeedge-v1.0.0
Kube-Proxy Version:
PodCIDR: 10.42.1.0/24
Non-terminated Pods: (1 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
default nginx-7db9fccd9b-shkw7 0 (0%) 0 (0%) 0 (0%) 0 (0%) 44m
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 0 (0%) 0 (0%)
memory 0 (0%) 0 (0%)
ephemeral-storage 0 (0%) 0 (0%)
Events: <none>

接下来,就可以像使用普通k8s一样部署你的应用到edge节点(你可以把节点换成你的树莓派或者其他开发板)了。enjoy yourself ^_^

0%