
如何本地部署 laf - k8s学习篇
在 Ubuntu 服务器自建 laf 测试环境的实践:准备域名和证书、执行部署、调整运行配置,并排查 Kubernetes DNS、镜像访问及 npm 依赖安装问题。
最近做了几个小程序,没有搭建自己的后台服务,全部使用的 serverless,使用的平台是 laf,laf 是一个和微信云开发一样的 serverless 平台,同样集函数、数据库、存储为一体,一个 MVP 版本的小程序可快速基于 laf 构建,同样的服务,微信云开发每个月要 39 块,而 laf 最小版本大概 13 块,当然现在还有基于 sealos 的 laf,每个月成本更低。
之前的做法是会在 laf 上起两个应用,一个用作 production 环境,一个用于 staging 环境,但这样会有两项应用在计费,最近有一些其他小程序的想法,所以萌生了使用之前空置的一台华为云服务器搭建一个自己的 laf 作为测试环境的想法,说干就干!

前期需要做一些准备工作
- 域名
- 服务器(Ubuntu22.0)
- docker 代理
假如 web 控制台域名是 a.b.com 则需要准备:
oss.a.b.com,*.oss.a.b.com,*.site.a.b.com,*.a.b.com,a.b.com,需要将这些域名映射到服务器,同样申请证书需要申请上边这些域名的
服务器需要特别注意,之前服务器安装了 docker 和 nginx 需要全部清空,就是只需要一台完全干净的服务器就可以,不然会有一些预料之中的错误,类似:

卸载 nginx
#卸载 Nginx
sudo systemctl stop nginx
sudo apt-get remove --purge nginx
sudo rm -rf /etc/nginx
#删除 Nginx 配置文件和目录
sudo rm -rf /var/log/nginx
#卸载 docker
sudo systemctl stop docker
sudo systemctl stop docker.socket
#卸载 docker-compose
sudo apt-get remove docker-compose
#删除 docker 数据
sudo rm -rf /var/lib/docker
sudo rm -rf /etc/docker
sudo rm -rf /etc/systemd/system/docker.service
sudo rm -rf /etc/systemd/system/docker.socketdocker.io 在 6 月份之后基本就不能访问了,所以需要自己配置代理,可以找还能运行的代理或者基于 cloudflare 的 worker 自己搭建代理,本次是基于 worker 代理的,比较简单直接部署即可,部署后可自定义自己的域名,部署步骤:GO
部署完成可修改 docker 的访问地址为自定义的域名即可
vim /etc/containers/registries.conf
修改后是这样的:
unqualified-search-registries = ["docker-proxy.b.com"]
prefix = "docker.io"
location = "docker-proxy.b.com"
[engine]
service_destinations = "docker-proxy.b.com:443"前期准备工作已做完,现在可以开始部署了
可通过 wegt 下载,需注意下载完成之后需修改脚本内的 docker.io 为你的代理 docker 地址
export DOMAIN=laf.a.b.com
执行 sh install-on-linux.sh
基本上前期都是一键操作的,laf 提供的部署脚本很完善了
#!/usr/bin/env sh
# Intro: start laf with sealos in linux
# Usage: sh ./install-on-linux.sh <domain>
# TIP: use `sh -x install-on-linux.sh` to debug
# set the first param as domain
DOMAIN="$1"
# if domain is empty string, use default domain
if [ -z "$DOMAIN" ]; then
DOMAIN="127.0.0.1.nip.io"
fi
# Install Sealos
# if apt installed, use `apt` to install
if [ -x "$(command -v apt)" ]; then
echo "deb [trusted=yes] https://apt.fury.io/labring/ /" | tee /etc/apt/sources.list.d/labring.list
apt update
apt install iptables host -y
apt install sealos=4.3.5 -y
apt install jq -y
# fix /etc/hosts overwrite bug in ubuntu while restarting
sed -i "/update_etc_hosts/c \\ - ['update_etc_hosts', 'once-per-instance']" /etc/cloud/cloud.cfg && touch /var/lib/cloud/instance/sem/config_update_etc_hosts
fi
# if yum installed, use `yum` to install
if [ -x "$(command -v yum)" ]; then
cat > /etc/yum.repos.d/labring.repo << EOF
[fury]
name=labring Yum Repo
baseurl=https://yum.fury.io/labring/
enabled=1
gpgcheck=0
EOF
# yum update
yum clean all
yum install -y bind-utils iptables
yum install sealos=4.3.7 -y
yum install jq -y
fi
ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/)
echo "ARCH: $ARCH"
# if sealos not installed
if [ ! -x "$(command -v sealos)" ]; then
echo "sealos not installed"
exit 1
fi
set -e
# pull sealos cluster images
sealos pull labring/kubernetes:v1.24.9
sealos pull labring/flannel:v0.19.0
sealos pull labring/helm:v3.8.2
sealos pull labring/openebs:v1.9.0
sealos pull labring/cert-manager:v1.8.0
sealos pull labring/metrics-server:v0.6.2
sealos pull lafyun/laf:latest
sealos pull docker-proxy.b.com/labring/ingress-nginx:v1.8.1
sealos pull labring/kubeblocks:v0.7.1
# install k8s cluster
sealos run labring/kubernetes:v1.24.9 labring/flannel:v0.19.0 labring/helm:v3.8.2
# taint master node
NODENAME=$(kubectl get nodes -ojsonpath='{.items[0].metadata.name}')
kubectl taint node $NODENAME node-role.kubernetes.io/master- || true
kubectl taint node $NODENAME node-role.kubernetes.io/control-plane- || true
# install required components
sealos run labring/openebs:v1.9.0
sealos run labring/cert-manager:v1.8.0
sealos run labring/metrics-server:v0.6.2
sealos run docker.io/labring/ingress-nginx:v1.8.1 \
-e HELM_OPTS="--set controller.hostNetwork=true --set controller.kind=DaemonSet --set controller.service.enabled=false"
sealos run labring/kubeblocks:v0.7.1
sealos run --env DOMAIN=$DOMAIN --env DB_PV_SIZE=5Gi --env OSS_PV_SIZE=5Gi --env EXTERNAL_HTTP_SCHEMA=http lafyun/laf:latest
基本上部署是一键的,不需要其他的命令或者操作,部署完成需要一些配置,例如https 和内部的一些配置
runtime-exporter 是 laf 的运行时镜像,这个因为使用了 docker.io 的地址,所以部署后肯定会出现 ErrImagePull 类似这样的错误,所以需要手动修改该节点的配置
需要先拉下来 deployment.yaml 配置文件
kubectl get deployment runtime-exporter -o yaml > deployment.yaml -n laf-system
修改 docker.io 为配置的 docker 代理地址后执行:
kubectl apply -f deployment.yaml
可以先删除 runtime-exporter 的 pod,也可以等待执行
kubectl delete pods -l app.kubernetes.io/name=runtime-exporter -n laf-system
这样即可替换
运行完成查看 pod 的状态
kubectl get pods -A
替换完成所有 pod 的运行状态大概是这样的:
此处引用了白夜的部署教程图片

