全世界最简单的kubernetes高可用安装工具sealos!

English docsnode

概述与设计原则

sealos旨在作一个简单干净轻量级稳定的kubernetes安装工具,能很好的支持高可用安装。 其实把一个东西作的功能强大并不难,可是作到极简且灵活可扩展就比较难。
因此在实现时就必需要遵循这些原则。python

sealos特性与优点:nginx

  • 支持离线安装,工具与资源包(二进制程序 配置文件 镜像 yaml文件等)分离,这样不一样版本替换不一样离线包便可
  • 证书延期
  • 使用简单
  • 支持自定义配置
  • 内核负载,极其稳定,由于简单因此排查问题也极其简单
为何不使用ansile

1.0版本确实是用ansible实现,可是用户仍是须要先装ansible,装ansible有须要装python和一些依赖等,为了避免让用户那么麻烦把ansible放到了容器里供用户使用。若是不想配置免密钥使用用户名密码时又须要ssh-pass等,总之不能让我满意,不是我想的极简。git

因此我想就来一个二进制文件工具,没有任何依赖,文件分发与远程命令都经过调用sdk实现因此不依赖其它任何东西,总算让我这个有洁癖的人满意了。github

为何不用keepalived haproxy

haproxy用static pod跑没有太大问题还算好管理,keepalived如今大部分开源ansible脚本都用yum 或者apt等装,这样很是的不可控,有以下劣势:golang

  • 源不一致可能致使版本不一致,版本不一直连配置文件都不同,我曾经检测脚本不生效一直找不到缘由,后来才知道是版本缘由
  • 系统缘由安装不上,依赖库问题某些环境就直接装不上了
  • 看了网上不少安装脚本,不少检测脚本与权重调节方式都不对,直接去检测haproxy进程在不在,实际上是应该去检测apiserver是否是healthz的,api挂了即便haproxy在集群也会不正常了,就是伪高可用了。
  • 管理不方便,经过prometheus对集群进行监控,是能直接监控到static pod的可是用systemd跑又须要单独设置监控,且重启啥的还须要单独拉起。不如kubelet统一管理来的干净简洁。
  • 咱们还出现过keepalived把CPU占满的状况。

因此为了解决这个问题,我把keepalived跑在了容器中(社区提供的镜像基本是不可用的) 改造中间也是发生过不少问题,最终好在解决了。docker

总而言之,累觉不爱,因此在想能不能甩开haproxy和keepalived作出更简单更可靠的方案出来,还真找到了。。。shell

本地负载为何不使用envoy或者nginx

咱们经过本地负载解决高可用问题api

解释一下本地负载,就是在每一个node节点上都启动一个负载均衡,上游就是三个master,负载方式有不少 ipvs envoy nginx等,咱们最终使用内核ipvs服务器

若是使用envoy等须要在每一个节点上都跑一个进程,消耗更多资源,这是我不但愿的。ipvs实际也多跑了一个进程lvscare,可是lvscare只是负责管理ipvs规则,和kube-proxy相似,真正的流量仍是从很稳定的内核走的,不须要再把包走到用户态中去处理。

实现上有个问题会让使用envoy等变得很是尴尬,就是join时若是负载均衡没有创建那是会卡住的,kubelet就不会起,因此为此你须要先把envory起起来,意味着你又不能用static pod去管理它,同上面keepalived宿主机部署同样的问题,用static pod就会相互依赖,逻辑死锁,鸡说要先有蛋,蛋说要先有鸡,最后谁都没有。

使用ipvs就不同,我能够在join以前先把ipvs规则创建好,再去join就能够join进去了,而后对规则进行守护便可。一旦apiserver不可访问了,会自动清理掉全部node上对应的ipvs规则, master恢复正常时添加回来。

为何要定制kubeadm

首先是因为kubeadm把证书时间写死了,因此须要定制把它改为99年,虽然大部分人能够本身去签个新证书,可是咱们仍是不想再依赖个别的工具,就直接改源码了。

