前言

为什么要迁移到 K8s?答案是闲着也是贤者。K8s能够提供更集中的资源调度与管理,也能实现更好的不停机更新策略。虽然这些东西对我一个辣鸡网站来说并不是很用得上。

其实更主要的原因是,之前我是通过开多个虚拟机 + docker 来实现一台宿主机上跑N个服务的。但是服务日益增多,我就发现资源碎片化的情况比较严重,有些资源被浪费掉了。这种情况下,更好的解决方案就是将它们统一放置到一台虚拟机上跑。想着既然都在一台虚拟机上跑了,还是要做点什么高可用的措施来方便维护。这么想着就想起了之前了解过的 K8s,节点任务自动调度什么的都听着还不错!还有基于配置文件的维护能够让服务迁移不再成为痛点。

于是乎,就这么愉快的决定了,搭建一个单节点 K8s 集群,实现容器的编排。

架构

  • 使用 k3s 作为 k8s 的发行版
    • 考虑到我这台机器性能也并不是特别强劲,资源也不是特别多,还是用一些资源占用比较少的发行版吧。
  • 一个控制平面,一个 worker 节点
    • 控制平面与工作节点分离到两台机器上,防止单点故障。同时,也能保证我需要维护一个 worker 节点的时候,能够启动另一个 worker 节点实现不停机维护。
  • 使用 nfs 保存持久化数据
    • 既然节点都分离了,那么就需要有一个公共的数据存储位置。为了保证文件安全,万一节点炸了我还能读取到文件,这里使用了NFS+本地磁盘的方式存储文件,而并没有使用什么 S3FS 之类的东西。

但是吧,这些节点都跑在同一台物理机上,其实还是会有单点风险的。不过这也是没有办法的事情,毕竟成本所限。

安装

安装方法直接参考官网教程和对应的博客就可以了:

配置

修改数据存储位置

默认情况下,K3S 会将数据存储于 /var/lib/rancher/k3s 目录下。如果你想要修改这个地址,可以修改 /etc/systemd/system/k3s.service 文件,在启动参数后面加上 --data-dir。其他命令行参数可以参考 K3S 文档的命令行页面

如果你的集群已经在运行了,请先使用 k3s-killall.sh 停止所有的镜像,不然可能会出现文件占用的情况。

防止其他 Pods 调度到控制平面的 Node 上

我们之前为了稳定,将控制平面和工作节点分离了。为了防止新增的 Pod 调度到控制平面所在的节点上,需要为这个节点打上污点。

node-role.kubernetes.io/control-plane 是一个预定义的污点,控制平面的 Pod 已经容忍了这个污点,所以直接为对应节点打上这个污点就可以了:

kubectl taint nodes <节点名称> node-role.kubernetes.io/control-plane:NoSchedule

创建 PV / PVC

基于 NFS 的 PV 和 PVC 创建,官方已经有对应的示例配置文件

创建动态卷制备

由于一个 PV 必须对应一个 PVC,而一个 PVC 最好只分配给同一个 Pod。如果你想要多个 Pod 分离数据存储,那么就需要创建多个PV/PVC,这确实很繁琐。

好在 nfs-subdir-external-provisioner 可以帮我们动态制备卷。这个插件的配置还算简单,按照教程走就可以了。如果你跟我一样是手动安装的话,那么调整下配置,然后直接 apply 即可:

kubectl apply -f rbac.yaml -f deployment.yaml -f class.yaml

这个插件不支持限额,也不支持动态PVC大小调整。如果想要调整,可能要换 dynamic-nfs-provisioner

将已有的 docker compose 配置文件转换为 pod

k8s 提供了 kompose 工具,可以帮助将 docker compose 配置文件转为 pod 的配置文件。注意这个转换工具不一定好用,转完之后肯定需要自己多看看。

通常情况下,一个 docker compose 由多个容器构成,这些容器互相协作,可以通过名字互相访问而不需要暴露端口;而 kompose 默认转换的逻辑是将每个容器都作为一个 deployment,这样的问题是他们只有在声明了 service 的情况下才能被外部访问。而根据之前文章提到的那样,k8s 中最接近 compose 的概念其实是 pod,所以我们其实应该修改上面的文件,把生成的多个 deployment 改成一个 deployment 下有多个 container。

在上述修改后,同一个 pod 内的所有服务共享同一个网络 namespace,所以它们可以通过 127.0.0.1 直接访问。如果你有什么配置文件写了对应的地址,记得更新!

还要注意的是,它默认创建的是 deployment。如果你想要的是 statefulSet,那记得在 apply 之前修改掉。

修改默认的 nginx Ingress 配置规则

如果你像我一样,ingress 外面还套了一层 nginx 的话,你可能想要让 ingress 继续传递 forwarded 的信息:

kind: ConfigMap
apiVersion: v1
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  use-forwarded-headers: "true"

创建 Ingress 映射

如果一切正常的话,你就可以创建一个映射,把服务给暴露出去了:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: [映射名字]
spec:
  rules:
  - host: [要匹配的Host]
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: [转发到的Service名字]
            port:
              number: [Service 端口]
  ingressClassName: nginx

问题

在测试 Ingress 时出错

新增 Ingress 时提示无法访问 Webhook。

使用 kubectl run -it alpine --image alpine --rm 启动一个新镜像,尝试在里面ping对应域名,发现无法正确解析。

Github 的这个 Issue 提示我们有可能是系统的iptables被改乱了,清理下iptable就好了:

systemctl stop k3s (k3s-agent)
nft flush ruleset
systemctl start k3s (k3s-agent)

通用调试流程

如果发现 pod 没起来,那么可以用以下命令看启动的详细信息:

kubectl describe pod

如果怀疑是拉取失败,可以查看工作节点的containerd的日志:

/var/lib/rancher/k3s/agent/containerd/containerd.log

增加虚拟机内存后,kubectl top node 未更新

重启 k3s-agent.service

分类: 未分类

0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注