需要首先映射 mongodb 的端口到宿主机,然后通过 ssh 链接
先获取 mongodb 的密码
kubectl get secrets -n laf-system mongodb-conn-credential -o jsonpath='{.data.password}' | base64 --decode
映射端口到宿主机
kubectl port-forward mongodb-mongodb-0 27017:27017 -n laf-system
通过 mongodb compass链接数据库
数据库的链接是 mongodb://root:你的密码@127.0.0.1:27017/sys_db?authSource=admin&replicaSet=mongodb-mongodb&w=majority

这里需要注意,因为服务器配置了不能通过密码只能使用 ssh key 的方式,这里选择SSH Identity File

这里需要修改 runtime collection 中的 image 字段

需要修改为之前设置的 docker 代理地址,不然新建应用会启不起来
其他基本配置完成,现在还需要一个 https 证书,证书一般有两种方式,laf 部署脚本中有安装 cert-manager,我们可以通过 cert-manager 来管理集群的证书,还有一种是直接在手动替换 ingress 的 tls 也就是 laf 使用的网关来完成
cert-manager 部署一直遇到问题,我想使用的是 acme 完成证书的自动更新,但是一直遇到网络问题

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-sys
namespace: lafyun
spec:
ingressClassName: nginx
tls:
- hosts:
- www.lafyun.com
secretName: lafyun-tls-secret
rules:
- host: www.lafyun.com
# ....所以我通过直接使用 acme 签名证书然后修改 tls 来解决的(后来也知道了该网络问题是因为集群内的 DNS 解析有问题导致的),也就是上述脚本的形式,可查看马老板的回复:https://github.com/labring/laf/issues/88
acme 证书申请
./acme.sh --issue --dns dns_ali -d laf.a.com -d "*.laf.a.com" -d "*.oss.laf.a.com" -d "*.site.laf.a.com" -d "oss.a.com"需注意这里需要同时申请 oss.a.com
我就是忘了申请,导致云存储访问有问题
证书安装
./acme.sh --install-cert -d laf.a.com -d "*.laf.a.com" -d "*.oss.laf.a.com" -d "oss.a.com" -d "*.site.laf.a.com" --key-file /root/.acme.sh/laf.a.com_ecc/laf.a.com.key --fullchain-file /root/.acme.sh/laf.a.com_ecc/fullchain.cer导入k8s
kubectl create secret -n laf-system tls laf-cert-secret --cert=/root/.acme.sh/laf.a.com_ecc/fullchain.cer --key=/root/.acme.sh/laf.a.com_ecc/laf.a.com.key查看 ingress
kubectl get ingress --all-namespaces
这个下面的节点都需要手动替换,已创建的应用可删除重新创建
可通过替换配置文件修改 tls 字段
kubectl get ingress minio-console-ingress -o yaml > laf-minio-ingress.yaml -n laf-system
vim laf-minio-ingress.yaml
kubectl apply -f laf-minio-ingress.yaml替换 tls 之后,可通过查看 ingress 查看节点端口是否已更新
kubectl get ingress --all-namespaces
修改数据库
这里同样需要修改数据库中的 tls 字段
修改 Region collection 中的 gatewayConf 中 tls 字段
wildcardCertificateSecretName: laf-cert-secret
这里名字需要与前边导入的 secret name 保持一致
域名证书的更新同样和创建一样的步骤,唯一的区别是需要手动修改 tls
需要先把证书转为base64,然后更新 secret 的形式来完成域名证书的更新
- 先转 base64
base64 -w 0 /root/.acme.sh/laf.a.com_ecc/fullchain.cerbase64 -w 0 /root/.acme.sh/laf.a.com_ecc/laf.marryto.me.key- 获取现有的 secret
kubectl get secret laf-cert-secret -n laf-system -o yaml > laf-cert-secret.yaml- 编辑 YAML 文件:tls 字段更新新的 base 编码
验证更新:
kubectl get secret laf-cert-secret -n laf-system -o yaml
前边有提到有遇到过集群内访问外网失败问题,最开始是以为间歇性的,后来通过开启测试节点 ping 相应域名发现是集群内访问外网有问题导致的
开一个测试节点
kubectl run -it --rm test-dns --image=busybox --restart=Never
执行 ping www.baidu.com 和 ping 39.156.66.10(外部IP,baidu的某一个节点),发现域名无法解析,IP能够Ping通,才找到问题
查了一下网上的解决方案,都是通过修改/etc/resolv.con的方式解决的,我试了下并未解决,后来看到一个取巧的方法,直接修改集群内的 dns 配置,遂试了一下
修改 DNS 配置
kubectl -n kube-system edit cm coredns
将 forward 修改为 8.8.8.8 也就是谷歌的 dns 服务器,然后解决了。。。
最后记得修改完成需要重启 dns 节点
重启 DNS pod
kubectl get pod -n kube-system | grep coredns |awk '{system("kubectl delete pod "$1" -n kube-system")}'
这里的 npm 安装问题一部分是网络问题,还有一部分和上边的集群 dns 问题比较相关,因为集群无法访问外网导致 npm 安装失败,最开始以为是 npmjs 网络问题导致的,后来测试节点 ping npm才发现是自己集群 dns 解析问题

这还是设置了NPM_INSTALL_FLAGS
NPM_INSTALL_FLAGS=--registry=https://registry.npmmirror.com --canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas --sharp_binary_host=https://npmmirror.com/mirrors/sharp --sharp_libvips_binary_host=https://npmmirror.com/mirrors/sharp-libvips需注意,npm还是要设置一下
后来修改了集群 dns 之后安装才成功

到此我们的部署已全部完成,部署工程中基本没啥问题,部署后的配置到时遇到了很大的问题,总结起来基本上是两类问题:网络和k8s,还是需要熟悉k8s的各种操作才能玩转,至于网络问题只是一堵墙罢了。
可以开心的玩转自己的 laf 了。
