个人搭建serverless架构快速指南和第一个nodejs服务
发布于 5 年前 作者 zy445566 8150 次浏览 来自 分享

之前我们都是基于云服务商的serverless来做服务的,但是存在一个问题,不够标准化,即每个云服务商都可能有自己的一套方案,最近在看knative,发现是一套不错的标准化方案,所以个人搭建来尝尝鲜。

准备工作

如果我们只有一台机器的话,则需要一台相对较好的机器或工作站,如果自己有三台以上的机器则相对“舒适”。目前本人以一台机器搭建集群的方式来构建基于knative的serverless服务。

我们可以使用轻量的虚拟服务工具multipass来方便的模拟集群服务。 我这里使用multipass运行了一个master和两个slave,都是分配了双核CPU和2G运行内存(所以您的机器至少还有8G空闲内存),如下:

multipass launch --name m1 -c 2 -m 4G
multipass launch --name s1 -c 2 -m 2G
multipass launch --name s2 -c 2 -m 2G
# 这一步可以虚拟机是否启动
multipass list 

同时分别给下面的机器都安装microk8s,我这里就示范一下master的安装过程,两个slave的安装步骤类似,如下:

# 这一步进入master节点
multipass exec m1 bash 
# 安装microk8s,慢的话可以重试,它会自动切换节点
# 当前目前最新的microk8s版本是v1.16.0
sudo snap install --classic microk8s 
# 设置一下命令行的别名
sudo snap alias microk8s.kubectl kubectl 
# 退出主节点
exit

安装好了microk8s 先不要着急,我们还要做一些工作,这里您可以选择走代理容器仓库或者在虚拟服务中打开翻墙。

  • 翻墙方案
# 进入后如果需要代理则需要获取宿主机的地址进行代理
# 比如先在宿主机终端代理ip不要绑定127.0.0.1而是0.0.0.0,这样同局域网其它机器才能访问
# 比如我在宿主机内网ip192.168.64.1
# 那么在每个虚拟服务代理命令是:
export http_proxy=http://192.168.64.1:1087;export https_proxy=http://192.168.64.1:1087;
# 然后修改代理
sudo vim /var/snap/microk8s/current/args/containerd-env
# 增加HTTPS_PROXY=http://192.168.64.1:1087
# 完成后重置下服务,这里可以多重置几次直到提示服务重启完成
sudo microk8s.reset 
# 这里注意看看虚拟服务是否翻墙成功
curl google.com
  • 代理容器仓库方案
# 因为k8s.gcr.io被墙了,如果不方便使用代理
# 可以先把对应的容器images放到自己私库中
sudo sed -i 's/k8s.gcr.io/{这里替换成你自己的私库地址}/g' `sudo grep -rl  --include="*.yaml" --include="*.toml"  "k8s.gcr.io"  /var/snap/microk8s/current/args/`
# 完成后重置下服务,这里可以多重置几次直到提示服务重启完成
sudo microk8s.reset 

设置主从服务

我这里只展示master和slave1节点的的主从设置,如果要设置slave2节点,请重复下面的步骤,如下:

# 进入master节点
multipass exec m1 bash 
# 设置为k8s的master节点
sudo microk8s.add-node 
# 这里第一行会输出Join node with: microk8s.join .....
# 然后复制这一行
# 不是其它行的,不要搞错了
# 退出主节点
exit
# 进入slave1节点,如果要进slave2,则为s2
multipass exec s1 bash 
# 下面这行是我主节点输出的,你们的是不一样的
sudo microk8s.join 192.168.64.3:25000/bBhVYWpAEdgVdzchAidRMHbqRzevXXEt
# 退出slave1节点
exit

查看节点是否完成,如下:

sudo microk8s.kubectl get no
# 输出如下:
NAME           STATUS   ROLES    AGE     VERSION
192.168.64.4   Ready    <none>   3m35s   v1.16.0
192.168.64.5   Ready    <none>   2m38s   v1.16.0
m1             Ready    <none>   22m     v1.16.0