其次就是作本地负载时修改kubeadm代码是最方便的,由于在join时咱们须要作两个事,第一join以前先建立好ipvs规则,第二建立static pod,若是这块不去定制kubeadm就把报静态pod目录已存在的错误,忽略这个错误很不优雅。 并且kubeadm中已经提供了一些很好用的sdk供咱们去实现这个功能。

且这样作以后最核心的功能都集成到kubeadm中了,sealos就单单变成分发和执行上层命令的轻量级工具了,增长节点时咱们也就能够直接用kubeadm了

使用教程

安装依赖

安装教程

多master HA:

sealos init --master 192.168.0.2 \
    --master 192.168.0.3 \
    --master 192.168.0.4 \
    --node 192.168.0.5 \
    --user root \
    --passwd your-server-password \
    --version v1.14.1 \
    --pkg-url /root/kube1.14.1.tar.gz

或者单master多node:

sealos init --master 192.168.0.2 \
    --node 192.168.0.5 \
    --user root \
    --passwd your-server-password \
    --version v1.14.1 \
    --pkg-url /root/kube1.14.1.tar.gz

使用免密钥或者密钥对:

sealos init --master 172.16.198.83 \
    --node 172.16.198.84 \
    --pkg-url https://sealyun.oss-cn-beijing.aliyuncs.com/free/kube1.15.0.tar.gz \
    --pk /root/kubernetes.pem # this is your ssh private key file \
    --version v1.15.0
--master   master服务器地址列表
--node     node服务器地址列表
--user     服务器ssh用户名
--passwd   服务器ssh用户密码
--pkg-url  离线包位置,能够放在本地目录,也能够放在一个http服务器上,sealos会wget到安装目标机
--version  kubernetes版本
--pk       ssh私钥地址,配置免密钥默认就是/root/.ssh/id_rsa

Other flags:

--kubeadm-config string   kubeadm-config.yaml kubeadm配置文件,可自定义kubeadm配置文件
 --vip string              virtual ip (default "10.103.97.2") 本地负载时虚拟ip,不推荐修改,集群外不可访问

检查安装是否正常:

[root@iZj6cdqfqw4o4o9tc0q44rZ ~]# kubectl get node
NAME                      STATUS   ROLES    AGE     VERSION
izj6cdqfqw4o4o9tc0q44rz   Ready    master   2m25s   v1.14.1
izj6cdqfqw4o4o9tc0q44sz   Ready    master   119s    v1.14.1
izj6cdqfqw4o4o9tc0q44tz   Ready    master   63s     v1.14.1
izj6cdqfqw4o4o9tc0q44uz   Ready    <none>   38s     v1.14.1
[root@iZj6cdqfqw4o4o9tc0q44rZ ~]# kubectl get pod --all-namespaces
NAMESPACE     NAME                                              READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-5cbcccc885-9n2p8          1/1     Running   0          3m1s
kube-system   calico-node-656zn                                 1/1     Running   0          93s
kube-system   calico-node-bv5hn                                 1/1     Running   0          2m54s
kube-system   calico-node-f2vmd                                 1/1     Running   0          3m1s
kube-system   calico-node-tbd5l                                 1/1     Running   0          118s
kube-system   coredns-fb8b8dccf-8bnkv                           1/1     Running   0          3m1s
kube-system   coredns-fb8b8dccf-spq7r                           1/1     Running   0          3m1s
kube-system   etcd-izj6cdqfqw4o4o9tc0q44rz                      1/1     Running   0          2m25s
kube-system   etcd-izj6cdqfqw4o4o9tc0q44sz                      1/1     Running   0          2m53s
kube-system   etcd-izj6cdqfqw4o4o9tc0q44tz                      1/1     Running   0          118s
kube-system   kube-apiserver-izj6cdqfqw4o4o9tc0q44rz            1/1     Running   0          2m15s
kube-system   kube-apiserver-izj6cdqfqw4o4o9tc0q44sz            1/1     Running   0          2m54s
kube-system   kube-apiserver-izj6cdqfqw4o4o9tc0q44tz            1/1     Running   1          47s
kube-system   kube-controller-manager-izj6cdqfqw4o4o9tc0q44rz   1/1     Running   1          2m43s
kube-system   kube-controller-manager-izj6cdqfqw4o4o9tc0q44sz   1/1     Running   0          2m54s
kube-system   kube-controller-manager-izj6cdqfqw4o4o9tc0q44tz   1/1     Running   0          63s
kube-system   kube-proxy-b9b9z                                  1/1     Running   0          2m54s
kube-system   kube-proxy-nf66n                                  1/1     Running   0          3m1s
kube-system   kube-proxy-q2bqp                                  1/1     Running   0          118s
kube-system   kube-proxy-s5g2k                                  1/1     Running   0          93s
kube-system   kube-scheduler-izj6cdqfqw4o4o9tc0q44rz            1/1     Running   1          2m43s
kube-system   kube-scheduler-izj6cdqfqw4o4o9tc0q44sz            1/1     Running   0          2m54s
kube-system   kube-scheduler-izj6cdqfqw4o4o9tc0q44tz            1/1     Running   0          61s
kube-system   kube-sealyun-lvscare-izj6cdqfqw4o4o9tc0q44uz      1/1     Running   0          86s

