Kubernetes | 搭建环境

2020 07 19, Sun

风靡IT界很久的Kubernetes,我因为没有需求,也没有日常维护一套k8s服务器的能力,就一直没有折腾。

最近淘了一个垃圾服务器,E3 v2只要不到2k,加上32G内存2k整。有条件了就瞎玩呗,k8s走起。

方案

废话不多说了,k8s搭建有几种方案。

开发用的单节点

有很多现成工具,比如说

  • minikube
  • Docker for Mac
  • microk8s
  • kind

由于我是希望能跑一些负载真正用起来,而不是开发用的环境,所以我并没有用这些方案。

不过我在Mac上的开发环境用了Docker for Mac,自带k8s环境,只要打开选项就行,比较简单省事儿,不开心的地方在于我Mac空间本来就不大够,结果这一下更惨了。

包括Mac在内的所有平台,如果需要一个开发环境,minikube也挺好的。

生产可用的方案

生产可用的方案主要是在多个节点上搭建master和worker节点。

master节点主要是api server和数据库一类东西,也叫control plane。worker则是跑真正的负载的节点。

一般可以用的工具有

  • kubeadm
  • kops
  • k3s
  • kubespray

等等。

其中kubeadm是官方比较推荐的。一会儿会简单说一下搭建过程,但是这条路我没有完全走通,只是觉得解决了这些问题,其他的方案可以了,kubeadm应该也没问题。

而我用的是k3s,一个比较轻量级的方案,用了k8s官方的大部分代码,剔除了少部分用不到的。

或者公司有钱或者自己有钱的话,也可以直接用云端的k8s方案。

组件

容器这个概念一开始是LXC提出的,后来有了Docker这个Go的杀手级应用然后被广大群众熟悉。其实就是利用内核的特性,隔离一部分资源,让进程以为自己在一个独立的机器上运行。在其他系统上也有类似的概念,比如说BSD的jail,或者Windows后来有的容器。

容器隔离开的资源主要是计算、存储、网络这些。简单说就是

  • PID隔离:认为自己是独立的一些进程,看不到宿主一侧和其他容器里面的其他进程。
  • 内存:完全独立的内存,且有自己的一套共享库。
  • FS:可以使用独立的一套文件系统,且无法访问其他的文件和目录,有自己的挂载点,和宿主这边没有关系。
  • 网络:可以虚拟化一套网络,容器可以和宿主不共用网络。

这套东西Docker用,其他的应用也在用,大家各自写各自的都造一套轮子,有没有意思?没意思啊,所以Docker后来就把这部分分离了出去,叫containerd。

但是其他人可能已经写了类似的东西想要用进来,或者我就是想拓展这个生态,怎么办?社区后来又定义了一套接口,只要符合这个接口的程序,就可以拓展docker或者containerd的能力,主要就是 容器运行时接口 ( Container Runtime Interface ) 容器网络接口 ( Container Network Interface ) 容器安全接口 ( Container Security Interface ) ,分别负责容器要怎么启动一个进程、怎么配置容器的网络和怎么操作容器里面的文件系统,除此之外还有一个OCI,主要是定义了容器的构成,包括什么东西,怎么样描述这些东西。

运行时

其中常见的CRI就包括

  • docker
  • containerd: 去掉docker无用的部分
  • cri-o: 在k8s里面用的比较多
  • kata container: 借助了kvm的力量,相当于轻量级虚拟机做容器,口号是:“容器的速度,虚拟机的安全性“ …

网络

Docker和k8s可以通过插件来拓展网络的能力,解决的大部分主要是进出流量的管理和路由的问题。

  • flannel
  • weave net
  • calico …

搭建过程

k8s搭建其实就是这么几部分:

  • 满足系统基本要求
    • 安装docker或者containerd,最好配置一下cgroup driver
    • 禁用swap
  • 初始化主节点
  • 安装网络插件
  • 把其他节点加入集群
  • (部署应用)

kubeadm

这部分是我一开始尝试的方法,尝试的版本是1.18.5。

简单说就是

  • 主节点: kubeadm init
    • 如果网络选择flannel,那么需要kubeadm init --pod-network-cidr=10.244.0.0/16
    • 如果有多个网卡,建议再加上--apiserver-advertise-address=<ip>选项
    • kubeadm init输出的最后几行会告诉你,可以把配置文件从/etc/kubernetes/admin.conf复制出来,直接复制粘贴几个命令直接执行就行
    • 最后几行还会有一段kubeadm join的命令,复制下来,后面会用
  • 选择其中一个网络插件
    • 大部分都是应用一个k8s的资源定义
    • flannel
      • 项目:https://github.com/coreos/flannel/
      • 直接执行命令也行: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    • weave net:
      • 项目:https://www.weave.works/oss/net/
      • 命令: $ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
    • 其他的我没试过,自己可以查查
  • 挨个在子节点上执行那个kubeadm join的命令

如果子节点在很久以后才加进来,可以执行kubeadm token create --print-join-command,就会打印这么一个命令出来。

k3s

k3s是我最后采用的方案,因为资源占用小,而且刚刚好尝试到这里的时候解决了其他的问题。

k3s的安装相对比较简单,而且内置了网络插件的配置,所以不大需要我们做什么。如果需要配置的话,可以直接看文档,我就用最简单的配置了。

  • 主节点: curl -sfL https://get.k3s.io | sh -
    • 执行以后,cat一下/var/lib/rancher/k3s/server/token,会有一个token,复制一下
  • 从节点: curl -sfL https://get.k3s.io | K3S_URL=https://主节点IP:6443 K3S_TOKEN=刚才复制的token sh -

会默认配置flannel作为网络插件,同时会安装traefik作为ingress controller

客户端一侧要做的事情

kubectl

装一个kubectl是一切的基础。

kube/config

复制出来master节点的/etc/kubernetes/admin.conf内容

  • kubectl: 贴到自己的$HOME/.kube/config文件里面。如果目录不存在就新建一个,如果有现有的要用的文件,建议参考k8s文档配置客户端访问多个集群
  • android/ios: kubenav

dashboard

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/latest/aio/deploy/recommended.yaml

使用方法参考项目页面

自动化部署工具

k8s有不少自动化、简化部署应用的工具。

遇到的坑

Linux本身的问题

虚拟机

用cockpit-machines的时候没有创建网络,所以我手动加了一个Direct Attachment的网卡,结果节点间不能通信。

direct attachment

后来查了资料,似乎是因为直接附加在物理网卡上的这种方法必须把包直接发出去,而不能发给host或者其他guest,导致无法通信。

我一拍脑壳,那也没关系啊,加一个路由,互相之间全部从路由转发。结果还是不行,似乎有的插件会找MAC地址,这样没有arp互相不认MAC的情况,似乎连接还是有问题。

最后还是尝试了一圈,建了一个NAT网络,虚拟机都用这个NAT网络就ok了。

debian

RHEL系列逐渐的不再提供docker,centos8虽然可以用centos7的repo,但是我不觉得这是个好做法,所以我干脆使用了debian buster。这倒不是啥问题。

遇到的问题主要是debian上的iptables实现有两套:iptables-legacy和iptables-nft,默认使用iptables-nft。

结果因为某些我还不是特别明白的原因,网络插件通信有问题。具体来说就是用iptables/iptables-nft和iptables-legacy会产生两套iptables规则。

解决方案:都用iptables-legacy:sudo update-alternatives --set iptables /usr/sbin/iptables-legacy