到这里主从设置就完成了,如果机器好的话建议最后设置主从,毕竟分布后没有单机方便调试了。

开启k8s的dns服务

sudo microk8s.enable dns

由于默认dns的上游是8.8.8.8是谷歌的dns服务,我们可能链接不上,所以修改成阿里云的吧,如下:

# 输入<英文>冒号(:),后粘贴下面 
# %s/8.8.8.8\ 8.8.4.4/223.5.5.5\ 223.6.6.6/g 
# 按回车就能一键修改了
sudo microk8s.kubectl -n kube-system edit configmap/coredns 
# 这个vim编辑器,然后:wq 保存并退出就好

然后看服务是否正常runing

sudo microk8s.kubectl get pods --all-namespaces

如果有问题则看看是什么问题引起的,比如镜像是否下拉正常,代理是否成功,并解决

sudo microk8s.kubectl -n kube-system describe pod coredns 

解决删除coredns,它会自动重启个新的

# coredns-xxxxx-xxxxx是你那个容器的名字和后缀,每个不一样
sudo microk8s.kubectl -n kube-system delete pod coredns-xxxxx-xxxxx

直到这样才算成功

multipass@m1:~$ sudo microk8s.kubectl get pods --all-namespaces
NAMESPACE     NAME                      READY   STATUS    RESTARTS   AGE
kube-system   coredns-9b8997588-chwbr   1/1     Running   0          4m8s

开启istio服务

echo 'N' | sudo microk8s.enable istio
# 最后会输出Istio is starting就部署成功了

但是还是要看服务是否都启动

sudo microk8s.kubectl get pods --all-namespaces

这里有些istio老是健康检查失败,我觉得是microk8s的BUG,可能是重启容器后kubelet未启动导致,我这重启下全部microk8s就好了

sudo snap stop microk8s
sudo snap start microk8s

注意这里可能会重置dns的配置,重新改下就好

# 输入<英文>冒号(:),后粘贴下面 
# %s/8.8.8.8\ 8.8.4.4/223.5.5.5\ 223.6.6.6/g 
# 按回车就能一键修改了
sudo microk8s.kubectl -n kube-system edit configmap/coredns 
# 这个vim编辑器,然后:wq 保存并退出就好

开启knative服务

echo 'N' | sudo microk8s.enable knative
# 最后会输出Knative is starting就部署成功了

可能会停留在这里,没关系,多等一下就好了.这是因为istio没有启动完全,启动完全就好了

The connection to the server 127.0.0.1:16443 was refused - did you specify the right host or port?

注意这里如果使用自己的私库,注意一些替换

echo '#!/bin/bash
namespace=${1-"kube-system"}
for podname in $(sudo microk8s.kubectl -n $namespace get -o=name pod)
do
    mkdir -p $(dirname $podname)
    echo $(basename $podname)
    sudo microk8s.kubectl -n $namespace get pod  -o yaml $(basename $podname) > $podname.yaml
    sed -i "s/gcr.io/{替换成你对应的私库地址}/g" $podname.yaml
    sudo microk8s.kubectl  -n $namespace replace -f $podname.yaml
done' > replace_mirror.sh
sh replace_mirror.sh {替换成你需要重新替换的命名空间}

knavtive果然很大,给大家看一下有多少pod,反正我这分配了2核,4G的虚拟机已经卡的不行了