清理

sealos clean \
    --master 192.168.0.2 \
    --master 192.168.0.3 \
    --master 192.168.0.4 \
    --node 192.168.0.5 \
    --user root \
    --passwd your-server-password

增长节点

获取 join command, 在master上执行:

kubeadm token create --print-join-command

可使用super kubeadm, 可是join时须要增长一个--master 参数:

cd kube/shell && init.sh
echo "10.103.97.2 apiserver.cluster.local" >> /etc/hosts   # using vip
kubeadm join 10.103.97.2:6443 --token 9vr73a.a8uxyaju799qwdjv \
    --master 10.103.97.100:6443 \
    --master 10.103.97.101:6443 \
    --master 10.103.97.102:6443 \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

也能够用sealos join命令:

sealos join 
    --master 192.168.0.2 \
    --master 192.168.0.3 \
    --master 192.168.0.4 \
    --vip 10.103.97.2 \       
    --node 192.168.0.5 \            
    --user root \             
    --passwd your-server-password \
    --pkg-url /root/kube1.15.0.tar.gz

使用自定义kubeadm配置文件

好比咱们须要在证书里加入 sealyun.com:

先获取配置文件模板:

sealos config -t kubeadm >>  kubeadm-config.yaml.tmpl

修改kubeadm-config.yaml.tmpl,文件便可, 编辑增长 sealyun.com, 注意其它部分不用动,sealos会自动填充模板里面的内容:

apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: {{.Version}}
controlPlaneEndpoint: "apiserver.cluster.local:6443"
networking:
  podSubnet: 100.64.0.0/10
apiServer:
        certSANs:
        - sealyun.com # this is what I added
        - 127.0.0.1
        - apiserver.cluster.local
        {{range .Masters -}}
        - {{.}}
        {{end -}}
        - {{.VIP}}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
        excludeCIDRs: 
        - "{{.VIP}}/32"

使用 --kubeadm-config 指定配置文件模板便可:

sealos init --kubeadm-config kubeadm-config.yaml.tmpl \
    --master 192.168.0.2 \
    --master 192.168.0.3 \
    --master 192.168.0.4 \
    --node 192.168.0.5 \
    --user root \
    --passwd your-server-password \
    --version v1.14.1 \
    --pkg-url /root/kube1.14.1.tar.gz

版本升级

本教程以1.14版本升级到1.15为例,其它版本原理大差不差,懂了这个其它的参考官方教程便可

升级过程

  1. 升级kubeadm,全部节点导入镜像
  2. 升级控制节点
  3. 升级master(控制节点)上的kubelet
  4. 升级其它master(控制节点)
  5. 升级node
  6. 验证集群状态

升级kubeadm

把离线包拷贝到全部节点执行 cd kube/shell && sh init.sh
这里会把kubeadm kubectl kubelet bin文件都更新掉,并且会导入高版本镜像

升级控制节点