pod/grafana-7568fffb58-2bphj
pod/istio-citadel-756ffc49cc-66f4x
pod/istio-cleanup-secrets-1.2.2-ftf6m
pod/istio-egressgateway-79f567989c-mj72l
pod/istio-galley-757c85bdcb-r2rw2
pod/istio-grafana-post-install-1.2.2-8mm52
pod/istio-ingressgateway-7d4c9898bf-5h4nk
pod/istio-pilot-7d89f7fdd4-kfqjh
pod/istio-policy-568dd867fb-th4fc
pod/istio-sidecar-injector-7ccc68767c-q7jtk
pod/istio-telemetry-867dc6bd9f-wjqxb
pod/istio-tracing-84cbc6bc8-s5rq6
pod/kiali-54655cd89-wxkj2
pod/prometheus-6f74d6f76d-8bqq7
pod/zipkin-78b84857d5-pc7fq
pod/eventing-controller-699c55df94-mjfn5
pod/eventing-webhook-57b5c65467-sd2p2
pod/imc-controller-9d7bf5895-pm8xv
pod/imc-dispatcher-7848cfc59b-77pth
pod/sources-controller-64f8c46b5d-zgfls
pod/elasticsearch-logging-0
pod/grafana-b7999c9c8-5ws5b
pod/kibana-logging-669968b8d4-f9htp
pod/kube-state-metrics-594f5d4588-rqvvq
pod/node-exporter-z8ctb
pod/prometheus-system-1
pod/activator-6469979459-ztwnk
pod/autoscaler-67ddb69b5c-qcnpg
pod/autoscaler-hpa-5dd6b94d9-brssm
pod/controller-58c9c44966-tggzd
pod/networking-istio-8fc67796d-75p4b
pod/webhook-dfc9dd4c4-874cg
pod/coredns-9b8997588-t5lrn

到这里knavtive就搭建完了,可以走我们第一个例子了

Hello World

  1. npm初始化package.json(./package.json)
{
  "name": "hello-world",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "zy445566",
  "license": "MIT"
}
  1. Hello World代码(./index.js)
const http = require('http');
const port = process.env.PORT || 8080;
http.createServer((req, res) => {
    const target = process.env.TARGET || 'World';
    res.end(`Hello ${target}!`);
}).listen(port);
console.log(`listening on port:http://127.0.0.1:${port}`);
  1. 构建docker文件并推送(./Dockerfile)
FROM node:12-slim
WORKDIR /usr/src/app
COPY . ./
RUN npm install
CMD [ "npm", "start" ]

比如我的docker.io的id是zy445566

docker build -t zy445566/helloworld-nodejs .
docker push zy445566/helloworld-nodejs
  1. 写service的yaml文件并部署(./service.yaml)
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-nodejs
  namespace: default
spec:
  template:
    spec:
      containers:
      - image: docker.io/zy445566/helloworld-nodejs
        env:
        - name: TARGET
          value: "Node.js Sample Native v1"

部署服务

kubectl apply --filename service.yaml
  1. 获取ip并访问
echo 'INGRESSGATEWAY=knative-ingressgateway
if kubectl get configmap config-istio -n knative-serving &> /dev/null; then
    INGRESSGATEWAY=istio-ingressgateway
fi
kubectl get svc $INGRESSGATEWAY --namespace istio-system' > get_ip_address.sh
sh get_ip_address.sh
kubectl get ksvc helloworld-nodejs  --output=custom-columns=NAME:.metadata.name,URL:.status.url
curl -H "Host: helloworld-nodejs.default.example.com" http://{IP_ADDRESS} # 这个是get_ip_address获取的地址
# output: Hello Node.js Sample Native v1!

总结

至此使用microk8s搭建的Knative服务总体来说还是不错,但是microk8s问题也挺多的,本来抱着省心去做的,结果也不是那么省心,期待microk8s后续能越做越好吧。就Knative来说服务偏大,单机基本无法承载,远远超出了我的预想,不建议为了实现serverless架构就动用这个牛刀,服务复杂后再上这个也不迟。对于multipass用来虚拟环境做分布式应用测试还不错,是个小而美的东西。

3 回复

微服务还没搞清楚,serverless 又来了……

@waitingsong 是啊,现在前后端技术更迭的都快。不过主流还是Paas

@zy445566 学不过来了……

回到顶部