kubeadm upgrade plan
kubeadm upgrade apply v1.15.0

重启kubelet:

systemctl restart kubelet

其实kubelet升级简单粗暴,咱们只须要把新版本的kubelet拷贝到/usr/bin下面,重启kubelet service便可,若是程序正在使用不让覆盖那么就停一下kubelet再进行拷贝,kubelet bin文件在 conf/bin 目录下

升级其它控制节点

kubeadm upgrade apply

升级node

驱逐节点(要不要驱逐看状况, 喜欢粗暴的直接来也没啥)

kubectl drain $NODE --ignore-daemonsets

更新kubelet配置:

kubeadm upgrade node config --kubelet-version v1.15.0

而后升级kubelet 同样是替换二进制再重启 kubelet service

systemctl restart kubelet

召回失去的爱情:

kubectl uncordon $NODE

验证

kubectl get nodes

若是版本信息对的话基本就ok了

kubeadm upgrade apply 干了啥

  1. 检查集群是否可升级
  2. 执行版本升级策略 哪些版本之间能够升级
  3. 确认镜像可在
  4. 执行控制组件升级,若是失败就回滚,其实就是apiserver controller manager scheduler 等这些容器
  5. 执行kube-dns 和kube-proxy的升级
  6. 建立新的证书文件,备份老的若是其超过180天

源码编译

由于使用了netlink库,因此推荐在容器内进行编译

docker run --rm -v $GOPATH/src/github.com/fanux/sealos:/go/src/github.com/fanux/sealos -w /go/src/github.com/fanux/sealos -it golang:1.12.7  go build

若是使用go mod 指定经过vendor 编译:

go build -mod vendor

原理

执行流程

  • 经过sftp或者wget把离线安装包拷贝到目标机器上(masters和nodes)
  • 在master0上执行kubeadm init
  • 在其它master上执行kubeadm join 并设置控制面,这个过程会在其它master上起etcd并与master0的etcd组成集群,并启动控制组建(apiserver controller等)
  • join node节点,会在node上配置ipvs规则,配置/etc/hosts等

    有个细节是全部对apiserver进行访问都是经过域名,由于master上链接本身就行,node须要经过虚拟ip连接多个master,这个每一个节点的kubelet与kube-proxy访问apiserver的地址是不同的,而kubeadm又只能在配置文件中指定一个地址,因此使用一个域名可是每一个节点解析不一样。

使用域名的好处还有就是IP地址发生变化时仅须要修改解析便可。

本地内核负载

经过这样的方式实现每一个node上经过本地内核负载均衡访问masters:

+----------+                       +---------------+  virturl server: 127.0.0.1:6443
  | mater0   |<----------------------| ipvs nodes    |    real servers:
  +----------+                      |+---------------+            10.103.97.200:6443
                                    |                             10.103.97.201:6443
  +----------+                      |                             10.103.97.202:6443
  | mater1   |<---------------------+
  +----------+                      |
                                    |
  +----------+                      |
  | mater2   |<---------------------+
  +----------+

在node上起了一个lvscare的static pod去守护这个 ipvs, 一旦apiserver不可访问了,会自动清理掉全部node上对应的ipvs规则, master恢复正常时添加回来。

因此在你的node上加了三个东西,能够直观的看到:

cat /etc/kubernetes/manifests   # 这下面增长了lvscare的static pod
ipvsadm -Ln                     # 能够看到建立的ipvs规则
cat /etc/hosts                  # 增长了虚拟IP的地址解析

定制kubeadm

对kubeadm改动很是少,主要是证书时间延长和join命令的扩展,主要讲讲join命令的改造:

首先join命令增长--master参数用于指定master地址列表

flagSet.StringSliceVar(
    &locallb.LVScare.Masters, "master", []string{},
    "A list of ha masters, --master 192.168.0.2:6443  --master 192.168.0.2:6443  --master 192.168.0.2:6443",
)

这样就能够拿到master地址列表去作ipvs了

若是不是控制节点切不是单master,那么就建立一条ipvs规则,控制节点上不须要建立,连本身的apiserver便可:

if data.cfg.ControlPlane == nil {
            fmt.Println("This is not a control plan")
            if len(locallb.LVScare.Masters) != 0 {
                locallb.CreateLocalLB(args[0])
            }
        }

而后再去建立lvscare static pod去守护ipvs:

if len(locallb.LVScare.Masters) != 0 {
                locallb.LVScareStaticPodToDisk("/etc/kubernetes/manifests")
            }

因此哪怕你不使用sealos,也能够直接用定制过的kubeadm去装集群,只是麻烦一些:

kubeadm配置文件

apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.14.0
controlPlaneEndpoint: "apiserver.cluster.local:6443" # apiserver DNS name
apiServer:
        certSANs:
        - 127.0.0.1
        - apiserver.cluster.local
        - 172.20.241.205
        - 172.20.241.206
        - 172.20.241.207
        - 172.20.241.208
        - 10.103.97.1          # virturl ip
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
        excludeCIDRs: 
        - "10.103.97.1/32" # 注意不加这个kube-proxy会清理你的规则

master0 10.103.97.100 上

echo "10.103.97.100 apiserver.cluster.local" >> /etc/hosts # 解析的是master0的地址
kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs  
mkdir ~/.kube && cp /etc/kubernetes/admin.conf ~/.kube/config
kubectl apply -f https://docs.projectcalico.org/v3.6/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

master1 10.103.97.101 上

echo "10.103.97.100 apiserver.cluster.local" >> /etc/hosts #解析的是master0的地址,为了能正常join进去
kubeadm join 10.103.97.100:6443 --token 9vr73a.a8uxyaju799qwdjv \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 \
    --experimental-control-plane \
    --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07 

sed "s/10.103.97.100/10.103.97.101/g" -i /etc/hosts  # 解析再换成本身的地址,不然就都依赖master0的伪高可用了

master2 10.103.97.102 上,同master1

echo "10.103.97.100 apiserver.cluster.local" >> /etc/hosts
kubeadm join 10.103.97.100:6443 --token 9vr73a.a8uxyaju799qwdjv \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 \
    --experimental-control-plane \
    --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07  

sed "s/10.103.97.100/10.103.97.101/g" -i /etc/hosts

nodes 上

join时加上--master指定master地址列表

echo "10.103.97.1 apiserver.cluster.local" >> /etc/hosts   # 须要解析成虚拟ip
kubeadm join 10.103.97.1:6443 --token 9vr73a.a8uxyaju799qwdjv \
    --master 10.103.97.100:6443 \
    --master 10.103.97.101:6443 \
    --master 10.103.97.102:6443 \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

离线包结构分析

.
├── bin  # 指定版本的bin文件,只须要这三个,其它组件跑容器里
│   ├── kubeadm
│   ├── kubectl
│   └── kubelet
├── conf
│   ├── 10-kubeadm.conf  # 这个文件新版本没用到,我在shell里直接生成,这样能够检测cgroup driver
│   ├── dashboard
│   │   ├── dashboard-admin.yaml
│   │   └── kubernetes-dashboard.yaml
│   ├── heapster
│   │   ├── grafana.yaml
│   │   ├── heapster.yaml
│   │   ├── influxdb.yaml
│   │   └── rbac
│   │       └── heapster-rbac.yaml
│   ├── kubeadm.yaml # kubeadm的配置文件
│   ├── kubelet.service  # kubelet systemd配置文件
│   ├── net
│   │   └── calico.yaml
│   └── promethus
├── images  # 全部镜像包
│   └── images.tar
└── shell
    ├── init.sh  # 初始化脚本
    └── master.sh # 运行master脚本

init.sh脚本中拷贝bin文件到$PATH下面,配置systemd,关闭swap防火墙等,而后导入集群所须要的镜像。

master.sh主要执行了kubeadm init

conf下面有有我须要的如kubeadm的配置文件,calico yaml文件等等

sealos会会调用两者。 因此大部分兼容不一样版本均可以微调脚本作到。

关注咱们就是关注技术干货


kubernetes一键HA

相关文章
相关标签/搜索