kubeasz Documentation

使用Ansible脚本安装K8S集群,介绍组件交互原理,方便直接,不受国内网络环境影响

11,407 stars Jinja 1 file · ~30,976 tokens #ansible#calico#cilium#docker#etcd#flannel#k8s#kubeasz
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy kubeasz on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name kubeasz --restart always easzlab/kubeasz:latest

Setup/Network Plugin/Calico

06-安装calico网络组件.md

calico 是k8s社区最流行的网络插件之一,也是k8s-conformance test 默认使用的网络插件,功能丰富,支持network policy;是当前kubeasz项目的默认网络插件。

如果需要安装calico,请在clusters/xxxx/hosts文件中设置变量 CLUSTER_NETWORK="calico",参考这里

bash
roles/calico/
├── tasks
│   └── main.yml
├── templates
│   ├── calico-csr.json.j2
│   ├── calicoctl.cfg.j2
│   ├── calico-v3.15.yaml.j2
│   ├── calico-v3.19.yaml.j2
│   └── calico-v3.8.yaml.j2
└── vars
    └── main.yml

请在另外窗口打开roles/calico/tasks/main.yml文件,对照看以下讲解内容。

创建calico 证书申请

bash
{
  "CN": "calico",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "k8s",
      "OU": "System"
    }
  ]
}

calico 使用客户端证书,所以hosts字段可以为空;后续可以看到calico证书用在四个地方:

  • calico/node 这个docker 容器运行时访问 etcd 使用证书
  • cni 配置文件中,cni 插件需要访问 etcd 使用证书
  • calicoctl 操作集群网络时访问 etcd 使用证书
  • calico/kube-controllers 同步集群网络策略时访问 etcd 使用证书

创建 calico DaemonSet yaml文件和rbac 文件

请对照 roles/calico/templates/calico.yaml.j2文件注释和以下注意内容

  • 详细配置参数请参考calico官方文档
  • 配置ETCD_ENDPOINTS 、CA、证书等,所有{{ }}变量与ansible hosts文件中设置对应
  • 配置集群POD网络 CALICO_IPV4POOL_CIDR={{ CLUSTER_CIDR }}
  • 配置FELIX_DEFAULTENDPOINTTOHOSTACTION=ACCEPT 默认允许Pod到Node的网络流量,更多felix配置选项

安装calico 网络

  • 安装前检查主机名不能有大写字母,只能由小写字母 - . 组成 (name must consist of lower case alphanumeric characters, '-' or '.' (regex: a-z0-9?(.a-z0-9?)*))(calico-node v3.0.6以上已经解决主机大写字母问题)
  • 安装前必须确保各节点主机名不重复 ,calico node name 由节点主机名决定,如果重复,那么重复节点在etcd中只存储一份配置,BGP 邻居也不会建立。
  • 安装之前必须确保kube_master和kube_node节点已经成功部署
  • 轮询等待calico 网络插件安装完成,删除之前kube_node安装时默认cni网络配置

[可选]配置calicoctl工具 [calicoctl.cfg.j2](roles/calico/templates/calicoctl.cfg.j2)

bash
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: "etcdv3"
  etcdEndpoints: {{ ETCD_ENDPOINTS }}
  etcdKeyFile: /etc/calico/ssl/calico-key.pem
  etcdCertFile: /etc/calico/ssl/calico.pem
  etcdCACertFile: {{ ca_dir }}/ca.pem

验证calico网络

执行calico安装成功后可以验证如下:(需要等待镜像下载完成,有时候即便上一步已经配置了docker国内加速,还是可能比较慢,请确认以下容器运行起来以后,再执行后续验证步骤)

bash
kubectl get pod --all-namespaces
NAMESPACE     NAME                                       READY     STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-5c6b98d9df-xj2n4   1/1       Running   0          1m
kube-system   calico-node-4hr52                          2/2       Running   0          1m
kube-system   calico-node-8ctc2                          2/2       Running   0          1m
kube-system   calico-node-9t8md                          2/2       Running   0          1m

查看网卡和路由信息

先在集群创建几个测试pod: kubectl run test --image=busybox --replicas=3 sleep 30000

bash
# 查看网卡信息
ip a
  • 可以看到包含类似cali1cxxx的网卡,是calico为测试pod生成的
  • tunl0网卡现在不用管,是默认生成的,当开启IPIP 特性时使用的隧道
bash
# 查看路由
route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 ens3
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 ens3
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.20.3.64     192.168.1.34    255.255.255.192 UG    0      0        0 ens3
172.20.33.128   0.0.0.0         255.255.255.192 U     0      0        0 *
172.20.33.129   0.0.0.0         255.255.255.255 UH    0      0        0 caliccc295a6d4f
172.20.104.0    192.168.1.35    255.255.255.192 UG    0      0        0 ens3
172.20.166.128  192.168.1.63    255.255.255.192 UG    0      0        0 ens3

查看所有calico节点状态

bash
calicoctl node status
Calico process is running.

IPv4 BGP status
+--------------+-------------------+-------+----------+-------------+
| PEER ADDRESS |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+--------------+-------------------+-------+----------+-------------+
| 192.168.1.34 | node-to-node mesh | up    | 12:34:00 | Established |
| 192.168.1.35 | node-to-node mesh | up    | 12:34:00 | Established |
| 192.168.1.63 | node-to-node mesh | up    | 12:34:01 | Established |
+--------------+-------------------+-------+----------+-------------+

BGP 协议是通过TCP 连接来建立邻居的,因此可以用netstat 命令验证 BGP Peer

bash
netstat -antlp|grep ESTABLISHED|grep 179
tcp        0      0 192.168.1.66:179        192.168.1.35:41316      ESTABLISHED 28479/bird      
tcp        0      0 192.168.1.66:179        192.168.1.34:40243      ESTABLISHED 28479/bird      
tcp        0      0 192.168.1.66:179        192.168.1.63:48979      ESTABLISHED 28479/bird

查看etcd中calico相关信息

因为这里calico网络使用etcd存储数据,所以可以在etcd集群中查看数据

  • calico 3.x 版本默认使用 etcd v3存储,登录集群的一个etcd 节点,查看命令:
bash
# 查看所有calico相关数据
ETCDCTL_API=3 etcdctl --endpoints="http://127.0.0.1:2379" get --prefix /calico
# 查看 calico网络为各节点分配的网段
ETCDCTL_API=3 etcdctl --endpoints="http://127.0.0.1:2379" get --prefix /calico/ipam/v2/host

下一步:[设置 BGP Route Reflector](calico-bgp-rr.md)


Setup/Network Plugin/Calico Bgp Rr

calico 配置 BGP Route Reflectors

Calico作为k8s的一个流行网络插件,它依赖BGP路由协议实现集群节点上的POD路由互通;而路由互通的前提是节点间建立 BGP Peer 连接。BGP 路由反射器(Route Reflectors,简称 RR)可以简化集群BGP Peer的连接方式,它是解决BGP扩展性问题的有效方式;具体来说:

  • 没有 RR 时,所有节点之间需要两两建立连接(IBGP全互联),节点数量增加将导致连接数剧增、资源占用剧增
  • 引入 RR 后,其他 BGP 路由器只需要与它建立连接并交换路由信息,节点数量增加连接数只是线性增加,节省系统资源

calico-node 版本 v3.3 开始支持内建路由反射器,非常方便,因此使用 calico 作为网络插件可以支持大规模节点数的K8S集群。

  • 建议集群节点数大于50时,应用BGP Route Reflectors 特性

前提条件

k8s 集群使用calico网络插件部署成功。本实验环境为按照kubeasz安装的2主2从集群,calico 版本 v3.19.4。

text
$ kubectl get node
NAME           STATUS                     ROLES    AGE    VERSION
192.168.1.1   Ready,SchedulingDisabled   master   178m   v1.13.1
192.168.1.2   Ready,SchedulingDisabled   master   178m   v1.13.1
192.168.1.3   Ready                      node     178m   v1.13.1
192.168.1.4   Ready                      node     178m   v1.13.1
$ kubectl get pod -n kube-system -o wide | grep calico
calico-kube-controllers-77487546bd-jqrlc   1/1     Running   0          179m   192.168.1.3   192.168.1.3   <none>           <none>
calico-node-67t5m                          2/2     Running   0          179m   192.168.1.1   192.168.1.1   <none>           <none>
calico-node-drmhq                          2/2     Running   0          179m   192.168.1.2   192.168.1.2   <none>           <none>
calico-node-rjtkv                          2/2     Running   0          179m   192.168.1.4   192.168.1.4   <none>           <none>
calico-node-xtspl                          2/2     Running   0          179m   192.168.1.3   192.168.1.3   <none>           <none>

查看当前集群中BGP连接情况:可以看到集群中4个节点两两建立了 BGP 连接

text
/* Detailed source-code truncated for AI context efficiency. */

kubeasz 自动安装启用 route reflector

  • 修改/etc/kubeasz/clusters/xxx/config.yml文件,设置配置项CALICO_RR_ENABLED: true
  • 重新执行网络安装 dk ezctl setup xxx 07

执行完成,检查bgp连接验证即可。

附:手动安装route reflector 过程讲解

  • 选择并配置 Route Reflector 节点

首先查看当前集群中的节点:

text
$ calicoctl get node -o wide
NAME     ASN       IPV4              IPV6
k8s401   (64512)   192.168.1.1/24
k8s402   (64512)   192.168.1.2/24
k8s403   (64512)   192.168.1.3/24
k8s404   (64512)   192.168.1.4/24

可以在集群中选择1个或多个节点作为 rr 节点,这里先选择节点:k8s401

bash
#配置routeReflectorClusterID
calicoctl patch node k8s401 -p '{"spec": {"bgp": {"routeReflectorClusterID": "244.0.0.1"}}}'

#配置node label
calicoctl patch node k8s401 -p '{"metadata": {"labels": {"route-reflector": "true"}}}'
  • 配置 BGP node 与 Route Reflector 的连接建立规则
bash
$ cat << EOF | calicoctl create -f -
kind: BGPPeer
apiVersion: projectcalico.org/v3
metadata:
  name: peer-with-route-reflectors
spec:
  nodeSelector: all()
  peerSelector: route-reflector == 'true'
EOF
  • 配置全局禁用全连接(BGP full mesh)
text
$ cat << EOF | calicoctl create -f -
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
  name: default
spec:
  logSeverityScreen: Info
  nodeToNodeMeshEnabled: false
  asNumber: 64512
EOF
  • 验证增加 rr 之后的bgp 连接情况
text
/* Detailed source-code truncated for AI context efficiency. */

可以看到所有其他节点都与所选rr节点建立bgp连接。

  • 再增加一个 rr 节点(略)

步骤同上,添加成功后可以看到所有其他节点都与两个rr节点建立bgp连接,两个rr节点之间也建立bgp连接。对于节点数较多的K8S集群建议配置2-3个 RR 节点。

参考文档


Setup/Network Plugin/Cilium

06-安装cilium网络组件

cilium 是一个革新的网络与安全组件;基于 linux 内核新技术--BPF,它可以透明、零侵入地实现服务间安全策略与可视化,主要优势如下:

  • 支持L3/L4, L7(如:HTTP/gRPC/Kafka)的安全策略
  • 支持基于安全ID而不是地址+端口的传统防火墙策略
  • 支持基于Overlay或Native Routing的扁平多节点pod网络
    • Overlay VXLAN 方式类似于 flannel 的VXLAN后端
  • 高性能负载均衡,支持DSR
  • 支持事件、策略跟踪和监控集成

cilium 项目文档比较完整,建议仔细阅读官网文档

kubeasz 集成安装 cilium

kubeasz 3.3.1 更新重写了cilium 安装流程,使用helm charts 方式,配置文件在 roles/cilium/templates/values.yaml.j2,请阅读原charts中values.yaml 文件后自定义修改。

0.检查系统内核版本

  • Linux kernel >= 4.9.17,如需升级请阅读文档升级内核
  • etcd >= 3.1.0 or consul >= 0.6.4

1.选择cilium网络后安装

  • 参考快速指南,设置/etc/kubeasz/clusters/xxx/hosts文件中变量 CLUSTER_NETWORK="cilium"
  • 下载额外镜像 ./ezdown -X cilium 和 ./ezdown -X network-check
  • 执行集群安装 dk ezctl setup xxx all

注意默认设置未集成cilium_hubble,可以在/etc/kubeasz/clusters/xxx/config.yml配置启用后再开始安装。

  • cilium_connectivity_check:检查集群cilium网络是否工作正常,非常实用
  • cilium_hubble:很酷很实用的监控、策略追踪排查工具

Cilium CLI 和 Hubble CLI 二进制已经默认包含在kubeasz-ext-bin 1.2.0及之后的版本中 https://github.com/kubeasz/dockerfiles/blob/master/kubeasz-ext-bin/Dockerfile

2.验证

一键安装完成后如下,注意cilium_connectivity_check 中带multi-node的检查任务需要多节点集群才能完成

text
/* Detailed source-code truncated for AI context efficiency. */

检查 cilium 节点状态

text
cilium status
    /¯¯\
 /¯¯\__/¯¯\    Cilium:         OK
 \__/¯¯\__/    Operator:       OK
 /¯¯\__/¯¯\    Hubble:         OK
 \__/¯¯\__/    ClusterMesh:    disabled
    \__/

DaemonSet         cilium             Desired: 4, Ready: 4/4, Available: 4/4
Deployment        cilium-operator    Desired: 1, Ready: 1/1, Available: 1/1
Deployment        hubble-relay       Desired: 1, Ready: 1/1, Available: 1/1
Deployment        hubble-ui          Desired: 1, Ready: 1/1, Available: 1/1
Containers:       cilium             Running: 4
                  cilium-operator    Running: 1
                  hubble-relay       Running: 1
                  hubble-ui          Running: 1
Cluster Pods:     17/17 managed by Cilium
Image versions    hubble-relay       easzlab.io.local:5000/cilium/hubble-relay:v1.11.6: 1
                  hubble-ui          easzlab.io.local:5000/cilium/hubble-ui:v0.9.0: 1
                  hubble-ui          easzlab.io.local:5000/cilium/hubble-ui-backend:v0.9.0: 1
                  cilium             easzlab.io.local:5000/cilium/cilium:v1.11.6: 4
                  cilium-operator    easzlab.io.local:5000/cilium/operator-generic:v1.11.6: 1

cilium network policy

cilium network policy 提供了比k8s network policy更丰富的网络安全策略功能,有兴趣的请阅读官网文档,以下是一个有趣的小例子:


Setup/Network Plugin/Cilium Example

开始使用 cilium

以下为简要翻译 cilium doc上的一个应用示例原文,部署在单节点k8s 环境的实践。

部署示例应用

官方文档用几个pod/svc 抽象一个有趣的应用场景(星战迷):星战中帝国方建造了被称为“终极武器”的“死星”,它是一个卫星大小的战斗空间站,它的核心是使用凯伯晶体(Kyber Crystal)的超级激光炮,剧中它的首秀就以完全火力摧毁了“杰达圣城”(Jedha)。下面将用运行于 k8s上的 pod/svc/cilium 等模拟“死星“的一个“飞船登陆”系统安全策略设计。

  • deploy/deathstar:作为控制整个“死星”的飞船登陆管理系统,它暴露一个SVC,提供HTTP REST 接口给飞船请求登陆使用;
  • pod/tiefighter:作为“帝国”方的常规战斗飞船,它会调用上述 HTTP 接口,请求登陆“死星”;
  • pod/xwing:作为“盟军”方的飞行舰,它也尝试调用 HTTP 接口,请求登陆“死星”;

根据文件http-sw-app.yaml 创建 $ kubectl create -f http-sw-app.yaml 后,验证如下:

bash
$ kubectl get pods,svc
NAME                             READY     STATUS    RESTARTS   AGE
pod/deathstar-5fc7c7795d-djf2q   1/1       Running   0          4h
pod/deathstar-5fc7c7795d-hrgst   1/1       Running   0          4h
pod/tiefighter                   1/1       Running   0          4h
pod/xwing                        1/1       Running   0          4h

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/deathstar    ClusterIP   10.68.242.130   <none>        80/TCP    4h
service/kubernetes   ClusterIP   10.68.0.1       <none>        443/TCP   5h

每个 POD 在 cilium 中都表示为 Endpoint,初始每个 Endpoint 的”进出安全策略“状态均为 Disabled,如下:(已省略部分无关 POD 信息)

text
/* Detailed source-code truncated for AI context efficiency. */

检查初始状态

当然“死星”应该只允许“帝国”的飞船着陆,因为没有应用任何策略,所以初始状态下“帝国”和“联盟”的飞船都可以登陆,如下测试:

bash
$ kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed # 成功着陆
$ kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed # 成功着陆

应用 L3/L4 策略

现在我们应用策略,仅让带有标签 org=empire的飞船登陆“死星”;那么带有标签 org=alliance的“联盟”飞船将禁止登陆;这个就是我们熟悉的传统L3/L4 防火墙策略,并跟踪连接(会话)状态;

根据文件sw_l3_l4_policy.yaml 创建 $ kubectl apply -f sw_l3_l4_policy.yaml 后,验证如下:

bash
$ kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed # 成功着陆

$ kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
# 失败超时

查看安全策略

再次执行 cilium endpoint list,可以看到标签带deathstar的 POD 已经应用了 Ingress方向的策略:

text
/* Detailed source-code truncated for AI context efficiency. */

查看具体策略内容 kubectl describe cnp rule1

L7 安全策略

上述的策略可以进行简单的安全防护了,但是“死星”的这个系统还有很多复杂的功能;比如它还提供了一个内部维护接口,如果被不合理调用将带来严重灾难性后果,也许“联盟”勇士劫持了一架“帝国”飞船正在进行这个任务(虽然我们内心希望他能够成功摧毁“死星”)。不幸的是“死星”系统设计者考虑到这个风险,它有办法严格限制每架飞船能够请求的权限。

没有限制飞船请求权限时,如下运行:

bash
$ kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
Panic: deathstar exploded

goroutine 1 [running]:
main.HandleGarbage(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
        /code/src/github.com/empire/deathstar/
        temp/main.go:9 +0x64
main.main()
        /code/src/github.com/empire/deathstar/
        temp/main.go:5 +0x85

限制L7 的安全策略,根据文件sw_l3_l4_l7_policy.yaml 创建 $ kubectl apply -f sw_l3_l4_l7_policy.yaml 后,验证如下:

bash
$ kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed
$ kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
Access denied

我们同样可以使用 kubectl desribe cnp检查更新的策略,或者使用 cilium 命令行:

bash
$ kubectl exec -n kube-system cilium-6t5vx -- cilium policy get
[
  {
    "endpointSelector": {
      "matchLabels": {
        "any:class": "deathstar",
        "any:org": "empire",
        "k8s:io.kubernetes.pod.namespace": "default"
      }
    },
    "ingress": [
      {
        "fromEndpoints": [
          {
            "matchLabels": {
              "any:org": "empire",
              "k8s:io.kubernetes.pod.namespace": "default"
            }
          }
        ],
        "toPorts": [
          {
            "ports": [
              {
                "port": "80",
                "protocol": "TCP"
              }
            ],
            "rules": {
              "http": [
                {
                  "path": "/v1/request-landing",
                  "method": "POST"
                }
              ]
            }
          }
        ]
      }
    ],
    "labels": [
      {
        "key": "io.cilium.k8s.policy.name",
        "value": "rule1",
        "source": "k8s"
      },
      {
        "key": "io.cilium.k8s.policy.namespace",
        "value": "default",
        "source": "k8s"
      }
    ]
  }
]
Revision: 267

我们看到 cilium 可以实现 7层 HTTP 协议的请求方法(GET/PUT/POST等)、路径(/v1/request-landing)等等安全策略;另外,它还可以防护其他应用(如:Kafka, gRPC, Elasticsearch),可以去官网文档示例学习!

参考资料


Setup/Network Plugin/Flannel

06-安装flannel网络组件.md

Flannel是最早应用到k8s集群的网络插件之一,简单高效,且提供多个后端backend模式供选择;本文介绍以DaemonSet Pod方式集成到k8s集群,需要在所有master节点和node节点安装。

kubeasz 集成安装flannel

  • 参考快速指南,设置/etc/kubeasz/clusters/xxx/hosts文件中变量 CLUSTER_NETWORK="flannel"
  • 下载额外镜像 ./ezdown -X flannel
  • 执行集群安装 dk ezctl setup xxx all

配置介绍

Flannel CNI 插件的配置文件可以包含多个plugin 或由其调用其他plugin;Flannel DaemonSet Pod运行以后会生成/run/flannel/subnet.env 文件,例如:

bash
FLANNEL_NETWORK=10.1.0.0/16
FLANNEL_SUBNET=10.1.17.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=true

然后它利用这个文件信息去配置和调用bridge插件来生成容器网络,调用host-local来管理IP地址,例如:

bash
{
	"name": "mynet",
	"type": "bridge",
	"mtu": 1472,
	"ipMasq": false,
	"isGateway": true,
	"ipam": {
		"type": "host-local",
		"subnet": "10.1.17.0/24"
	}
}

请阅读 roles/flannel/templates/kube-flannel.yaml.j2 内容,注意:

验证flannel网络

执行flannel安装成功后可以验证如下:(需要等待镜像下载完成,有时候即便上一步已经配置了docker国内加速,还是可能比较慢,请确认以下容器运行起来以后,再执行后续验证步骤)

bash
# kubectl get pod --all-namespaces
NAMESPACE     NAME                    READY     STATUS    RESTARTS   AGE
kube-system   kube-flannel-ds-m8mzm   1/1       Running   0          3m
kube-system   kube-flannel-ds-mnj6j   1/1       Running   0          3m
kube-system   kube-flannel-ds-mxn6k   1/1       Running   0          3m

在集群创建几个测试pod: kubectl run test --image=busybox --replicas=3 sleep 30000

bash
# kubectl get pod --all-namespaces -o wide|head -n 4
NAMESPACE     NAME                    READY     STATUS    RESTARTS   AGE       IP             NODE
default       busy-5956b54c8b-ld4gb   1/1       Running   0          9m        172.20.2.7     192.168.1.1
default       busy-5956b54c8b-lj9l9   1/1       Running   0          9m        172.20.1.5     192.168.1.2
default       busy-5956b54c8b-wwpkz   1/1       Running   0          9m        172.20.0.6     192.168.1.3

# 查看路由
# ip route
default via 192.168.1.254 dev ens3 onlink 
192.168.1.0/24 dev ens3  proto kernel  scope link  src 192.168.1.1 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown 
172.20.0.0/24 via 192.168.1.3 dev ens3 
172.20.1.0/24 via 192.168.1.2 dev ens3 
172.20.2.0/24 dev cni0  proto kernel  scope link  src 172.20.2.1

在各节点上分别 ping 这三个POD IP地址,确保能通:

bash
ping 172.20.2.7
ping 172.20.1.5
ping 172.20.0.6

Setup/Network Plugin/Kube Ovn

06-安装kube-ovn网络组件.md

(以下文档暂未更新,以插件官网文档为准)

由灵雀云开源的网络组件 kube-ovn,将已被 openstack 社区采用的成熟网络虚拟化技术 ovs/ovn 引入 kubernetes 平台;为 kubernetes 网络打开了新的大门,令人耳目一新;强烈推荐大家试用该网络组件,反馈建议以帮助项目早日走向成熟。

特性介绍

kube-ovn 提供了针对企业应用场景下容器网络实用功能,并为实现更高级的网络管理控制提供了可能性;现有主要功能:

  • 1.Namespace 和子网的绑定,以及子网间的访问控制;
  • 2.静态IP分配;
  • 3.动态QoS;
  • 4.分布式和集中式网关;
  • 5.内嵌 LoadBalancer;
  • 6.Pod IP对外直接暴露
  • 7.流量镜像
  • 8.IPv6

kubeasz 集成安装 kube-ovn

kube-ovn 的安装十分简单,详见项目的安装文档;基于 kubeasz,以下两步将安装一个集成了 kube-ovn 网络的 k8s 集群;

  • 在 ansible hosts 中设置变量 CLUSTER_NETWORK="kube-ovn"
  • 执行安装 ansible-playbook 90.setup.yml 或者 ezctl setup

kubeasz 项目为kube-ovn网络生成的 ansible role 如下:

bash
roles/kube-ovn
├── defaults
│   └── main.yml		# kube-ovn 相关配置文件
├── tasks
│   └── main.yml		# 安装执行文件
└── templates
    ├── crd.yaml.j2	        # crd 模板
    ├── kube-ovn.yaml.j2	# kube-ovn yaml 模板
    └── ovn.yaml.j2		    # ovn yaml 模板

安装成功后,可以验证所有 k8s 集群功能正常,查看集群的 pod 网络如下:

text
/* Detailed source-code truncated for AI context efficiency. */

直观上 kube-ovn 与传统 k8s 网络(flannel/calico等)比较最大的不同是 pod 子网的分配:

  • 传统网络插件下,集群中 pod 一般是不同 node 节点分配不同的子网;然后通过 overlay 等技术打通不同 node 节点的 pod 子网;
  • kube-ovn 中 pod 网络根据其所在的 namespace 而定; namespace 在创建时可以根据 annotation 来配置它的子网/网关等参数;默认使用 10.16.0.0/16 的子网;

测试 namespace 子网分配

新建一个 subnet 并绑定 namespace 测试分配一个新的 pod 子网

text
# 创建一个 namespace: test-ns
$ cat > test-ns.yaml << EOF
apiVersion: v1
kind: Namespace
metadata:
  annotations:
  name: test-ns
EOF
$ kubectl apply -f test-ns.yaml

# 创建一个 subnet: test-subnet 并绑定 namespace test-ns
$ cat > test-subnet.yaml << EOF
apiVersion: kubeovn.io/v1
kind: Subnet
metadata:
  name: test-subnet
spec:
  protocol: IPv4
  default: false
  namespaces:
  - test-ns
  cidrBlock: 10.17.0.0/24
  gateway: 10.17.0.1
  excludeIps:
  - 10.17.0.1..10.17.0.10
EOF
$ kubectl apply -f test-subnet.yaml

# 在 test-ns 中创建 nginx 部署
$ kubectl run -n test-ns nginx --image=nginx --replicas=2 --port=80 --expose

# 在 default 中创建 busy 客户端
$ kubectl run busy --image=busybox sleep 360000

创建成功后,查看 pod 地址的分配,可以看到确实 test-ns 中 pod 使用新的子网,而 default 中 pod 使用了默认子网,并验证 pod 之间的联通性(默认可通)

text
/* Detailed source-code truncated for AI context efficiency. */
  • 更多的测试(pod网络QOS限速,namespace网络隔离等)请参考 kube-ovn 项目说明文档

延伸阅读


Setup/Network Plugin/Kube Router

kube-router 网络组件

(以下文档暂未更新,以插件官网文档为准)

kube-router是一个简单、高效的网络插件,它提供一揽子解决方案:

  • 基于GoBGP 提供Pod 网络互联(Routing)
  • 使用ipsets优化的iptables 提供网络策略支持(Firewall/NetworkPolicy)
  • 基于IPVS/LVS 提供高性能服务代理(Service Proxy)(注:由于 k8s 新版本中 ipvs 已可用,因此这里不选择启用kube-router基于ipvs的service proxy)

更多介绍请前往https://github.com/cloudnativelabs/kube-router

配置

本项目提供多种网络插件可选,如果需要安装kube-router,请在/etc/kubeasz/hosts文件中设置变量 CLUSTER_NETWORK="kube-router",更多设置请查看roles/kube-router/defaults/main.yml

  • kube-router需要在所有master节点和node节点安装

安装

  • 单步安装已经集成:ansible-playbook 90.setup.yml
  • 分步安装请执行:ansible-playbook 06.network.yml

验证

  • 1.pod间网络联通性:略

  • 2.host路由表

bash
# master上路由
root@master1:~$ ip route
...
172.20.1.0/24 via 192.168.1.2 dev ens3  proto 17 
172.20.2.0/24 via 192.168.1.3 dev ens3  proto 17 
...

# node3上路由
root@node3:~$ ip route
... 
172.20.0.0/24 via 192.168.1.1 dev ens3  proto 17 
172.20.1.0/24 via 192.168.1.2 dev ens3  proto 17 
172.20.2.0/24 dev kube-bridge  proto kernel  scope link  src 172.20.2.1 
...
  • 3.bgp连接状态
bash
# master上
root@master1:~$ netstat -antlp|grep router|grep LISH|grep 179
tcp        0      0 192.168.1.1:179        192.168.1.3:58366      ESTABLISHED 26062/kube-router
tcp        0      0 192.168.1.1:42537      192.168.1.2:179        ESTABLISHED 26062/kube-router

# node3上
root@node3:~$ netstat -antlp|grep router|grep LISH|grep 179
tcp        0      0 192.168.1.3:58366      192.168.1.1:179        ESTABLISHED 18897/kube-router
tcp        0      0 192.168.1.3:179        192.168.1.2:43928      ESTABLISHED 18897/kube-router
  • 4.NetworkPolicy有效性,验证参照这里

  • 5.ipset列表查看

bash
$ ipset list
...
Name: kube-router-pod-subnets
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 65536 timeout 0
Size in memory: 672
References: 2
Members:
172.20.1.0/24 timeout 0
172.20.2.0/24 timeout 0
172.20.0.0/24 timeout 0

Name: kube-router-node-ips
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536 timeout 0
Size in memory: 416
References: 1
Members:
192.168.1.1 timeout 0
192.168.1.2 timeout 0
192.168.1.3 timeout 0
...

Setup/Network Plugin/Network Check

network-check

网络测试组件,根据cilium connectivity-check 脚本修改而来;利用cronjob 定期检测集群各节点、容器、serviceip、nodeport等之间的网络联通性;可以方便的判断当前集群网络是否正常。

目前检测如下:

bash
kubectl get cronjobs.batch -n network-test
NAME                                  SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
test01-pod-to-container               */5 * * * *   False     0        3m19s           6d3h
test02-pod-to-node-nodeport           */5 * * * *   False     0        3m19s           6d3h
test03-pod-to-multi-node-clusterip    */5 * * * *   False     1        6d3h            6d3h
test04-pod-to-multi-node-headless     */5 * * * *   False     1        6d3h            6d3h
test05-pod-to-multi-node-nodeport     */5 * * * *   False     1        6d3h            6d3h
test06-pod-to-external-1111           */5 * * * *   False     0        3m19s           6d3h
test07-pod-to-external-fqdn-baidu     */5 * * * *   False     0        3m19s           6d3h
test08-host-to-multi-node-clusterip   */5 * * * *   False     1        6d3h            6d3h
test09-host-to-multi-node-headless    */5 * * * *   False     1        6d3h            6d3h
  • 带multi-node的测试需要多节点集群才能运行,如果单节点集群,测试pod会处于Pending状态
  • 带external的测试需要节点能够访问互联网,否则测试会失败

启用网络检测

  • 下载额外容器镜像 ./ezdown -X network-check

  • 配置集群,在配置文件/etc/kubeasz/clusters/xxx/config.yml (xxx为集群名) 修改如下选项

text
# network-check 自动安装
network_check_enabled: true
network_check_schedule: "*/5 * * * *"  # 检测频率,默认5分钟执行一次
  • 安装网络检测插件 docker exec -it kubeasz ezctl setup xxx 07

检查测试结果

大约等待5分钟左右,查看运行结果,如果pod 状态为Completed 表示检测正常通过。

text
kubectl get pod -n network-test
NAME                                                 READY   STATUS      RESTARTS   AGE
echo-server-58d7bb7f6-77ps6                          1/1     Running     0          6d4h
echo-server-host-cc87c966d-bk57t                     1/1     Running     0          6d4h
test01-pod-to-container-27606775-q6xlb               0/1     Completed   0          3m10s
test02-pod-to-node-nodeport-27606775-x2v5d           0/1     Completed   0          3m10s
test03-pod-to-multi-node-clusterip-27597895-cbq8d    0/1     Pending     0          6d4h
test04-pod-to-multi-node-headless-27597895-qzsgz     0/1     Pending     0          6d4h
test05-pod-to-multi-node-nodeport-27597895-kb5r7     0/1     Pending     0          6d4h
test06-pod-to-external-1111-27606775-p6v8s           0/1     Completed   0          3m10s
test07-pod-to-external-fqdn-baidu-27606775-qdfwd     0/1     Completed   0          3m10s
test08-host-to-multi-node-clusterip-27597895-qsgn9   0/1     Pending     0          6d4h
test09-host-to-multi-node-headless-27597895-hpkt5    0/1     Pending     0          6d4h
  • pod 状态为Completed 表示检测正常通过
  • pod 状态为Pending 表示该检测需要多节点的k8s集群才会运行

禁用网络检测

如果集群已经开启网络检测,检测结果符合预期,并且不想继续循环检测时,只要删除对应namespace即可

text
kubectl delete ns network-test

Setup/00 Planning And Overall Intro

00-集群规划和基础参数设定

HA architecture

  • 注意1:确保各节点时区设置一致、时间同步。 如果你的环境没有提供NTP 时间同步,推荐集成安装chrony
  • 注意2:确保在干净的系统上开始安装,不要使用曾经装过kubeadm或其他k8s发行版的环境
  • 注意3:建议操作系统升级到新的稳定内核,请结合阅读内核升级文档
  • 注意4:在公有云上创建多主集群,请结合阅读在公有云上部署 kubeasz

高可用集群所需节点配置如下

角色 数量 描述
部署节点 1 运行ansible/ezctl命令,一般复用第一个master节点
etcd节点 3 注意etcd集群需要1,3,5,...奇数个节点,一般复用master节点
master节点 2 高可用集群至少2个master节点
node节点 n 运行应用负载的节点,可根据需要提升机器配置/增加节点数

机器配置:

  • master节点:4c/8g内存/50g硬盘
  • worker节点:建议8c/32g内存/200g硬盘以上

注意:默认配置下容器运行时和kubelet会占用/var的磁盘空间,如果磁盘分区特殊,可以设置config.yml中的容器运行时和kubelet数据目录:CONTAINERD_STORAGE_DIR DOCKER_STORAGE_DIR KUBELET_ROOT_DIR

在 kubeasz 2x 版本,多节点高可用集群安装可以使用2种方式

  • 1.按照本文步骤先规划准备,预先配置节点信息后,直接安装多节点高可用集群
  • 2.先部署单节点集群 AllinOne部署,然后通过 节点添加 扩容成高可用集群

部署步骤

以下示例创建一个4节点的多主高可用集群,文档中命令默认都需要root权限运行。

1.基础系统配置

  • 2c/4g内存/40g硬盘(该配置仅测试用)
  • 最小化安装Ubuntu 16.04 server或者CentOS 7 Minimal
  • 配置基础网络、更新源、SSH登录等

2.在每个节点安装依赖工具

推荐使用ansible in docker 容器化方式运行,无需安装额外依赖。

3.准备ssh免密登陆

配置从部署节点能够ssh免密登陆所有节点,并且设置python软连接

bash
#$IP为所有节点地址包括自身,按照提示输入yes 和root密码
ssh-copy-id $IP

4.在部署节点编排k8s安装

  • 4.1 下载项目源码、二进制及离线镜像

下载工具脚本ezdown,举例使用kubeasz版本3.5.0

bash
export release=3.5.0
wget https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
chmod +x ./ezdown

下载kubeasz代码、二进制、默认容器镜像(更多关于ezdown的参数,运行./ezdown 查看)

bash
# 国内环境
./ezdown -D
# 海外环境
#./ezdown -D -m standard

【可选】下载额外容器镜像(cilium,flannel,prometheus等)

bash
# 按需下载
./ezdown -X flannel
./ezdown -X prometheus
...

【可选】下载离线系统包 (适用于无法使用yum/apt仓库情形)

bash
./ezdown -P

上述脚本运行成功后,所有文件(kubeasz代码、二进制、离线镜像)均已整理好放入目录/etc/kubeasz

  • 4.2 创建集群配置实例
bash
# 容器化运行kubeasz
./ezdown -S

# 创建新集群 k8s-01
docker exec -it kubeasz ezctl new k8s-01
2021-01-19 10:48:23 DEBUG generate custom cluster files in /etc/kubeasz/clusters/k8s-01
2021-01-19 10:48:23 DEBUG set version of common plugins
2021-01-19 10:48:23 DEBUG cluster k8s-01: files successfully created.
2021-01-19 10:48:23 INFO next steps 1: to config '/etc/kubeasz/clusters/k8s-01/hosts'
2021-01-19 10:48:23 INFO next steps 2: to config '/etc/kubeasz/clusters/k8s-01/config.yml'

然后根据提示配置'/etc/kubeasz/clusters/k8s-01/hosts' 和 '/etc/kubeasz/clusters/k8s-01/config.yml':根据前面节点规划修改hosts 文件和其他集群层面的主要配置选项;其他集群组件等配置项可以在config.yml 文件中修改。

  • 4.3 开始安装
    如果你对集群安装流程不熟悉,请阅读项目首页 安装步骤 讲解后分步安装,并对 每步都进行验证
bash
#建议使用alias命令,查看~/.bashrc 文件应该包含:alias dk='docker exec -it kubeasz'
source ~/.bashrc

# 一键安装,等价于执行docker exec -it kubeasz ezctl setup k8s-01 all
dk ezctl setup k8s-01 all

# 或者分步安装,具体使用 dk ezctl help setup 查看分步安装帮助信息
# dk ezctl setup k8s-01 01
# dk ezctl setup k8s-01 02
# dk ezctl setup k8s-01 03
# dk ezctl setup k8s-01 04
...

更多ezctl使用帮助,请参考这里

后一篇


Setup/01 CA And Prerequisite

01-创建证书和环境准备

本步骤主要完成:

  • (deprecated) role:os-harden,(未更新上游项目,未验证最新k8s集群安装,不建议启用)可选系统加固,符合linux安全基线,详见upstream
  • (optional) role:chrony,可选集群节点时间同步
  • role:deploy,创建CA证书、集群组件访问apiserver所需的各种kubeconfig
  • role:prepare,系统基础环境配置、分发CA证书、kubectl客户端安装

deploy 角色

主要任务讲解:roles/deploy/tasks/main.yml

创建 CA 证书

kubernetes 系统各组件需要使用 TLS 证书对通信进行加密,使用 CloudFlare 的 PKI 工具集生成自签名的 CA 证书,用来签名后续创建的其它 TLS 证书。参考阅读

根据认证对象可以将证书分成三类:服务器证书server cert,客户端证书client cert,对等证书peer cert(既是server cert又是client cert),在kubernetes 集群中需要的证书种类如下:

  • etcd 节点需要标识自己服务的server cert,也需要client cert与etcd集群其他节点交互,当然可以分别指定2个证书,为方便这里使用一个对等证书
  • master 节点需要标识 apiserver服务的server cert,也需要client cert连接etcd集群,这里也使用一个对等证书
  • kubectl calico kube-proxy 只需要client cert,因此证书请求中 hosts 字段可以为空
  • kubelet 需要标识自己服务的server cert,也需要client cert请求apiserver,也使用一个对等证书

整个集群要使用统一的CA 证书,只需要在ansible控制端创建,然后分发给其他节点;为了保证安装的幂等性,如果已经存在CA 证书,就跳过创建CA 步骤

创建 CA 配置文件 [ca-config.json.j2](../../roles/deploy/templates/ca-config.json.j2)

bash
{
  "signing": {
    "default": {
      "expiry": "{{ CERT_EXPIRY }}"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "{{ CERT_EXPIRY }}"
      },
      "kcfg": {
        "usages": [
            "signing",
            "key encipherment",
            "client auth"
        ],
        "expiry": "{{ CUSTOM_EXPIRY }}"
      }
    }
  }
}
  • signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE;
  • server auth:表示可以用该 CA 对 server 提供的证书进行验证;
  • client auth:表示可以用该 CA 对 client 提供的证书进行验证;
  • profile kubernetes 包含了server auth和client auth,所以可以签发三种不同类型证书;expiry 证书有效期,默认50年
  • profile kcfg 在后面客户端kubeconfig证书管理中用到

创建 CA 证书签名请求 [ca-csr.json.j2](../../roles/deploy/templates/ca-csr.json.j2)

bash
{
  "CN": "kubernetes-ca",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "k8s",
      "OU": "System"
    }
  ],
  "ca": {
    "expiry": "876000h"
  }
}
  • ca expiry 指定ca证书的有效期,默认100年

生成CA 证书和私钥

bash
cfssl gencert -initca ca-csr.json | cfssljson -bare ca

生成 kubeconfig 配置文件

kubectl使用~/.kube/config 配置文件与kube-apiserver进行交互,且拥有管理 K8S集群的完全权限,

准备kubectl使用的admin 证书签名请求 admin-csr.json.j2

bash
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
  • kubectl 使用客户端证书可以不指定hosts 字段
  • 证书请求中 O 指定该证书的 Group 为 system:masters,而 RBAC 预定义的 ClusterRoleBinding 将 Group system:masters 与 ClusterRole cluster-admin 绑定,这就赋予了kubectl所有集群权限
bash
$ kubectl describe clusterrolebinding cluster-admin
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate=true
Role:
  Kind:  ClusterRole
  Name:  cluster-admin
Subjects:
  Kind   Name            Namespace
  ----   ----            ---------
  Group  system:masters

生成 admin 用户证书

text
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin

生成 ~/.kube/config 配置文件

使用kubectl config 生成kubeconfig 自动保存到 ~/.kube/config,生成后 cat ~/.kube/config可以验证配置文件包含 kube-apiserver 地址、证书、用户名等信息。

text
kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=127.0.0.1:8443
kubectl config set-credentials admin --client-certificate=admin.pem --embed-certs=true --client-key=admin-key.pem
kubectl config set-context kubernetes --cluster=kubernetes --user=admin
kubectl config use-context kubernetes

生成 kube-proxy.kubeconfig 配置文件

创建 kube-proxy 证书请求

bash
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • kube-proxy 使用客户端证书可以不指定hosts 字段
  • CN 指定该证书的 User 为 system:kube-proxy,预定义的 ClusterRoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier 绑定,授予了调用 kube-apiserver Proxy 相关 API 的权限;
bash
$ kubectl describe clusterrolebinding system:node-proxier
Name:         system:node-proxier
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate=true
Role:
  Kind:  ClusterRole
  Name:  system:node-proxier
Subjects:
  Kind  Name               Namespace
  ----  ----               ---------
  User  system:kube-proxy

生成 system:kube-proxy 用户证书

text
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy

生成 kube-proxy.kubeconfig

使用kubectl config 生成kubeconfig 自动保存到 kube-proxy.kubeconfig

text
kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=127.0.0.1:8443 --kubeconfig=kube-proxy.kubeconfig
kubectl config set-credentials kube-proxy --client-certificate=kube-proxy.pem --embed-certs=true --client-key=kube-proxy-key.pem --kubeconfig=kube-proxy.kubeconfig
kubectl config set-context default --cluster=kubernetes --user=kube-proxy --kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

创建kube-controller-manager 和 kube-scheduler 组件的kubeconfig 文件

过程与创建kube-proxy.kubeconfig 类似,略。

prepare 角色

请在另外窗口打开roles/prepare/tasks/main.yml 文件,比较简单直观

  1. 设置基础操作系统软件和系统参数,请阅读脚本中的注释内容
  2. 创建一些基础文件目录、环境变量以及添加本地镜像仓库easzlab.io.local的域名解析
  3. 分发kubeconfig等配置文件

后一篇


Setup/02 Install Etcd

02-安装etcd集群

kuberntes 集群使用 etcd 存储所有数据,是最重要的组件之一,注意 etcd集群需要奇数个节点(1,3,5...),本文档使用3个节点做集群。

请在另外窗口打开roles/etcd/tasks/main.yml 文件,对照看以下讲解内容。

创建etcd证书

注意:证书是在部署节点创建好之后推送到目标etcd节点上去的,以增加ca证书的安全性

创建ectd证书请求 etcd-csr.json.j2

bash
{
  "CN": "etcd",
  "hosts": [
{% for host in groups['etcd'] %}
    "{{ host }}",
{% endfor %}
    "127.0.0.1"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • etcd使用对等证书,hosts 字段必须指定授权使用该证书的 etcd 节点 IP,这里枚举了所有ectd节点的地址

创建etcd 服务文件 [etcd.service.j2](../../roles/etcd/templates/etcd.service.j2)

bash
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory={{ ETCD_DATA_DIR }}
ExecStart={{ bin_dir }}/etcd \
  --name=etcd-{{ inventory_hostname }} \
  --cert-file={{ ca_dir }}/etcd.pem \
  --key-file={{ ca_dir }}/etcd-key.pem \
  --peer-cert-file={{ ca_dir }}/etcd.pem \
  --peer-key-file={{ ca_dir }}/etcd-key.pem \
  --trusted-ca-file={{ ca_dir }}/ca.pem \
  --peer-trusted-ca-file={{ ca_dir }}/ca.pem \
  --initial-advertise-peer-urls=https://{{ inventory_hostname }}:2380 \
  --listen-peer-urls=https://{{ inventory_hostname }}:2380 \
  --listen-client-urls=https://{{ inventory_hostname }}:2379,http://127.0.0.1:2379 \
  --advertise-client-urls=https://{{ inventory_hostname }}:2379 \
  --initial-cluster-token=etcd-cluster-0 \
  --initial-cluster={{ ETCD_NODES }} \
  --initial-cluster-state={{ CLUSTER_STATE }} \
  --data-dir={{ ETCD_DATA_DIR }} \
  --wal-dir={{ ETCD_WAL_DIR }} \
  --snapshot-count=50000 \
  --auto-compaction-retention=1 \
  --auto-compaction-mode=periodic \
  --max-request-bytes=10485760 \
  --quota-backend-bytes=8589934592
Restart=always
RestartSec=15
LimitNOFILE=65536
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target
  • 完整参数列表请使用 etcd --help 查询
  • 注意etcd 即需要服务器证书也需要客户端证书,为方便使用一个peer 证书代替两个证书
  • --initial-cluster-state 值为 new 时,--name 的参数值必须位于 --initial-cluster 列表中
  • --snapshot-count --auto-compaction-retention 一些性能优化参数,请查阅etcd项目文档
  • 设置--data-dir 和--wal-dir 使用不同磁盘目录,可以避免磁盘io竞争,提高性能,具体请参考etcd项目文档

验证etcd集群状态

  • systemctl status etcd 查看服务状态
  • journalctl -u etcd 查看运行日志
  • 在任一 etcd 集群节点上执行如下命令
text
/* Detailed source-code truncated for AI context efficiency. */
  • 所有节点可达:etcdctl endpoint health 对所有三个节点都返回 healthy。
  • 有且仅有一个领导者:etcdctl endpoint status 显示一个节点 is leader: true,另外两个节点 is leader: false。
  • Raft 任期一致:所有三个节点的 raft term 值完全相同。
  • Raft 索引同步:所有节点的 raft index 值相差不大(跟随者与领导者的差距在可接受范围内)。
  • 无活跃告警:etcdctl alarm list 返回空。
  • 节点间网络稳定:没有频繁的领导者切换(通过监控 etcd_server_leader_changes_seen_total 指标)。
  • 磁盘空间充足:没有 NOSPACE 告警,且磁盘使用率在安全阈值内(例如低于80%)。

磁盘性能

快速的磁盘是 etcd 部署性能和稳定性的最关键因素。

磁盘速度慢会增加 etcd 请求延迟,并可能损害集群稳定性。由于 etcd 的共识协议依赖于将元数据持久地存储到日志中,因此大多数 etcd 集群成员必须将每个请求写入磁盘。此外,etcd 还会逐步将其状态检查点写入磁盘,以便截断此日志。如果这些写入耗时过长,心跳可能会超时并触发选举,从而损害集群的稳定性。通常,要判断磁盘速度是否足以满足 etcd 的要求,可以使用fio等基准测试工具。

etcd 对磁盘写入延迟非常敏感。通常需要 50 的顺序 IOPS(例如,7200 RPM 磁盘)。对于负载较重的集群,建议使用 500 的顺序 IOPS(例如,典型的本地 SSD 或高性能虚拟化块设备)。请注意,大多数云提供商发布的是并发 IOPS,而不是顺序 IOPS;发布的并发 IOPS 可能比顺序 IOPS 高出 10 倍。要测量实际的顺序 IOPS,我们建议使用磁盘基准测试工具,例如diskbench或fio。

bash
# 测试示例
mkdir test-data
fio --rw=write --ioengine=sync --fdatasync=1 --directory=test-data --size=2200m --bs=2300 --name=mytest

后一篇


Setup/03 Container Runtime

03-安装容器运行时

项目根据k8s版本提供不同的默认容器运行时:

  • k8s 版本 < 1.24 时,支持docker containerd 可选
  • k8s 版本 >= 1.24 时,仅支持 containerd

安装containerd

作为 CNCF 毕业项目,containerd 致力于提供简洁、可靠、可扩展的容器运行时;它被设计用来集成到 kubernetes 等系统使用,而不是像 docker 那样独立使用。

kubeasz 集成安装 containerd

  • 注意:k8s 1.24以后,项目已经设置默认容器运行时为 containerd,无需手动修改
  • 执行安装:分步安装ezctl setup xxxx 03,一键安装ezctl setup xxxx all

命令对比

命令 docker crictl(推荐) ctr
查看容器列表 docker ps crictl ps ctr -n k8s.io c ls
查看容器详情 docker inspect crictl inspect ctr -n k8s.io c info
查看容器日志 docker logs crictl logs 无
容器内执行命令 docker exec crictl exec 无
挂载容器 docker attach crictl attach 无
容器资源使用 docker stats crictl stats 无
创建容器 docker create crictl create ctr -n k8s.io c create
启动容器 docker start crictl start ctr -n k8s.io run
停止容器 docker stop crictl stop 无
删除容器 docker rm crictl rm ctr -n k8s.io c del
查看镜像列表 docker images crictl images ctr -n k8s.io i ls
查看镜像详情 docker inspect crictl inspecti 无
拉取镜像 docker pull crictl pull ctr -n k8s.io i pull
推送镜像 docker push 无 ctr -n k8s.io i push
删除镜像 docker rmi crictl rmi ctr -n k8s.io i rm
查看Pod列表 无 crictl pods 无
查看Pod详情 无 crictl inspectp 无
启动Pod 无 crictl runp 无
停止Pod 无 crictl stopp 无

后一篇


Setup/04 Install Kube Master

04-安装kube_master节点

部署master节点主要包含三个组件apiserver scheduler controller-manager,其中:

  • apiserver提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等
    • 只有API Server才直接操作etcd
    • 其他模块通过API Server查询或修改数据
    • 提供其他模块之间的数据交互和通信的枢纽
  • scheduler负责分配调度Pod到集群内的node节点
    • 监听kube-apiserver,查询还未分配Node的Pod
    • 根据调度策略为这些Pod分配节点
  • controller-manager由一系列的控制器组成,它通过apiserver监控整个集群的状态,并确保集群处于预期的工作状态

高可用机制

  • apiserver 无状态服务,可以通过外部负载均衡实现高可用,如项目采用的两种高可用架构:HA-1x (#584)和 HA-2x (#585)
  • controller-manager 组件启动时会进行类似选举(leader);当多副本存在时,如果原先leader挂掉,那么会选举出新的leader,从而保证高可用;
  • scheduler 类似选举机制

安装流程

bash
cat playbooks/04.kube-master.yml
- hosts: kube_master
  roles:
  - kube-lb        # 四层负载均衡,监听在127.0.0.1:6443,转发到真实master节点apiserver服务
  - kube-master    #
  - kube-node      # 因为网络、监控等daemonset组件,master节点也推荐安装kubelet和kube-proxy服务
  ...

创建 kubernetes 证书签名请求

bash
{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
{% if groups['ex_lb']|length > 0 %}
    "{{ hostvars[groups['ex_lb'][0]]['EX_APISERVER_VIP'] }}",
{% endif %}
{% for host in groups['kube_master'] %}
    "{{ host }}",
{% endfor %}
    "{{ CLUSTER_KUBERNETES_SVC_IP }}",
{% for host in MASTER_CERT_HOSTS %}
    "{{ host }}",
{% endfor %}
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "k8s",
      "OU": "System"
    }
  ]
}

kubernetes apiserver 使用对等证书,创建时hosts字段需要配置:

  • 如果配置 ex_lb,需要把 EX_APISERVER_VIP 也配置进去
  • 如果需要外部访问 apiserver,可选在config.yml配置 MASTER_CERT_HOSTS
  • kubectl get svc 将看到集群中由api-server 创建的默认服务 kubernetes,因此也要把 kubernetes 服务名和各个服务域名也添加进去

创建apiserver的服务配置文件

text
/* Detailed source-code truncated for AI context efficiency. */
  • Kubernetes 对 API 访问需要依次经过认证、授权和准入控制(admission controll),认证解决用户是谁的问题,授权解决用户能做什么的问题,Admission Control则是资源管理方面的作用。
  • 关于authorization-mode=Node,RBAC v1.7+支持Node授权,配合NodeRestriction准入控制来限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源;需要注意的是v1.7中Node 授权是默认开启的,v1.8中需要显式配置开启,否则 Node无法正常工作
  • 详细参数配置请参考kube-apiserver --help,关于认证、授权和准入控制请阅读
  • 增加了访问kubelet使用的证书配置,防止匿名访问kubelet的安全漏洞,详见漏洞说明

创建controller-manager 的服务文件

bash
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart={{ bin_dir }}/kube-controller-manager \
  --allocate-node-cidrs=true \
  --authentication-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \
  --authorization-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \
  --bind-address=0.0.0.0 \
  --cluster-cidr={{ CLUSTER_CIDR }} \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file={{ ca_dir }}/ca.pem \
  --cluster-signing-key-file={{ ca_dir }}/ca-key.pem \
  --kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \
  --leader-elect=true \
  --node-cidr-mask-size={{ NODE_CIDR_LEN }} \
  --root-ca-file={{ ca_dir }}/ca.pem \
  --service-account-private-key-file={{ ca_dir }}/ca-key.pem \
  --service-cluster-ip-range={{ SERVICE_CIDR }} \
  --use-service-account-credentials=true \
  --v=2
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
  • --cluster-cidr 指定 Cluster 中 Pod 的 CIDR 范围,该网段在各 Node 间必须路由可达(flannel/calico 等网络插件实现)
  • --service-cluster-ip-range 参数指定 Cluster 中 Service 的CIDR范围,必须和 kube-apiserver 中的参数一致
  • --cluster-signing-* 指定的证书和私钥文件用来签名为 TLS BootStrap 创建的证书和私钥
  • --root-ca-file 用来对 kube-apiserver 证书进行校验,指定该参数后,才会在Pod 容器的 ServiceAccount 中放置该 CA 证书文件
  • --leader-elect=true 使用多节点选主的方式选择主节点。只有主节点才会启动所有控制器,而其他从节点则仅执行选主算法

创建scheduler 的服务文件

bash
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart={{ bin_dir }}/kube-scheduler \
  --authentication-kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \
  --authorization-kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \
  --bind-address=0.0.0.0 \
  --kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \
  --leader-elect=true \
  --v=2
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
  • --leader-elect=true 部署多台机器组成的 master 集群时选举产生一个处于工作状态的 kube-controller-manager 进程

在master 节点安装 node 服务: kubelet kube-proxy

项目master 分支使用 DaemonSet 方式安装网络插件,如果master 节点不安装 kubelet 服务是无法安装网络插件的,如果 master 节点不安装网络插件,那么通过apiserver 方式无法访问 dashboard kibana等管理界面,ISSUES #130

在master 节点也同时成为 node 节点后,默认业务 POD也会调度到 master节点;可以使用 kubectl cordon命令禁止业务 POD调度到 master节点。

master 集群的验证

运行 ansible-playbook 04.kube-master.yml 成功后,验证 master节点的主要组件:

bash
# 查看进程状态
systemctl status kube-apiserver
systemctl status kube-controller-manager
systemctl status kube-scheduler
# 查看进程运行日志
journalctl -u kube-apiserver
journalctl -u kube-controller-manager
journalctl -u kube-scheduler

执行 kubectl get componentstatus 可以看到

bash
NAME                 STATUS    MESSAGE              ERROR
scheduler            Healthy   ok                   
controller-manager   Healthy   ok                   
etcd-0               Healthy   {"health": "true"}   
etcd-2               Healthy   {"health": "true"}   
etcd-1               Healthy   {"health": "true"}

后一篇


Setup/05 Install Kube Node

05-安装kube_node节点

kube_node 是集群中运行工作负载的节点,前置条件需要先部署好kube_master节点,它需要部署如下组件:

bash
cat playbooks/05.kube-node.yml
- hosts: kube_node
  roles:
  - { role: kube-lb, when: "inventory_hostname not in groups['kube_master']" }
  - { role: kube-node, when: "inventory_hostname not in groups['kube_master']" }
  • kube-lb:由nginx裁剪编译的四层负载均衡,用于将请求转发到主节点的 apiserver服务
  • kubelet:kube_node上最主要的组件
  • kube-proxy: 发布应用服务与负载均衡

创建cni 基础网络插件配置文件

因为后续需要用 DaemonSet Pod方式运行k8s网络插件,所以kubelet.server服务必须开启cni相关参数,并且提供cni网络配置文件

创建 kubelet 的服务文件

  • 根据官方建议独立使用 kubelet 配置文件,详见roles/kube-node/templates/kubelet-config.yaml.j2
  • 必须先创建工作目录 /var/lib/kubelet
text
/* Detailed source-code truncated for AI context efficiency. */
  • --ExecStartPre=/bin/mkdir -p xxx 对于某些系统(centos7)cpuset和hugetlb 是默认没有初始化system.slice 的,需要手动创建,否则在启用--kube-reserved-cgroup 时会报错Failed to start ContainerManager Failed to enforce System Reserved Cgroup Limits
  • 关于kubelet资源预留相关配置请参考 https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/

创建 kube-proxy kubeconfig 文件

该步骤已经在 deploy节点完成,roles/deploy/tasks/main.yml

  • 生成的kube-proxy.kubeconfig 配置文件需要移动到/etc/kubernetes/目录,后续kube-proxy服务启动参数里面需要指定

创建 kube-proxy服务文件

bash
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart={{ bin_dir }}/kube-proxy \
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

请注意 kube-proxy-config 文件的注释说明

验证 node 状态

bash
systemctl status kubelet	# 查看状态
systemctl status kube-proxy
journalctl -u kubelet		# 查看日志
journalctl -u kube-proxy

运行 kubectl get node 可以看到类似

bash
NAME           STATUS    ROLES     AGE       VERSION
192.168.1.42   Ready     <none>    2d        v1.9.0
192.168.1.43   Ready     <none>    2d        v1.9.0
192.168.1.44   Ready     <none>    2d        v1.9.0

后一篇


Setup/06 Install Network Plugin

06-安装网络组件

首先回顾下K8S网络设计原则,在配置集群网络插件或者实践K8S 应用/服务部署请牢记这些原则:

  • 1.每个Pod都拥有一个独立IP地址,Pod内所有容器共享一个网络命名空间
  • 2.集群内所有Pod都在一个直接连通的扁平网络中,可通过IP直接访问
    • 所有容器之间无需NAT就可以直接互相访问
    • 所有Node和所有容器之间无需NAT就可以直接互相访问
    • 容器自己看到的IP跟其他容器看到的一样
  • 3.Service cluster IP只可在集群内部访问,外部请求需要通过NodePort、LoadBalance或者Ingress来访问

Container Network Interface (CNI)是目前CNCF主推的网络模型,它由两部分组成:

  • CNI Plugin负责给容器配置网络,它包括两个基本的接口
    • 配置网络: AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
    • 清理网络: DelNetwork(net *NetworkConfig, rt *RuntimeConf) error
  • IPAM Plugin负责给容器分配IP地址

Kubernetes Pod的网络是这样创建的:

    1. 每个Pod除了创建时指定的容器外,都有一个kubelet启动时指定的基础容器,即pause容器
    1. kubelet创建基础容器生成network namespace
    1. kubelet调用网络CNI driver,由它根据配置调用具体的CNI 插件
    1. CNI 插件给基础容器配置网络
    1. Pod 中其他的容器共享使用基础容器的网络

本项目基于CNI driver 调用各种网络插件来配置kubernetes的网络,常用CNI插件有 flannel calico cilium等等,这些插件各有优势,也在互相借鉴学习优点,比如:在所有node节点都在一个二层网络时候,flannel提供hostgw实现,避免vxlan实现的udp封装开销,估计是目前最高效的;calico也针对L3 Fabric,推出了IPinIP的选项,利用了GRE隧道封装;因此这些插件都能适合很多实际应用场景。

项目当前内置支持的网络插件有:calico cilium flannel kube-ovn kube-router

安装讲解

参考

后一篇


Setup/07 Install Cluster Addon

07-安装集群主要插件

目前挑选一些常用、必要的插件自动集成到安装脚本之中:

集群默认安装

kubeasz 默认安装上述基础插件,并支持离线方式安装(./ezdown -D 命令会自动下载组件镜像,并推送到本地镜像仓库easzlab.io.local:5000)

集群可选安装

Headlamp 请按使用说明通过 Helm 手动安装。其余可选插件默认不安装,可以在配置文件(clusters/xxx/config.yml)中开启;./ezdown -X 会下载对应的额外组件镜像,并推送到本地镜像仓库 easzlab.io.local:5000。

安装脚本

详见roles/cluster-addon/ 目录

  • 1.根据hosts文件中配置的CLUSTER_DNS_SVC_IP CLUSTER_DNS_DOMAIN等参数生成kubedns.yaml和coredns.yaml文件
  • 2.注册变量pod_info,pod_info用来判断现有集群是否已经运行各种插件
  • 3.根据pod_info和配置开关逐个进行/跳过插件安装

下一步


Setup/08 Cluster Storage

K8S 集群存储

前言

在kubernetes(k8s)中对于存储的资源抽象了两个概念,分别是PersistentVolume(PV)、PersistentVolumeClaim(PVC)。

  • PV是集群中的资源
  • PVC是对这些资源的请求。

如上面所说PV和PVC都只是抽象的概念,在k8s中是通过插件的方式提供具体的存储实现。目前包含有NFS、iSCSI和云提供商指定的存储系统,更多的存储实现参考官方文档。

以下介绍两种provisioner, 可以提供静态或者动态的PV

NFS存储目录供应者

首先我们需要一个NFS服务器,用于提供底层存储。通过文档nfs-server,我们可以创建一个NFS服务器。

静态 PV

  • 创建静态 pv,指定容量,访问模式,回收策略,存储类等
bash
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-es-0
spec:
  capacity:
    storage: 4Gi
  accessModes:
    - ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "es-storage-class"
  nfs:
    # 根据实际共享目录修改
    path: /share/es0
    # 根据实际 nfs服务器地址修改
    server: 192.168.1.208
  • 创建 pvc即可绑定使用上述 pv了,具体请看后文 test pod例子

创建动态PV

在一个工作k8s 集群中,PVC请求会很多,如果每次都需要管理员手动去创建对应的 PV资源,那就很不方便;因此 K8S还提供了多种 provisioner来动态创建 PV,不仅节省了管理员的时间,还可以根据StorageClasses封装不同类型的存储供 PVC 选用。

项目中以nfs-client-provisioner为例 https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

  • 1.编辑集群配置文件:clusters/${集群名}/config.yml
bash
... 省略
# 在role:cluster-addon 中启用nfs-provisioner 安装
nfs_provisioner_install: "yes"			# 修改为yes
nfs_provisioner_namespace: "kube-system"
nfs_provisioner_ver: "v4.0.1"
nfs_storage_class: "managed-nfs-storage"	
nfs_server: "192.168.31.244"			# 修改为实际nfs server地址
nfs_path: "/data/nfs"				# 修改为实际的nfs共享目录
  • 2.创建 nfs provisioner
bash
$ dk ezctl setup ${集群名} 07 

# 执行成功后验证
$ kubectl get pod --all-namespaces |grep nfs-client
kube-system   nfs-client-provisioner-84ff87c669-ksw95      1/1     Running     0          21m
  • 3.验证使用动态 PV

在目录clusters/${集群名}/yml/nfs-provisioner/ 有个测试例子

bash
$ kubectl apply -f /etc/kubeasz/clusters/hello/yml/nfs-provisioner/test-pod.yaml

# 验证测试pod
kubectl get pod
NAME       READY   STATUS      RESTARTS   AGE
test-pod   0/1     Completed   0          6h36m

# 验证自动创建的pv 资源,
kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS          REASON   AGE
pvc-44d34a50-e00b-4f6c-8005-40f5cc54af18   2Mi        RWX            Delete           Bound    default/test-claim   managed-nfs-storage            6h36m

# 验证PVC已经绑定成功:STATUS字段为 Bound
kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
test-claim   Bound    pvc-44d34a50-e00b-4f6c-8005-40f5cc54af18   2Mi        RWX            managed-nfs-storage   6h37m

另外,Pod启动完成后,在挂载的目录中创建一个SUCCESS文件。我们可以到NFS服务器去看下:

text
.
└── default-test-claim-pvc-44d34a50-e00b-4f6c-8005-40f5cc54af18
    └── SUCCESS

如上,可以发现挂载的时候,nfs-client根据PVC自动创建了一个目录,我们Pod中挂载的/mnt,实际引用的就是该目录,而我们在/mnt下创建的SUCCESS文件,也自动写入到了这里。

后面当我们需要为上层应用提供持久化存储时,只需要提供StorageClass即可。很多应用都会根据StorageClass来创建他们的所需的PVC, 最后再把PVC挂载到他们的Deployment或StatefulSet中使用,比如:efk、jenkins等

本地存储目录供应者

当应用对于磁盘I/O性能要求高,比较适合本地文件目录存储,特别地可以本地挂载SSD磁盘(注意本地磁盘需要配置raid冗余策略)。Local Path Provisioner 可以方便地在k8s集群中使用本地文件目录存储。

在kubeasz项目中集成安装

  • 1.编辑集群配置文件:clusters/${集群名}/config.yml
bash
... 省略
local_path_provisioner_install: "yes" # 修改为yes
# 设置默认本地存储路径
local_path_provisioner_dir: "/opt/local-path-provisioner"
  • 2.创建 local path provisioner
bash
$ dk ezctl setup ${集群名} 07

# 执行成功后验证
$ kubectl get pod --all-namespaces |grep provisioner
  • 3.验证使用(略)

Setup/Config Guide

个性化集群参数配置

kubeasz创建集群主要在以下两个地方进行配置:(假设集群名xxxx)

  • clusters/xxxx/hosts 文件(模板在example/hosts.multi-node):集群主要节点定义和主要参数配置、全局变量
  • clusters/xxxx/config.yml(模板在examples/config.yml):其他参数配置或者部分组件附加参数

clusters/xxxx/hosts (ansible hosts)

如集群规划与安装概览中介绍,主要包括集群节点定义和集群范围的主要参数配置

  • 尽量保持配置简单灵活
  • 尽量保持配置项稳定

常用设置项:

  • 修改容器运行时: CONTAINER_RUNTIME="containerd"
  • 修改集群网络插件:CLUSTER_NETWORK="calico"
  • 修改容器网络地址:CLUSTER_CIDR="192.168.0.0/16"
  • 修改NodePort范围:NODE_PORT_RANGE="30000-32767"

clusters/xxxx/config.yml

主要包括集群某个具体组件的个性化配置,具体组件的配置项可能会不断增加;可以在不做任何配置更改情况下使用默认值创建集群

根据实际需要配置 k8s 集群,常用举例

  • 配置使用离线安装系统包:INSTALL_SOURCE: "offline" (需要ezdown -P 下载离线系统软件)
  • 配置CA证书以及其签发证书的有效期
  • 配置 apiserver 支持公网域名:MASTER_CERT_HOSTS
  • 配置 cluster-addon 组件安装
  • ...

Setup/Ex Lb

EX-LB 负载均衡部署

根据HA 2x架构,k8s集群自身高可用已经不依赖于外部 lb 服务;但是有时我们要从外部访问 apiserver(比如 CI 流程),就需要 ex_lb 来请求多个 apiserver;

还有一种情况是需要负载转发到ingress服务,也需要部署ex_lb;

注意:当遇到公有云环境无法自建 ex_lb 服务时,可以配置对应的云负载均衡服务

ex_lb 服务组件

更新:kubeasz 3.0.2 重写了ex-lb服务安装,利用最小化依赖编译安装的二进制文件,不依赖于linux发行版;优点是可以统一版本和简化离线安装部署,并且理论上能够支持更多linux发行版

ex_lb 服务由 keepalived 和 l4lb 组成:

  • l4lb:是一个精简版(仅支持四层转发)的nginx编译二进制版本
  • keepalived:利用主备节点vrrp协议通信和虚拟地址,消除l4lb的单点故障;keepalived保持存活,它是基于VRRP协议保证所谓的高可用或热备的,这里用来预防l4lb的单点故障。

keepalived与l4lb配合,实现master的高可用过程如下:

  • 1.keepalived利用vrrp协议生成一个虚拟地址(VIP),正常情况下VIP存活在keepalive的主节点,当主节点故障时,VIP能够漂移到keepalived的备节点,保障VIP地址高可用性。
  • 2.在keepalived的主备节点都配置相同l4lb负载配置,并且监听客户端请求在VIP的地址上,保障随时都有一个l4lb负载均衡在正常工作。并且keepalived启用对l4lb进程的存活检测,一旦主节点l4lb进程故障,VIP也能切换到备节点,从而让备节点的l4lb进行负载工作。
  • 3.在l4lb的配置中配置多个后端真实kube-apiserver的endpoints,并启用存活监测后端kube-apiserver,如果一个kube-apiserver故障,l4lb会将其剔除负载池。

安装l4lb

配置l4lb (roles/ex-lb/templates/l4lb.conf.j2)

配置由全局配置和三个upstream servers配置组成:

  • apiservers 用于转发至多个apiserver
  • ingress-nodes 用于转发至node节点的ingress http服务,参阅
  • ingress-tls-nodes 用于转发至node节点的ingress https服务

安装keepalived

配置keepalived主节点 [keepalived-master.conf.j2](../../roles/ex-lb/templates/keepalived-master.conf.j2)

bash
global_defs {
}

vrrp_track_process check-l4lb {
    process l4lb
    weight -60
    delay 3
}

vrrp_instance VI-01 {
    state MASTER
    priority 120
    unicast_src_ip {{ inventory_hostname }}
    unicast_peer {
{% for h in groups['ex_lb'] %}{% if h != inventory_hostname %}
        {{ h }}
{% endif %}{% endfor %}
    }
    dont_track_primary
    interface {{ LB_IF }}
    virtual_router_id {{ ROUTER_ID }}
    advert_int 3
    track_process {
        check-l4lb
    }
    virtual_ipaddress {
        {{ EX_APISERVER_VIP }}
    }
}
  • vrrp_track_process 定义了监测l4lb进程是否存活,如果进程不存在,根据weight -60设置将主节点优先级降低60,这样原先备节点将变成主节点。
  • vrrp_instance 定义了vrrp组,包括优先级、使用端口、router_id、心跳频率、检测脚本、虚拟地址VIP等
  • 特别注意 virtual_router_id 标识了一个 VRRP组,在同网段下必须唯一,否则出现 Keepalived_vrrp: bogus VRRP packet received on eth0 !!!类似报错
  • 配置 vrrp 协议通过单播发送

配置keepalived备节点 [keepalived-backup.conf.j2](../../roles/ex-lb/templates/keepalived-backup.conf.j2)

  • 备节点的配置类似主节点,除了优先级和检测脚本,其他如 virtual_router_id advert_int virtual_ipaddress必须与主节点一致

启动 keepalived 和 l4lb 后验证

  • lb 节点验证
bash
systemctl status l4lb 	# 检查进程状态
journalctl -u l4lb		# 检查进程日志是否有报错信息
systemctl status keepalived 	# 检查进程状态
journalctl -u keepalived	# 检查进程日志是否有报错信息
  • 在 keepalived 主节点
bash
ip a				# 检查 master的 VIP地址是否存在

keepalived 主备切换演练

  1. 尝试关闭 keepalived主节点上的 l4lb进程,然后在keepalived 备节点上查看 master的 VIP地址是否能够漂移过来,并依次检查上一步中的验证项。
  2. 尝试直接关闭 keepalived 主节点系统,检查各验证项。

Setup/Ezctl

ezctl 命令行介绍

为什么使用 ezctl

kubeasz 项目使用ezctl 方便地创建和管理多个k8s 集群,ezctl 使用shell 脚本封装ansible-playbook 执行命令,它十分轻量、简单和易于扩展。

使用帮助

随时运行 ezctl 获取命令行提示信息,如下

text
/* Detailed source-code truncated for AI context efficiency. */
  • 命令集 1:集群安装相关操作
    • 显示当前所有管理的集群
    • 切换默认集群
    • 创建新集群配置
    • 安装新集群
    • 启动临时停止的集群
    • 临时停止某个集群(包括集群内运行的pod)
    • 升级集群k8s组件版本
    • 删除集群
    • 备份集群(仅etcd数据,不包括pv数据和业务应用数据)
    • 从备份中恢复集群
    • 创建单机集群(类似 minikube)
  • 命令集 2:集群节点操作
    • 增加 etcd 节点
    • 增加主节点
    • 增加工作节点
    • 删除 etcd 节点
    • 删除主节点
    • 删除工作节点
  • 命令集3:额外操作
    • 管理客户端kubeconfig

举例创建、安装新集群流程

  • 1.首先创建集群配置实例
bash
~# ezctl new k8s-01
2021-01-19 10:48:23 DEBUG generate custom cluster files in /etc/kubeasz/clusters/k8s-01
2021-01-19 10:48:23 DEBUG set version of common plugins
2021-01-19 10:48:23 DEBUG cluster k8s-01: files successfully created.
2021-01-19 10:48:23 INFO next steps 1: to config '/etc/kubeasz/clusters/k8s-01/hosts'
2021-01-19 10:48:23 INFO next steps 2: to config '/etc/kubeasz/clusters/k8s-01/config.yml'

然后根据提示配置'/etc/kubeasz/clusters/k8s-01/hosts' 和 '/etc/kubeasz/clusters/k8s-01/config.yml';为方便测试我们在hosts里面设置单节点集群(etcd/kube_master/kube_node配置同一个节点,注意节点需先设置ssh免密码登陆), config.yml 使用默认配置即可。

  • 2.然后开始安装集群
bash
# 一键安装
ezctl setup k8s-01 all

# 或者分步安装,具体使用 ezctl help setup 查看分步安装帮助信息
# ezctl setup k8s-01 01
# ezctl setup k8s-01 02
# ezctl setup k8s-01 03
# ezctl setup k8s-01 04
...
  • 3.重复步骤1,2可以创建、管理多个k8s集群(建议ezctl使用独立的部署节点)

ezctl 创建管理的多集群拓扑如下

text
+----------------+               +-----------------+
|ezctl 1.1.1.1   |               |cluster-aio:     |
+--+---+---+-----+               |                 |
   |   |   |                     |master 4.4.4.4   |
   |   |   +-------------------->+etcd   4.4.4.4   |
   |   |                         |node   4.4.4.4   |
   |   +--------------+          +-----------------+
   |                  |
   v                  v
+--+------------+ +---+----------------------------+
| cluster-1:    | | cluster-2:                     |
|               | |                                |
| master 2.2.2.1| | master 3.3.3.1/3.3.3.2         |
| etcd   2.2.2.2| | etcd   3.3.3.1/3.3.3.2/3.3.3.3 |
| node   2.2.2.3| | node   3.3.3.4/3.3.3.5/3.3.3.6 |
+---------------+ +--------------------------------+

That's it! 赶紧动手测试吧,欢迎通过 Issues 和 PRs 反馈您的意见和建议!


Setup/Kubeasz On Public Cloud

公有云上部署 kubeasz

在公有云上使用kubeasz部署k8s集群需要注意以下几个常见问题。

安全组

注意虚机的安全组规则配置,一般集群内部节点之间端口全部放开即可;

网络组件

一般公有云对网络限制较多,跨节点 pod 通讯需要使用 OVERLAY 添加报头;默认配置详见example/config.yml

  • flannel 使用 vxlan 模式:FLANNEL_BACKEND: "vxlan"
  • calico 开启 ipinip:CALICO_IPV4POOL_IPIP: "Always"
  • kube-router 开启 ipinip:OVERLAY_TYPE: "full"

节点公网访问

可以在安装时每个节点绑定弹性公网地址(EIP),装完集群解绑;也可以开通NAT网关,或者利用iptables自建上网网关等方式

负载均衡

一般云厂商会限制使用keepalived+haproxy自建负载均衡,你可以根据云厂商文档使用云负载均衡(内网)四层TCP负载模式;

  • kubeasz 2x 版本已无需依赖外部负载均衡实现apiserver的高可用,详见 2x架构
  • kubeasz 1x 及以前版本需要负载均衡实现apiserver高可用,详见 1x架构

时间同步

一般云厂商提供的虚机都已默认安装时间同步服务,无需自行安装。

访问 APISERVER

在公有云上安装完集群后,需要在公网访问集群 apiserver,而我们在安装前可能没有规划公网IP或者公网域名;而 apiserver 肯定需要 https 方式访问,在证书创建时需要加入公网ip/域名;可以参考这里修改 APISERVER(MASTER)证书

在公有云上部署多主高可用集群

处理好以上讨论的常见问题后,在公有云上使用 kubeasz 安装集群与自有环境没有差异。

  • 使用 kubeasz 2x 版本安装单节点、单主多节点、多主多节点 k8s 集群,云上云下的预期安装体验完全一致

Setup/Mix Arch

混合架构集群部署

混合架构集群本文是指集群中既有linux amd64架构机器,也有linux arm64架构机器;这里只记录一个简单的操作说明,实际操作注意风险。

部署思路

  1. 先选定一台amd64架构的机器做“amd64部署机”,使用它先部署amd64架构的集群
  2. 选一台arm64架构的机器做“arm64部署机”,复制amd64部署机的/etc/kubeasz目录文件(除去目录中的bin、down子目录),然后重新下载arm64架构的二进制和镜像,然后添加arm64节点到原有集群即可

操作步骤

  1. 假设已经正常部署了amd64架构的三节点集群
  2. 在“amd64部署机” 目录 /etc/kubeasz 中移除子目录 bin 和 down,然后把整体/etc/kubeasz 目录复制到“arm64部署机”
text
# 登录amd64部署机
cd /etc/kubeasz; mv bin down /tmp/; scp -r /etc/kubeasz root@{_ip_arm64}:/etc/
# 复制完成后找回 bin 和 down 子目录
mv /tmp/bin /etc/kubeasz/; mv /tmp/down /etc/kubeasz/
  1. 登录“arm64部署机”,执行下载,其他准备工作
text
cd /etc/kubeasz
# 下载基础部分
./ezdown -D
# 下载额外部分(如有)
./ezdown -X ...
# 运行部署容器
./ezdown -S
# 配置机器ssh免密码登录,集群所有节点都免密,包括待新增arm64节点
ssh-copy-id xx.xx.xx.xx
ssh-copy-id ...
# 复制kubeconfig
mkdir /root/.kube/; cp clusters/default/kubectl.kubeconfig /root/.kube/config
  1. 添加arm64新节点到集群
text
source ~/.bashrc
# 添加新节点 x.x.x.x
dk ezctl add-node default x.x.x.x
  1. 验证
text
$ kubectl get node -owide
NAME           STATUS   ROLES    AGE    VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
k8s-x.x.x-19   Ready    master   5d8h   v1.33.1   x.x.x.19   <none>        Ubuntu 20.04.4 LTS   5.4.0-122-generic    containerd://2.1.1
k8s-x.x.x-90   Ready    node     5d8h   v1.33.1   x.x.x.90   <none>        Ubuntu 22.04.5 LTS   5.15.0-134-generic   containerd://2.1.1
k8s-x.x.x-91   Ready    node     5d8h   v1.33.1   x.x.x.91   <none>        Ubuntu 22.04.5 LTS   5.15.0-134-generic   containerd://2.1.1
k8s-x.x.x-93   Ready    node     79s    v1.33.1   x.x.x.93   <none>        Ubuntu 22.04.5 LTS   5.15.0-140-generic   containerd://2.1.1

$ kubectl describe node|grep beta.kubernetes.io/arch
Labels:             beta.kubernetes.io/arch=amd64
Labels:             beta.kubernetes.io/arch=amd64
Labels:             beta.kubernetes.io/arch=amd64
Labels:             beta.kubernetes.io/arch=arm64

小结

通过以上步骤,成功实现了在amd64集群中添加arm64节点;充分展示kubeasz 项目部署集群的灵活性和可配置性;部署过程中ansible执行的过程性输出内容,以近乎白盒的方式展示每一个细节;假如出错有详细的说明,帮助定位,并且随时可以修改执行脚本,安装的幂等性保证随时可以重新安装以修复错误。Hack it, and have fun!


Setup/Multi Os

操作系统说明

目前发现部分使用新内核的linux发行版,k8s 安装使用 cgroup v2版本时,有时候安装会失败,需要删除/清理集群后重新安装。已报告可能发生于 Alma Linux 9, Rocky Linux 9, Fedora 37;建议如下步骤处理:

  • 1.确认系统使用的cgroup v2版本
text
stat -fc %T /sys/fs/cgroup/ 
cgroup2fs
  • 2.初次安装时kubelet可能启动失败,日志报错类似:err="openat2 /sys/fs/cgroup/kubepods.slice/cpu.weight: no such file or directory"

  • 3.建议删除集群然后重新安装,一般能够成功

text
# 删除集群
dk ezctl destroy xxxx

# 重启
reboot

# 启动后重新安装
dk ezctl setup xxxx all

Debian

  • Debian 11:默认可能没有安装iptables,使用kubeasz 安装前需要执行:(仅部署节点需要)
bash
apt update

apt install iptables -y

openEuler

  • openEuler 24.03 需要安装iptables
bash
yum install iptables -y

openSUSE

  • openSUSE Leap 15.4:需要安装iptables
bash
zypper install iptables
ln -s /usr/sbin/iptables /sbin/iptables

Setup/Multi Platform

多架构支持

kubeasz 3.4.1 以后支持多CPU架构,当前已支持linux amd64和linux arm64,更多架构支持根据后续需求来计划。

使用方式

kubeasz 多架构安装逻辑:根据部署机器(执行ezdown/ezctl命令的机器)的架构,会自动判断下载对应amd64/arm64的二进制文件和容器镜像,然后推送安装到整个集群。

  • 暂不支持自动部署混合架构集群,如有需要可以按说明文档手动操作。
  • harbor目前仅支持amd64安装

架构支持备忘

k8s核心组件本身提供多架构的二进制文件/容器镜像下载,项目调整了下载二进制文件的容器dockerfile

kubeasz其他用到的二进制或镜像,重新调整了容器创建dockerfile

其他组件(coredns/network plugin/dashboard/metrics-server等)一般都提供多架构的容器镜像,可以直接下载拉取


Setup/Offline Install

离线安装集群

使用kubeasz 离线安装 k8s集群需要下载四个部分:

  • kubeasz 项目代码
  • 二进制文件(k8s、etcd、containerd等组件)
  • 容器镜像文件(calico、coredns、metrics-server等容器镜像)
  • 系统软件安装包(ipset、libseccomp2等,仅无法使用本地yum/apt源时需要)

离线文件准备

在一台能够访问互联网的服务器上执行:

  • 下载工具脚本ezdown,举例使用kubeasz版本3.6.0
bash
export release=3.6.0
wget https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
chmod +x ./ezdown
  • 使用工具脚本下载(更多关于ezdown的参数,运行./ezdown 查看)

下载kubeasz代码、二进制、默认容器镜像

bash
# 国内环境
./ezdown -D

[可选]如果需要更多组件,请下载额外容器镜像(cilium,flannel,prometheus等)

bash
./ezdown -X flannel
./ezdown -X prometheus
...

下载离线系统包 (适用于无法使用yum/apt仓库情形)

bash
# 如果操作系统是ubuntu 22.04
./ezdown -P ubuntu_22

上述脚本运行成功后,所有文件(kubeasz代码、二进制、离线镜像)均已整理好放入目录/etc/kubeasz

  • /etc/kubeasz 包含 kubeasz 版本为 ${release} 的发布代码
  • /etc/kubeasz/bin 包含 k8s/etcd/docker/cni 等二进制文件
  • /etc/kubeasz/down 包含集群安装时需要的离线容器镜像
  • /etc/kubeasz/down/packages 包含集群安装时需要的系统基础软件

离线安装

上述下载完成后,把/etc/kubeasz整个目录复制到目标离线服务器相同目录,然后在离线服务器/etc/kubeasz目录下执行:

  • 离线安装 docker,检查本地文件,正常会提示所有文件已经下载完成,并上传到本地私有镜像仓库
text
./ezdown -D
./ezdown -X flannel
./ezdown -X prometheus
...
  • 启动 kubeasz 容器
text
./ezdown -S
  • 设置参数允许离线安装系统软件包
text
sed -i 's/^INSTALL_SOURCE.*$/INSTALL_SOURCE: "offline"/g' /etc/kubeasz/example/config.yml
bash
source ~/.bashrc
dk ezctl start-aio
# 或者执行 docker exec -it kubeasz ezctl start-aio

Setup/QuickStart

快速指南

本文档适用于kubeasz 3.3.1以上版本,部署单节点集群(aio),作为快速体验k8s集群的测试环境。

1.基础系统配置

  • 准备一台虚机配置内存4G/硬盘30G以上
  • 最小化安装Ubuntu 22.04 server
  • 配置基础网络、更新源、SSH登录等

注意: 确保在干净的系统上开始安装,不能使用曾经装过kubeadm或其他k8s发行版的环境

2.下载文件

  • 下载工具脚本ezdown,举例使用kubeasz版本3.6.7
bash
export release=3.6.7
wget https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
chmod +x ./ezdown
  • 使用工具脚本下载(更多关于ezdown的参数,运行./ezdown 查看)

下载kubeasz代码、二进制、默认容器镜像

bash
# 国内环境
./ezdown -D
# 海外环境
#./ezdown -D -m standard

【可选】下载额外容器镜像(cilium,flannel,prometheus等)

bash
# 按需下载
./ezdown -X prometheus
...

【可选】下载离线系统包 (适用于无法使用yum/apt仓库情形)

bash
./ezdown -P

上述脚本运行成功后,所有文件(kubeasz代码、二进制、离线镜像)均已整理好放入目录/etc/kubeasz

  • /etc/kubeasz 包含 kubeasz 版本为 ${release} 的发布代码
  • /etc/kubeasz/bin 包含 k8s/etcd/docker/cni 等二进制文件
  • /etc/kubeasz/down 包含集群安装时需要的离线容器镜像
  • /etc/kubeasz/down/packages 包含集群安装时需要的系统基础软件

3.安装集群

  • 容器化运行 kubeasz
text
./ezdown -S
  • 使用默认配置安装 aio 集群
text
docker exec -it kubeasz ezctl start-aio
# 如果安装失败,查看日志排除后,使用如下命令重新安装aio集群
# docker exec -it kubeasz ezctl setup default all

4.验证安装

bash
$ source ~/.bashrc
$ kubectl version         # 验证集群版本     
$ kubectl get node        # 验证节点就绪 (Ready) 状态
$ kubectl get pod -A      # 验证集群pod状态,默认已安装网络插件、coredns、metrics-server等
$ kubectl get svc -A      # 验证集群服务状态
  • 可选安装 Headlamp 查看和管理集群

5.清理

以上步骤创建的K8S开发测试环境请尽情折腾,碰到错误尽量通过查看日志、上网搜索、提交issues等方式解决;当然你也可以清理集群后重新创建。

在宿主机上,按照如下步骤清理

  • 清理集群 docker exec -it kubeasz ezctl destroy default
  • 重启节点,以确保清理残留的虚拟网卡、路由等信息

Release Notes/Kubeasz 3.7.0

kubeasz 3.7.0

首个 kubeasz 3.7.x 版本发布,默认使用nftables 模式,包含大量组件更新。

版本/组件更新

  • k8s: v1.36.3
  • etcd: v3.7.1
  • containerd: 2.3.3
  • runc: v1.5.1
  • cni: v1.9.1
  • calico: v3.32.1
  • flannel: v0.28.9
  • coredns: 1.14.6
  • nodelocaldns: 1.26.8
  • metrics: v0.9.0
  • pause: 3.10.2
  • headlamp: 0.43.0
  • openebs: 4.5.1
  • higress: 2.2.3
  • node-problem-detector: v1.35.3
  • kube-prometheus-stack: 88.1.5

重要更新

  • 支持 k8s v1.36集群默认使用 kube-proxy 的nftables 模式,需要较新的系统内核支持(kernal >= 5.13 and nft >= 1.0.0);更新默认支持的操作系统列表,尽量选择较新系统内核的稳定linux发行版。
  • 新增组件node-problem-detector 和若干自定义检查插件。
  • 新增组件 headlamp 替换 dashboard,使用更加方便。
  • 新增组件 higress ingress controller 替换 ingress-nginx。

其他更新

  • 新增 easzlab/kubeasz 镜像签名信息和SBOM 信息,感谢kobihikri #1538
  • 新增openeuler22/24系统软件离线包下载,感谢whowhopipi
  • 部分文档更新

Op/Ch Apiserver Cert

修改 APISERVER(MASTER)证书

kubeasz 创建集群后,APISERVER(MASTER)证书默认 CN 包含如下域名和IP:参见roles/kube-master/templates/kubernetes-csr.json.j2

text
"hosts": [
    "127.0.0.1",
{% if groups['ex_lb']|length > 0 %}
    "{{ hostvars[groups['ex_lb'][0]]['EX_APISERVER_VIP'] }}",
{% endif %}
{% for host in groups['kube_master'] %}
    "{{ host }}",
{% endfor %}
    "{{ CLUSTER_KUBERNETES_SVC_IP }}",
{% for host in MASTER_CERT_HOSTS %}
    "{{ host }}",
{% endfor %}
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],

有的时候(比如apiserver地址通过边界防火墙的NAT转换成公网IP访问,或者需要添加公网域名访问)我们需要在 APISERVER(MASTER)证书中添加一些域名或者IP,可以方便操作如下:

1.修改配置文件`/etc/kubeasz/clusters/${集群名}/config.yaml`

bash
# k8s 集群 master 节点证书配置,可以添加多个ip和域名(比如增加公网ip和域名)
MASTER_CERT_HOSTS:
  - "10.1.1.1"
  - "k8s.test.io"
  #- "www.test.com"

2.执行新证书生成并重启apiserver

bash
$ ezctl setup ${集群名} 04 -t change_cert,restart_master

Op/Cluster Restore

K8S 集群备份与恢复

虽然 K8S 集群可以配置成多主多节点的高可用的部署,还是有必要了解下集群的备份和容灾恢复能力;在高可用k8s集群中 etcd集群保存了整个集群的状态,因此这里的备份与恢复重点就是:

  • 从运行的etcd集群备份数据到磁盘文件
  • 从etcd备份文件恢复数据,从而使集群恢复到备份时状态

备份与恢复操作说明

  • 1.首先搭建一个测试集群,部署几个测试deployment,验证集群各项正常后,进行一次备份(假设集群名为k8s-01):
bash
$ ezctl backup k8s-01
# 或者如下手动执行ansible命令
# ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/94.backup.yml

执行完毕可以在部署主机的备份目录下检查备份情况,示例如下:

text
/etc/kubeasz/clusters/k8s-01/backup/
├── snapshot_202106201205.db
├── snapshot_202106211406.db
└── snapshot.db

其中,snapshot.db始终为最近一次备份文件

  • 2.模拟误删除操作(略)

  • 3.恢复集群及验证

可以在 roles/cluster-restore/defaults/main.yml 文件中配置需要恢复的 etcd备份版本(从上述备份目录中选取),默认使用最近一次备份;执行恢复后,需要一定时间等待 pod/svc 等资源恢复重建。

bash
$ ezctl restore k8s-01
# 或者如下手动执行ansible命令
# ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/95.restore.yml

如果集群主要组件(master/etcd/node)等出现不可恢复问题,可以尝试使用如下步骤 清理 --> 创建 --> 恢复

bash
$ ezctl clean k8s-01
# 或者如下手动执行ansible命令
# ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/99.clean.yml
$ ezctl setup k8s-01 01
$ ezctl setup k8s-01 02
$ ezctl setup k8s-01 03
$ ezctl setup k8s-01 04
$ ezctl setup k8s-01 05
...
$ ezctl restore k8s-01
# ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/95.restore.yml

参考


Op/Force Ch Certs

强制更新CA和所有证书

  • WARNNING: 此命令使用需要小心谨慎,确保了解功能背景和可能的结果;执行后,它会重新创建集群CA证书以及由它颁发的所有其他证书;一般适合于集群admin.conf不小心泄露,为了避免集群被非法访问,重新创建CA,从而使已泄漏的admin.conf失效。

  • 如果需要分发受限的kubeconfig,强烈建议使用自定义权限和期限的kubeconfig

使用帮助

确认需要强制更新后,在ansible 控制节点使用如下命令:(xxx 表示需要操作的集群名)

bash
docker exec -it kubeasz ezctl kca-renew xxx
# 或者使用 dk ezctl kca-renew xxx

上述命令执行后,按序进行以下的操作:详见playbooks/96.update-certs.yml

  • 重新生成CA证书,以及各种kubeconfig

  • 签发新etcd证书,并使用新证书重启etcd服务

  • 签发新kube-apiserver 证书,并重启kube-apiserver/kube-controller-manager/kube-scheduler 服务

  • 签发新kubelet 证书,并重启kubelet/kube-proxy 服务

  • 重启网络组件pod

  • 重启其他集群组件pod

  • 特别注意: 如果集群中运行的业务负载pod需要访问apiserver,需要重启这些pod

检查验证

更新完毕,注意检查集群组件日志和容器pod日志,确认集群处于正常状态

  • 集群组件日志:使用journalctl -u xxxx.service -f 依次检查 etcd.service/kube-apiserver.service/kube-controller-manager.service/kube-scheduler.service/kubelet.service/kube-proxy.service
  • 容器pod日志:使用 kubectl logs 方式检查容器日志

Op/Kcfg Adm

管理客户端kubeconfig

默认 k8s集群安装成功后生成客户端kubeconfig,它拥有集群管理的所有权限(不要将这个admin权限、50年期限的kubeconfig流露出去);而我们经常需要将限定权限、限定期限的kubeconfig 分发给普通用户;利用cfssl签发自定义用户证书和k8s灵活的rbac权限绑定机制,ezctl 工具封装了这个功能。

使用帮助

text
ezctl help kcfg-adm
Usage: ezctl kcfg-adm <cluster> <args>
available <args>:
    -A     to add a client kubeconfig with a newly created user
    -D     to delete a client kubeconfig with the existed user
    -L     to list all of the users
    -e     to set expiry of the user certs in hours (ex. 24h, 8h, 240h)
    -t     to set a user-type (admin or view)
    -u     to set a user-name prefix

examples: ./ezctl kcfg-adm test-k8s -L
          ./ezctl kcfg-adm default -A -e 240h -t admin -u jack
          ./ezctl kcfg-adm default -D -u jim-202101162141
  • 可以设置过期时间
  • 可以设置权限:管理员权限(admin)和只读权限(view)

使用举例

  • 1.查看集群k8s-01当前自定义kubeconfig
text
ezctl kcfg-adm k8s-01 -L
2021-01-24 16:32:43 INFO list-kcfg k8s-01
2021-01-24 16:32:43 INFO list-kcfg in cluster:k8s-01

USER                           TYPE            EXPIRY(+8h if in Asia/Shanghai)
---------------------------------------------------------------------------------

2021-01-24 16:32:43 INFO list-kcfg k8s-01 success

初始情况下列表为空

  • 2.增加集群k8s-01一个自定义用户kubeconfig,用户名user01,期限24h,只读权限
text
ezctl kcfg-adm k8s-01 -A -u user01 -e 24h -t view
2021-01-24 17:32:33 INFO add-kcfg k8s-01
2021-01-24 17:32:33 INFO add-kcfg in cluster:k8s-01 with user:user01-202101241732

PLAY [localhost] *****************************************************************************************************

...(此处省略输出) 

TASK [deploy : debug] ************************************************************************************************
ok: [localhost] => {
    "msg": "查看user01-202101241732自定义kubeconfig:/etc/kubeasz/clusters/k8s-01/ssl/users/user01-202101241732.kubeconfig"
}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=12   changed=10   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

2021-01-24 17:32:41 INFO add-kcfg k8s-01 success

生成的kubeconfig位于 /etc/kubeasz/clusters/k8s-01/ssl/users/user01-202101241732.kubeconfig

  • 3.再增加一个用户user02,期限240h,admin权限
text
ezctl kcfg-adm k8s-01 -A -u user02 -e 240h -t admin
2021-01-24 18:38:47 INFO add-kcfg k8s-01
2021-01-24 18:38:47 INFO add-kcfg in cluster:k8s-01 with user:user02-202101241838

PLAY [localhost] *****************************************************************************************************

...(此处省略输出)

TASK [deploy : debug] ************************************************************************************************
ok: [localhost] => {
    "msg": "查看user02-202101241838自定义kubeconfig:/etc/kubeasz/clusters/k8s-01/ssl/users/user02-202101241838.kubeconfig"
}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=12   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

2021-01-24 18:38:55 INFO add-kcfg k8s-01 success
  • 4.再次查看集群k8s-01当前自定义kubeconfig
text
ezctl kcfg-adm k8s-01 -L
2021-01-24 18:40:30 INFO list-kcfg k8s-01
2021-01-24 18:40:30 INFO list-kcfg in cluster:k8s-01

USER                           TYPE            EXPIRY(+8h if in Asia/Shanghai)
---------------------------------------------------------------------------------
user02-202101241838            cluster-admin   2021-02-03T10:34:00Z
user01-202101241732            view            2021-01-25T09:28:00Z

2021-01-24 18:40:31 INFO list-kcfg k8s-01 success
  • 5.删除user01-202101241732 权限
bash
ezctl kcfg-adm k8s-01 -D -u user01-202101241732
2021-01-24 21:41:50 INFO del-kcfg k8s-01
2021-01-24 21:41:50 INFO del-kcfg in cluster:k8s-01 with user:user01-202101241732
clusterrolebinding.rbac.authorization.k8s.io "crb-user01-202101241732" deleted
2021-01-24 21:41:50 INFO del-kcfg k8s-01 success

ezctl kcfg-adm k8s-01 -L
2021-01-24 21:42:02 INFO list-kcfg k8s-01
2021-01-24 21:42:02 INFO list-kcfg in cluster:k8s-01

USER                           TYPE            EXPIRY(+8h if in Asia/Shanghai)
---------------------------------------------------------------------------------
user02-202101241838            cluster-admin   2021-02-03T10:34:00Z

2021-01-24 21:42:02 INFO list-kcfg k8s-01 success

Op/Loadballance Ingress Nodeport

配置负载转发 ingress nodeport

向集群外暴露 ingress-controller 本身的服务端口(80/443/8080)一般有以下三种方法:

  • 1.部署ingress-controller时使用hostNetwork: true,这样就可以直接使用上述端口,可能与host已listen端口冲突
  • 2.部署ingress-controller时使用LoadBalancer类型服务,需要集群支持LoadBalancer
  • 3.部署ingress-controller时使用nodePort类型服务,然后在集群外使用 haproxy/f5 等配置 virtual server 集群

本文档讲解使用 haproxy 配置 ingress的 VS 集群,前提是配置了自建ex_lb节点

1.配置 ex_lb 参数开启转发 ingress nodeport

bash
# 编辑 roles/ex-lb/defaults/main.yml,配置如下变量
INGRESS_NODEPORT_LB: "yes"
INGRESS_TLS_NODEPORT_LB: "yes"

2.重新配置启动LB节点服务

bash
$ ezctl setup ${集群名} ex-lb

3.验证 ex_lb 节点的 haproxy 服务配置 `/etc/haproxy/haproxy.cfg` 包含如下配置

bash
... 前文省略
listen kube_master
        bind 0.0.0.0:8443
        mode tcp
        option tcplog
        balance roundrobin
        server 192.168.1.1 192.168.1.1:6443 check inter 2000 fall 2 rise 2 weight 1
        server 192.168.1.2 192.168.1.2:6443 check inter 2000 fall 2 rise 2 weight 1

listen ingress-node
        bind 0.0.0.0:80
        mode tcp
        option tcplog
        balance roundrobin
        server 192.168.1.3 192.168.1.3:23456 check inter 2000 fall 2 rise 2 weight 1
        server 192.168.1.4 192.168.1.4:23456 check inter 2000 fall 2 rise 2 weight 1

listen ingress-node-tls
        bind 0.0.0.0:443
        mode tcp
        option tcplog
        balance roundrobin
        server 192.168.1.3 192.168.1.3:23457 check inter 2000 fall 2 rise 2 weight 1
        server 192.168.1.4 192.168.1.4:23457 check inter 2000 fall 2 rise 2 weight 1

验证成功后,我们可以方便的去做配置ingress和配置https ingress实验了。


Op/Op Etcd

管理 etcd 集群

Etcd 集群支持在线改变集群成员节点,可以增加、修改、删除成员节点;不过改变成员数量仍旧需要满足集群成员多数同意原则(quorum),另外请记住集群成员数量变化的影响:

  • 注意:如果etcd 集群有故障节点,务必先删除故障节点,然后添加新节点,参考FAQ
  • 增加 etcd 集群节点, 提高集群稳定性
  • 增加 etcd 集群节点, 提高集群读性能(所有节点数据一致,客户端可以从任意节点读取数据)
  • 增加 etcd 集群节点, 降低集群写性能(所有节点数据一致,每一次写入会需要所有节点数据同步)

备份 etcd 数据

  1. 手动在任意正常 etcd 节点上执行备份:
bash
# snapshot备份
$ ETCDCTL_API=3 etcdctl snapshot save backup.db
# 查看备份
$ ETCDCTL_API=3 etcdctl --write-out=table snapshot status backup.db
  1. 使用 kubeasz 备份
    cluster_name 为 k8s-01
bash
ezctl backup k8s-01

使用 crontab 定时备份示例(使用 容器化的 kubeasz,每日01:01 备份)

text
1 1 * * * /usr/bin/docker exec -i kubeasz ezctl backup k8s-01

备份文件在

text
{{ base_dir }}/clusters/k8s-01/backup

etcd 集群节点操作

执行如下 (假设待操作节点为 192.168.1.11,集群名称test-k8s):

  • 增加 etcd 节点:
bash
# ssh 免密码登录
$ ssh-copy-id 192.168.1.11

# 新增节点
$ ezctl add-etcd test-k8s 192.168.1.11
  • 删除 etcd 节点:$ ezctl del-etcd test-k8s 192.168.1.11

具体操作流程参考 ezctl中 add-etcd/del-etcd 相关函数和playbooks/ 目录的操作剧本

验证 etcd 集群

bash
# 登录任意etcd节点验证etcd集群状态
$ export ETCDCTL_API=3 
$ etcdctl member list

# 验证所有etcd节点服务状态和日志
$ systemctl status etcd
$ journalctl -u etcd -f

参考


Op/Op Index

集群运维管理指南 operation guide


Op/Op Master

管理 kube_master 节点

1.增加 kube_master 节点

新增kube_master节点大致流程为:(参考ezctl 中add-master函数和playbooks/23.addmaster.yml)

  • [可选]新节点安装 chrony 时间同步
  • 新节点预处理 prepare
  • 新节点安装 container runtime
  • 新节点安装 kube_master 服务
  • 新节点安装 kube_node 服务
  • 新节点安装网络插件相关
  • 禁止业务 pod调度到新master节点
  • 更新 node 节点 haproxy 负载均衡并重启

操作步骤

执行如下 (假设待增加节点为 192.168.1.11, 集群名称test-k8s):

bash
# ssh 免密码登录
$ ssh-copy-id 192.168.1.11

# 新增节点
$ ezctl add-master test-k8s 192.168.1.11

# 同理,重复上面步骤再新增节点并自定义nodename
$ ezctl add-master test-k8s 192.168.1.12 k8s_nodename=master-03

验证

bash
# 在新节点master 服务状态
$ systemctl status kube-apiserver 
$ systemctl status kube-controller-manager
$ systemctl status kube-scheduler

# 查看新master的服务日志
$ journalctl -u kube-apiserver -f

# 查看集群节点,可以看到新 master节点 Ready, 并且禁止了POD 调度功能
$ kubectl get node
NAME           STATUS                     ROLES     AGE       VERSION
192.168.1.1    Ready,SchedulingDisabled   <none>    3h        v1.9.3
192.168.1.2    Ready,SchedulingDisabled   <none>    3h        v1.9.3
192.168.1.3    Ready                      <none>    3h        v1.9.3
192.168.1.4    Ready                      <none>    3h        v1.9.3
192.168.1.11   Ready,SchedulingDisabled   <none>    2h        v1.9.3	# 新增 master节点

2.删除 kube_master 节点

删除kube_master节点大致流程为:(参考ezctl 中del-master函数和playbooks/33.delmaster.yml)

  • 检测是否可以删除
  • 迁移节点 pod
  • 删除 master 相关服务及文件
  • 删除 node 相关服务及文件
  • 从集群删除 node 节点
  • 从 ansible hosts 移除节点
  • 在 ansible 控制端更新 kubeconfig
  • 更新 node 节点 haproxy 配置

操作步骤

bash
$ ezctl del-master test-k8s 192.168.1.11  # 假设待删除节点 192.168.1.11

验证

略


Op/Op Node

管理 node 节点

目录

  • 1.增加 kube_node 节点
  • 2.批量增加 kube_node 节点
  • 3.增加非标准ssh端口节点
  • 4.删除 kube_node 节点

1.增加 kube_node 节点

新增kube_node节点大致流程为:(参考ezctl 里面add-node函数 和 playbooks/22.addnode.yml)

  • [可选]新节点安装 chrony 时间同步
  • 新节点预处理 prepare
  • 新节点安装 container runtime
  • 新节点安装 kube_node 服务
  • 新节点安装网络插件相关

操作步骤

执行如下 (假设待增加节点为 192.168.1.11,k8s集群名为 test-k8s):

bash
# ssh 免密码登录
$ ssh-copy-id 192.168.1.11

# 新增节点
$ ezctl add-node test-k8s 192.168.1.11

# 同理,重复上面步骤再新增节点并自定义nodename
$ ezctl add-node test-k8s 192.168.1.12 k8s_nodename=worker-03

验证

bash
# 验证新节点状态
$ kubectl get node

# 验证新节点的网络插件calico 或flannel 的Pod 状态
$ kubectl get pod -n kube-system

# 验证新建pod能否调度到新节点,略

2.批量增加 kube_node 节点

当一次需要新增多台 work 节点时,可使用 add-nodes 一次性提交多个 IP,复用 Ansible 自身的并行能力,避免对每台节点重复 fork ansible-playbook。底层调用的仍然是 playbooks/22.addnode.yml,流程与 add-node 完全一致。

操作步骤

执行如下 (假设待增加节点为 192.168.1.21、192.168.1.22、192.168.1.23,k8s集群名为 test-k8s):

bash
# ssh 免密码登录(每个新节点都需要先做)
$ ssh-copy-id 192.168.1.21
$ ssh-copy-id 192.168.1.22
$ ssh-copy-id 192.168.1.23

# 一次性批量新增节点
$ ezctl add-nodes test-k8s 192.168.1.21 192.168.1.22 192.168.1.23

`add-node` 与 `add-nodes` 如何选择

场景 选用
只新增一台节点 add-node
需要给新节点附带 host_vars(如 ansible_ssh_port=10022、k8s_nodename=worker-03 等) add-node(参见 §3)
一次新增多台节点,且无需为每台节点单独配置 host_vars add-nodes

说明:add-nodes 的所有位置参数都按 IP 校验,不接受 inventory 行内变量。如果批量新增的节点中有部分需要 host_vars,请对这部分节点单独使用 add-node 添加。

3.增加非标准ssh端口节点

假设待添加节点192.168.2.1,ssh 端口 10022;然后执行

bash
$ ssh-copy-id -p 10022 192.168.2.1
$ ezctl add-node test-k8s 192.168.2.1 ansible_ssh_port=10022
  • 注意:如果在添加节点时需要设置其他个性化变量,可以同理在后面不断添加

4.删除 kube_node 节点

删除 node 节点流程:(参考ezctl 里面del-node函数 和 playbooks/32.delnode.yml)

  • 检测是否可以删除
  • 迁移节点上的 pod
  • 删除 node 相关服务及文件
  • 从集群删除 node

操作步骤

bash
$ ezctl del-node test-k8s 192.168.1.11 # 假设待删除节点为 192.168.1.11

验证

略


Op/Upgrade

k8s 集群升级

集群升级存在一定风险,请谨慎操作。

  • 支持k8s相同大版本基础上升级任意小版本,比如当前安装集群为1.25.0,你可以方便的升级到任何1.25.x版本
  • 不建议跨大版本升级,一般大版本更新时k8s api有一些变动

备份etcd数据

  • 自动备份

kubeasz项目也可以如下方便执行备份(假设集群名为k8s-01),详情阅读文档备份恢复

text
dk ezctl backup k8s-01
  • 手动备份 etcd数据,在任意 etcd节点上执行:
bash
# snapshot备份
$ ETCDCTL_API=3 etcdctl snapshot save backup.db
# 查看备份
$ ETCDCTL_API=3 etcdctl --write-out=table snapshot status backup.db

k8s 升级小版本

快速升级k8s小版本,比较常见如Bug修复 特性发布时使用。

  • 首先去官网release下载待升级的k8s版本,例如https://dl.k8s.io/v1.25.4/kubernetes-server-linux-amd64.tar.gz

  • 解压下载的tar.gz文件,找到如下kube*开头的二进制,复制替换kubeasz控制端目录/etc/kubeasz/bin对应文件

    • kube-apiserver
    • kube-controller-manager
    • kubectl
    • kubelet
    • kube-proxy
    • kube-scheduler
  • 切换当前所在集群为升级集群, 在kubeasz控制端执行dk ezctl checkout k8s-01

  • 在kubeasz控制端执行dk ezctl upgrade k8s-01 即可完成k8s 升级,不会中断业务应用

其他升级说明

其他升级是指升级k8s组件包括:etcd版本 docker版本,一般不需要用到,不建议升级,以下仅作说明。

  • 1.下载所有组件相关新的二进制解压并替换 /etc/kubeasz/bin/ 目录下文件

  • 2.升级 etcd: ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml -t upgrade_etcd playbooks/02.etcd.yml

  • 3.升级 docker (建议使用k8s官方支持的docker稳定版本)

    • 如果可以接受短暂业务中断,执行 ansible-playbook -t upgrade_docker 03.docker.yml
    • 如果要求零中断升级,执行 ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml -t download_docker playbooks/03.runtime.yml,然后手动执行如下
      • 待升级节点,先应用kubectl cordon和kubectl drain命令迁移业务pod
      • 待升级节点执行 systemctl restart docker
      • 恢复节点可调度 kubectl uncordon

Mixes/Conformance

关于K8S集群一致性认证

CNCF 一致性认证项目(https://github.com/cncf/k8s-conformance) 可以很方便帮助k8s搭建者和用户确认集群各项功能符合预期,既符合k8s设计标准。

kubeasz 通过一致性测试

自kubeasz 3.0.0 版本,k8s v1.20.2开始,正式通过cncf一致性认证,成为cncf 官方认证安装工具;后续k8s主要版本发布或者kubeasz有大版本更新,会优先确保通过集群一致性认证。

Conformance Test

按照测试文档,注意以下几点:

1.解决qiang的问题,可以临时去国外公有云创建集群,然后运行测试项目。

2.集群要保障资源,建议3个节点

3.网络组件选择calico,其他组件可能有bug导致特定测试项失败

附:测试流程

Node Provisioning

Provision 3 nodes for your cluster (OS: Ubuntu 20.04)

1 master node (4c16g)

2 worker node (4c16g)

for a High-Availability Kubernetes Cluster, read more

Install the cluster

(1) Download 'kubeasz' code, the binaries and offline images

text
export release=3.6.9
curl -C- -fLO --retry 3 https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
chmod +x ./ezdown
./ezdown -D -m ''

(2) install an all-in-one cluster

text
./ezdown -S
source ~/.bashrc
dk ezctl start-aio

(3) Add two worker nodes

text
ssh-copy-id ${worker1_ip}
dk ezctl add-node default ${worker1_ip}

ssh-copy-id ${worker2_ip}
dk ezctl add-node default ${worker2_ip}

Run Conformance Test

The standard tool for running these tests is
Sonobuoy. Sonobuoy is
regularly built and kept up to date to execute against all
currently supported versions of kubernetes.

Download a binary release of the CLI

Deploy a Sonobuoy pod to your cluster with:

text
$ sonobuoy run --plugin-env=e2e.E2E_EXTRA_ARGS="--ginkgo.v" --mode=certified-conformance

NOTE: You can run the command synchronously by adding the flag --wait but be aware that running the Conformance tests can take an hour or more.

View actively running pods:

text
$ sonobuoy status

To inspect the logs:

text
$ sonobuoy logs

Once sonobuoy status shows the run as completed, copy the output directory from the main Sonobuoy pod to a local directory:

text
$ outfile=$(sonobuoy retrieve)

This copies a single .tar.gz snapshot from the Sonobuoy pod into your local
. directory. Extract the contents into ./results with:

text
mkdir ./results; tar xzf $outfile -C ./results

NOTE: The two files required for submission are located in the tarball under plugins/e2e/results/{e2e.log,junit.xml}.

To clean up Kubernetes objects created by Sonobuoy, run:

text
sonobuoy delete

Mixes/Donate

捐赠

如果觉得本项目对您有帮助,请小小鼓励下项目作者,谢谢!

支付宝码(左)和微信钱包码(右)


Mixes/DoneList

前言

kubeasz项目开始于2017.11,半年多时间以来,从最开始单一的ansible部署脚本朝着提供部署高可用 K8S集群的完整解决方案的目标不断前进,接下去项目的发展需要各位的共同参与和贡献,希望越做越好,为国内k8s学习、实践者提供更多帮助。

项目已完成部分

类型 描述 备注
集群部署 服务器基础安全加固与参数优化 已完成
基础服务 集群监控告警-prometheus 已完成基础,待优化
应用服务 jenkins集成 已完成
集群部署 kube-router网络插件 已完成
基础服务 metrics server 已完成
集群部署 ipvs代理模式跟进 已完成
集群部署 cilium网络插件 已完成
集群部署 集群内时间同步-Chrony 已完成

Mixes/HowToContribute

为项目`kubeasz`提交`pull request`

首先请核对下本地git config配置的用户名和邮箱与你github上的注册用户和邮箱一致,否则即使pull request被接受,贡献者列表中也看不到自己的名字,设置命令:

bash
$ git config --global user.email "[email protected]"
$ git config --global user.name "Your Name"
  • 1.登录github,在本项目页面点击fork到自己仓库
  • 2.clone 自己的仓库到本地:git clone https://github.com/xxx/kubeasz.git
  • 3.在 master 分支添加原始仓库为上游分支:git remote add upstream https://github.com/easzlab/kubeasz.git
  • 4.在本地新建开发分支:git checkout -b dev
  • 5.在开发分支修改代码并提交:git add ., git commit -am 'xx变更说明'
  • 6.切换至 master 分支,同步原始仓库:git checkout master, git pull upstream master
  • 7.切换至 dev 分支,合并本地 master 分支(已经和原始仓库同步),可能需要解冲突:git checkout dev, git merge master
  • 8.提交本地 dev 分支到自己的远程 dev 仓库:git push origin dev
  • 9.在github自己仓库页面,点击Compare & pull request给原始仓库发 pull request 请求
  • a.等待原作者回复(接受/拒绝)

Guide/Argocd

argocd 安装

用 GitOps 方式把 Kubernetes 声明式配置“自动、可观测、可回滚”地同步到集群的控制器;它是 Kubernetes 世界里 GitOps 的事实标准。

初始安装

  • 建议使用helm chart 方式基础安装;后续用声明式方式配置cluster、project、repository等

服务暴露

  • 建议使用ingress方式
  • 备用:kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'

密码登录

  • 获取初始化密码 argocd admin initial-password -n argocd
  • 登录 argocd login {nodeIP}:{nodePort}
  • 更新密码 argocd account update-password
  • 重置遗忘密码
text
kubectl -n argocd patch secret argocd-secret -p '{"data": {"admin.password": null, "admin.passwordMtime": null}}'
kubectl -n argocd delete pods -l app.kubernetes.io/name=argocd-server

SSO 登录

text
dex.config: |
    connectors:
    - type: oidc
      id: aliyun
      name: aliyun
      config:
        issuer: https://oauth.aliyun.com
        clientID: "406************"
        clientSecret: E8G***************************************************b6
        scopes:
        - profile
        - openid
        - aliuid
        getUserInfo: true
        userIDKey: uid
        userNameKey: uid
        claimMapping:
          preferred_username: name
          email: uid
  • 配置argocd-rbac-cm
text
data:
  policy.csv: |
    # 设置普通用户app-dev 只读权限
    p, role:app-dev, projects, get, *, allow
    p, role:app-dev, applications, get, *, allow
    p, role:app-dev, logs, get, *, allow
    p, role:app-dev, exec, create, */*, allow

    # 设置测试项目,所有权限
    p, role:app-dev, applications, *, test-project/*, allow
    
    # 阿里云子账号 ID:2***********84
    g, "2***********84", role:admin
    g, "2***********27", role:app-dev

  policy.default: role:''
  scopes: '[name]'

支持 application in any namespace

  • 配置 argocd-cm
text
data:
  # 设置argocd 资源标记方式,使用annotation,禁用labelKey
  # application.instanceLabelKey: argocd.argoproj.io/instance
  application.resourceTrackingMethod: annotation
  • 配置 argocd-cmd-params-cm
text
data:
  #application.namespaces: app-team-one, app-team-two
  application.namespaces: '*'
  applicationsetcontroller.allowed.scm.providers: '*'
  applicationsetcontroller.namespaces: '*'

然后重启 argocd-server 和 argocd-application-controller

其他设置

text
# 修改argocd-cm configmap,重启argocd-application-controller
data:
  resource.customizations: |
    networking.k8s.io/Ingress:
      health.lua: |
        hs = {}
        hs.status = "Healthy"
        hs.message = "Skip health check for Ingress"
        return hs

Guide/Chrony

chrony 时间同步

在安装k8s集群前需确保各节点时间同步;chrony 是一个优秀的 NTP 实现,性能比ntp好,且配置管理方便;它既可作时间服务器服务端,也可作客户端。

  • OpenStack 社区也推荐使用 chrony实现各节点之间的时间同步

安装配置介绍

项目中选定一个节点(groups.chrony[0])作为集群内部其他节点的时间同步源,而这个节点本身从公网源同步;当然如果整个集群都无法访问公网,那么请手动校准这个节点的时间后,仍旧可以作为内部集群的时间源服务器。

  • 配置 chrony server,详见roles/chrony/templates/server.conf.j2

  • 配置 chrony client,详见roles/chrony/templates/client.conf.j2

`kubeasz` 集成安装

  • 修改 clusters/${cluster_name}/hosts 文件,在 chrony组中加入选中的节点ip
  • [可选] 修改 clusters/${cluster_name}/config.yml 中的相关配置
    -执行命令安装 ezctl setup ${cluster_name} 01

验证安装

  • 检查chronyd服务状态 systemctl status chronyd
  • 检查chronyd时间同步日志 /var/log/chrony

验证时间同步状态完成

chrony 服务启动后,chrony server 会与配置的公网参考时间服务器进行同步;server 同步完成后,chrony client 会与 server 进行时间同步;一般来说整个集群达到时间同步需要几十分钟。可以用如下命令检查,初始时 NTP synchronized: no,同步完成后 NTP synchronized: yes

bash
$ ansible -i clusters/${cluster_name}/hosts all -m shell -a 'timedatectl'
192.168.1.1 | SUCCESS | rc=0 >>
      Local time: Sat 2019-01-26 11:51:51 HKT
  Universal time: Sat 2019-01-26 03:51:51 UTC
        RTC time: Sat 2019-01-26 03:51:52
       Time zone: Asia/Hong_Kong (HKT, +0800)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no

192.168.1.4 | SUCCESS | rc=0 >>
      Local time: Sat 2019-01-26 11:51:51 HKT
  Universal time: Sat 2019-01-26 03:51:51 UTC
        RTC time: Sat 2019-01-26 03:51:52
       Time zone: Asia/Hong_Kong (HKT, +0800)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no

192.168.1.2 | SUCCESS | rc=0 >>
      Local time: Sat 2019-01-26 11:51:51 HKT
  Universal time: Sat 2019-01-26 03:51:51 UTC
        RTC time: Sat 2019-01-26 03:51:52
       Time zone: Asia/Hong_Kong (HKT, +0800)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no

192.168.1.3 | SUCCESS | rc=0 >>
      Local time: Sat 2019-01-26 11:51:51 HKT
  Universal time: Sat 2019-01-26 03:51:51 UTC
        RTC time: Sat 2019-01-26 03:51:52
       Time zone: Asia/Hong_Kong (HKT, +0800)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no

Guide/Dashboard.1.6.3

dashboard

本文档基于 dashboard 1.6.3版本,从 1.7.x 版本以后,dashboard 默认开启自带的登录验证界面,登录流程差异详见2.x 版本。

  • 注意:实际测试k8s版本<=1.9.1支持dashboard 1.6.3, 建议k8s 1.9 以后使用 dashboard 新版本。

部署

bash
# 部署dashboard 主yaml配置文件
$ kubectl create -f /etc/kubeasz/manifests/dashboard/1.6.3/kubernetes-dashboard.yaml
# 部署基本密码认证配置[可选],密码文件位于 /etc/kubernetes/ssl/basic-auth.csv
$ kubectl create -f /etc/kubeasz/manifests/dashboard/1.6.3/ui-admin-rbac.yaml
$ kubectl create -f /etc/kubeasz/manifests/dashboard/1.6.3/ui-read-rbac.yaml

请在另外窗口打开 kubernetes-dashboard.yaml

  • 由于 kube-apiserver 启用了 RBAC授权,dashboard使用的 ServiceAccount kubernetes-dashboard 必须有相应的权限去访问apiserver(在新版本1.8.0中,该访问权限已按最小化方式授权),在1.6.3 版本,先粗放一点,把kubernetes-dashboard 与 集群角色 cluster-admin 绑定,这样dashboard就拥有了所有访问apiserver的权限。
  • 开发测试环境为了方便配置dashboard-service时候,指定 NodePort方式暴露服务,这样集群外部可以使用 http://NodeIP:NodePort 方式直接访问 dashboard,生产环境建议关闭该访问途径。

验证

bash
# 查看pod 运行状态
kubectl get pod -n kube-system | grep dashboard
kubernetes-dashboard-86bd8778bf-w4974      1/1       Running   0          12h
# 查看dashboard service
kubectl get svc -n kube-system|grep dashboard
kubernetes-dashboard   NodePort    10.68.7.67      <none>        80:5452/TCP	12h
# 查看集群服务
kubectl cluster-info|grep dashboard
kubernetes-dashboard is running at https://192.168.1.10:6443/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy
# 查看pod 运行日志,关注有没有错误
kubectl logs kubernetes-dashboard-86bd8778bf-w4974 -n kube-system

访问

因为dashboard 作为k8s 原生UI,能够展示各种资源信息,甚至可以有修改、增加、删除权限,所以有必要对访问进行认证和控制,本项目预置部署的集群有以下安全设置:详见 apiserver配置模板

  • 启用 TLS认证 RBAC授权等安全特性
  • 关闭 apiserver非安全端口8080的外部访问--insecure-bind-address=127.0.0.1
  • 关闭匿名认证--anonymous-auth=false
  • 补充启用基本密码认证 --token-auth-file=/etc/kubernetes/ssl/basic-auth.csv,密码文件模板中按照每行(密码,用户名,序号)的格式,可以定义多个用户

1. 临时访问:使用 `http://NodeIP:NodePort` 方式直接访问 dashboard,生产环境建议关闭该途径

2. 用户+密码访问:安全性比证书方式差点,务必保管好密码文件`basic-auth.csv`

  • 这里演示两种权限,使用admin 登录dashboard拥有所有权限,使用readonly 登录后仅查看权限,首先在 master节点文件 /etc/kubernetes/ssl/basic-auth.csv 确认用户名和密码,如果要增加或者修改用户,修改保存该文件后记得逐个重启你的master 节点
  • 为了演示用户密码访问,如果你已经完成证书访问方式,你可以在浏览器删除证书,或者访问时候浏览器询问你证书时不选证书
  • 2.1 设置用户admin 的RBAC 权限,如下运行配置文件 kubectl create -f ui-admin-rbac.yaml
bash
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ui-admin
rules:
- apiGroups:
  - ""
  resources:
  - services
  - services/proxy
  verbs:
  - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ui-admin-binding
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ui-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: admin
  • 2.2 设置用户readonly 的RBAC 权限,如下运行配置文件 kubectl create -f ui-read-rbac.yaml
bash
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ui-read
rules:
- apiGroups:
  - ""
  resources:
  - services
  - services/proxy
  verbs:
  - get
  - list
  - watch

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ui-read-binding
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ui-read
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: readonly
  • 2.3 访问 https://x.x.x.x:6443/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy 使用 admin登录拥有所有权限,比如删除某个部署;使用 readonly登录只有查看权限,尝试删除某个部署会提示错误 forbidden: User \"readonly\" cannot delete services/proxy in the namespace \"kube-system\"

3. 证书访问:最安全的方式,配置较复杂

  • 使用集群CA 生成客户端证书,可以根据需要生成权限不同的证书,这里为了演示直接使用 kubectl使用的证书和key(在03.kubectl.yml阶段生成),该证书拥有所有权限
  • 指定格式导出该证书,进入/etc/kubernetes/ssl目录,使用命令openssl pkcs12 -export -in admin.pem -inkey admin-key.pem -out kube-admin.p12 提示输入证书密码和确认密码,可以用密码再增加一层保护,也可以直接回车跳过,完成后目录下多了 kube-admin.p12文件,将它分发给授权的用户
  • 用户将 kube-admin.p12 双击导入证书即可,IE 和Chrome 中输入https://x.x.x.x:6443/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy 或者 https://x.x.x.x:6443/ui 即可访问。补充:最新firefox需要在浏览器中单独导入 [选项] - [隐私与安全] - [证书/查看证书] - [您的证书] 页面点击 [导入] 该证书

小结

  • dashboard 版本 1.6.3 访问控制实现较复杂,文档中给出的例子也有助于你理解 RBAC的灵活控制能力,当然最好去官方文档学习一下,这块篇幅不长
  • 由于还未部署 Heapster 插件,当前 dashboard 不能展示 Pod、Nodes 的 CPU、内存等 metric 图形,后续部署 heapster后自然能够看到
  • 本文中的权限设置仅供演示用,生产环境请在此基础上修改成适合你安全需求的方式

Guide/Dashboard.2.X

dashboard

本文档基于 dashboard 2.2 版本,k8s 1.22 版本,因 dashboard 1.7 以后默认开启了自带的登录验证机制,因此不同版本登录有差异:

  • 旧版(<= 1.6)建议通过apiserver访问,直接通过apiserver 认证授权机制去控制 dashboard权限,详见旧版文档
  • 新版(>= 1.7)可以使用自带的登录界面,使用不同Service Account Tokens 去控制访问 dashboard的权限

部署

参考 https://github.com/kubernetes/dashboard

  • 增加了通过api-server方式访问dashboard
  • 增加了NodePort方式暴露服务,这样集群外部可以使用 https://NodeIP:NodePort (注意是https不是http,区别于1.6.3版本) 直接访问 dashboard。

安装部署

bash
# ezctl 集成部署组件,xxxx 代表集群部署名
# dashboard 部署文件位于 /etc/kubeasz/clusters/xxxx/yml/dashboard/ 目录
./ezctl setup xxxx 07

验证部署

bash
# 查看pod 运行状态
kubectl get pod -n kube-system | grep dashboard
dashboard-metrics-scraper-856586f554-l6bf4   1/1     Running   0          35m
kubernetes-dashboard-698d4c759b-67gzg        1/1     Running   0          35m

# 查看dashboard service
kubectl get svc -n kube-system|grep dashboard
kubernetes-dashboard   NodePort    10.68.219.38   <none>        443:24108/TCP                   53s

# 查看pod 运行日志
kubectl logs -n kube-system kubernetes-dashboard-698d4c759b-67gzg

登陆

因为dashboard 作为k8s 原生UI,能够展示各种资源信息,甚至可以有修改、增加、删除权限,所以有必要对访问进行认证和控制,为演示方便这里使用 https://NodeIP:NodePort 方式访问 dashboard,支持两种登录方式:Kubeconfig、令牌(Token)

注意: 使用chrome浏览器访问 https://NodeIP:NodePort 可能提示安全风险无法访问,可以换firefox浏览器设置安全例外,继续访问。

  • Token令牌方式登录(admin)

选择 Token 方式登录,复制下面输出的admin token 字段到输入框

bash
# 获取 Bearer Token,找到输出中 ‘token:’ 开头的后面部分
$ kubectl describe -n kube-system secrets admin-user
  • Token令牌方式登录(只读)

选择 Token 方式登录,复制下面输出的read token 字段到输入框

bash
# 获取 Bearer Token,找到输出中 ‘token:’ 开头的后面部分
$ kubectl describe -n kube-system secrets dashboard-read-user
  • Kubeconfig登录(admin)
    Admin kubeconfig文件默认位置:/root/.kube/config,该文件中默认没有token字段,使用Kubeconfig方式登录,还需要将token追加到该文件中,完整的文件格式如下:
text
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdxxxxxxxxxxxxxx
    server: https://192.168.1.2:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: admin
  name: kubernetes
current-context: kubernetes
kind: Config
preferences: {}
users:
- name: admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRxxxxxxxxxxx
    client-key-data: LS0tLS1CRUdJTxxxxxxxxxxxxxx
    token: eyJhbGcixxxxxxxxxxxxxxxx

参考


Guide/Dashboard

dashboard(已废弃)

Kubernetes Dashboard 已归档,不再维护。本项目推荐使用 Headlamp 作为 Kubernetes Web UI。

部署(已废弃)

本文档基于 dashboard 7.12.0 版本,k8s 1.32 版本,dashboard 7.0.0 以后引入大量不兼容变化。
假设已经使用kubeasz 部署k8s集群完成;新版dashboard 部署如下:(以单机集群为例,其他情况请修改集群名称'default'为实际的名称)

bash
# 1. 修改 clusters/default/config.yml 文件,设置 dashboard_install: "yes"

# 2. 下载dashboard 需要的镜像
./ezdown -X dashboard

# 3. 执行安装,配置文件位于 clusters/default/yml/dashboard/ 目录
dk ezctl setup default 07
  • 增加NodePort方式暴露服务,这样集群外部可以使用 https://NodeIP:NodePort (注意是https不是http) 直接访问 dashboard。

验证

bash
# 查看pod 运行状态
kubectl get pod -n kube-system |grep kubernetes-dashboard
kubernetes-dashboard-api-6d77cb7964-4tklq               1/1     Running   0          17h
kubernetes-dashboard-auth-5fbd64f659-f9dst              1/1     Running   0          17h
kubernetes-dashboard-kong-6dcdbf5dfd-829h4              1/1     Running   0          17h
kubernetes-dashboard-metrics-scraper-7757c48476-4lcrq   1/1     Running   0          17h
kubernetes-dashboard-web-5f9f47979-7khrk                1/1     Running   0          17h

# 查看service
kubectl get svc -n kube-system |grep kong
kubernetes-dashboard-kong-proxy        NodePort    10.68.148.170   <none>   443:31544/TCP  17h

登陆

因为dashboard 作为k8s 原生UI,能够展示各种资源信息,甚至可以有修改、增加、删除权限,所以有必要对访问进行认证和控制,为演示方便这里使用 https://NodeIP:NodePort 方式访问 dashboard,目前支持登录方式:令牌(Token)

注意: 使用chrome浏览器访问 https://NodeIP:NodePort 可能提示安全风险无法访问,可以换firefox浏览器设置安全例外,继续访问。

  • Token令牌方式登录(admin)

选择 Token 方式登录,复制下面输出的admin token 字段到输入框

bash
# 获取 Bearer Token,找到输出中 ‘token:’ 开头的后面部分
$ kubectl describe -n kube-system secrets admin-user
  • Token令牌方式登录(只读)

选择 Token 方式登录,复制下面输出的read token 字段到输入框

bash
# 获取 Bearer Token,找到输出中 ‘token:’ 开头的后面部分
$ kubectl describe -n kube-system secrets dashboard-read-user

参考


Guide/Harbor

harbor 镜像仓库

Habor是由VMWare中国团队开源的企业级容器镜像仓库。特性包括:友好的用户界面,基于角色的访问控制,水平扩展,同步复制,AD/LDAP集成以及审计日志等。本文档仅说明单机安装harbor 服务。

  • 目录
    • 安装步骤
    • 安装讲解
    • 配置docker/containerd信任harbor证书
    • 在k8s集群使用harbor
    • 管理维护

安装步骤

  1. 下载离线安装包,成功后在/etc/kubeasz/down/目录下有离线包harbor-offline-installer-$HARBOR_VER.tgz
text
ezdown -D
ezdown -R
  1. 利用ezctl 文档 创建一个新的集群,已有集群修改同样的文件
text
#clusters/xxx/hosts 中修改如下,配置harbor组下机器,设置NEW_INSTALL=true
...
# 'NEW_INSTALL': 'true' to install a harbor server; 'false' to integrate with existed one
[harbor]
192.168.1.8 NEW_INSTALL=true
...

#clusters/xxx/config.yml 中修改如下,按需修改HARBOR_DOMAIN/HARBOR_TLS_PORT 等配置项,举例如下
############################
# role:harbor
############################
# harbor version,完整版本号
HARBOR_VER: "v2.10.2"
HARBOR_DOMAIN: "harbor.yourdomain.com"
HARBOR_PATH: /var/data
HARBOR_TLS_PORT: 8443
HARBOR_REGISTRY: "{{ HARBOR_DOMAIN }}:{{ HARBOR_TLS_PORT }}"

# if set 'false', you need to put certs named harbor.pem and harbor-key.pem in directory 'down'
HARBOR_SELF_SIGNED_CERT: true

# install component
HARBOR_WITH_TRIVY: false
  1. 配置完成后,执行 ./ezctl setup xxx harbor,完成harbor安装和docker 客户端配置
  • 安装验证
  1. 在harbor节点使用docker ps -a 查看harbor容器组件运行情况
  2. 浏览器访问地址(忽略证书报错) https://${HARBOR_DOMAIN}:${HARBOR_TLS_PORT},管理员账号是 admin ,密码见harbor.yml文件 harbor_admin_password 对应值(默认密码 Harbor12345 已被随机生成的16位随机密码替换,不然存在安全隐患)

安装讲解

根据playbooks/11.harbor.yml文件,harbor节点需要以下步骤:

  • role os-harden 系统安全加固(可选)
  • role chrony 时间同步服务(可选)
  • role prepare 基础系统环境准备
  • role docker 安装docker
  • role harbor 安装harbor
  • 注意:kube_node节点在harbor部署完之后,需要配置harbor的证书(详见下节配置docker/containerd信任harbor证书),并可以在hosts里面添加harbor的域名解析,如果你的环境中有dns服务器,可以跳过hosts文件设置
  1. 下载docker-compose可执行文件到$PATH目录
  2. 自注册变量result判断是否已经安装harbor,避免重复安装问题
  3. 解压harbor离线安装包到指定目录
  4. 导入harbor所需 docker images
  5. 创建harbor证书和私钥(复用集群的CA证书)
  6. 修改harbor.yml配置文件
  7. 启动harbor安装脚本

在k8s集群使用harbor

admin用户web登录后可以方便的创建项目,并指定项目属性(公开或者私有);然后创建用户,并在项目成员选项中选择用户和权限;

镜像上传

使用docker客户端登录{{ HARBOR_REGISTRY }},然后把镜像tag成 {{ HARBOR_REGISTRY }}/$项目名/$镜像名:$TAG 之后,即可使用docker push 上传

bash
docker login harbor.test.com
Username: 
Password:
Login Succeeded
docker tag busybox:latest harbor.test.com/library/busybox:latest
docker push harbor.test.com/library/busybox:latest
The push refers to a repository [harbor.test.com/library/busybox]
0271b8eebde3: Pushed 
latest: digest: sha256:91ef6c1c52b166be02645b8efee30d1ee65362024f7da41c404681561734c465 size: 527

k8s中使用harbor

  1. 如果镜像保存在harbor中的公开项目中,那么只需要在yaml文件中简单指定harbor私有镜像即可,例如
bash
apiVersion: v1
kind: Pod
metadata:
  name: test-busybox
spec:
  containers:
  - name: test-busybox
    image: harbor.test.com/xxx/busybox:latest
    imagePullPolicy: Always
  1. 如果镜像保存在harbor中的私有项目中,那么yaml文件中使用该私有项目的镜像需要指定imagePullSecrets,例如
bash
apiVersion: v1
kind: Pod
metadata:
  name: test-busybox
spec:
  containers:
  - name: test-busybox
    image: harbor.test.com/xxx/busybox:latest
    imagePullPolicy: Always
  imagePullSecrets:
  - name: harborkey1

其中 harborKey1可以用以下两种方式生成:

  • 1.使用 kubectl create secret docker-registry harborkey1 --docker-server=harbor.test.com --docker-username=admin --docker-password=Harbor12345 [email protected]
  • 2.使用yaml配置文件生成
bash
//harborkey1.yaml
apiVersion: v1
kind: Secret
metadata:
  name: harborkey1
  namespace: default
data:
    .dockerconfigjson: {base64 -w 0 ~/.docker/config.json}
type: kubernetes.io/dockerconfigjson

前面docker login会在~/.docker下面创建一个config.json文件保存鉴权串,这里secret yaml的.dockerconfigjson后面的数据就是那个json文件的base64编码输出(-w 0让base64输出在单行上,避免折行)

管理维护

  • 日志目录 /var/log/harbor
  • 数据目录 /var/data ,其中最主要是 /var/data/database 和 /var/data/registry 目录,如果你要彻底重新安装harbor,删除这两个目录即可

先进入harbor安装目录 cd /var/data/harbor,常规操作如下:

  1. 暂停harbor docker-compose stop : docker容器stop,并不删除容器
  2. 恢复harbor docker-compose start : 恢复docker容器运行
  3. 停止harbor docker-compose down -v : 停止并删除docker容器
  4. 启动harbor docker-compose up -d : 启动所有docker容器

修改harbor的运行配置,需要如下步骤:

bash
# 停止 harbor
 docker-compose down -v
# 修改配置
 vim harbor.yml
# 执行./prepare已更新配置到docker-compose.yml文件
 ./prepare
# 启动 harbor
 docker-compose up -d

Guide/Headlamp

headlamp

Kubernetes Dashboard 已归档,不再维护;本项目推荐使用 Headlamp 作为 Kubernetes Web UI。Headlamp 支持桌面客户端和集群内两种运行方式,本文介绍在集群内通过 Helm 安装的方法。

集成部署

假设已经使用kubeasz 部署k8s集群完成;headlamp 部署如下:(以单机集群为例,其他情况请修改集群名称'default'为实际的名称)

bash
# 1. 修改 clusters/default/config.yml 文件,设置 headlamp_install: "yes"

# 2. 下载需要的镜像
./ezdown -X headlamp

# 3. 执行安装,配置文件位于 clusters/default/yml/headlamp/ 目录
dk ezctl setup default 07

验证

bash
# 查看 Pod 运行状态
kubectl get pod -n kube-system -l app.kubernetes.io/name=headlamp

# 查看 Service
kubectl get svc -n kube-system headlamp
  • 增加NodePort方式暴露服务,这样集群外部可以使用 http://NodeIP:NodePort 直接访问 headlamp。

登陆

Headlamp 使用 Kubernetes RBAC 控制资源访问权限。桌面客户端会直接使用本机 kubeconfig;集群内访问可使用 ServiceAccount Token 或 OIDC 登录。

  • Token令牌方式登录(admin)

选择 Token 方式登录,复制下面输出的admin token 字段到输入框

bash
# 获取 Bearer Token,找到输出中 ‘token:’ 开头的后面部分
$ kubectl describe -n kube-system secrets admin-user
  • Token令牌方式登录(只读)

选择 Token 方式登录,复制下面输出的read token 字段到输入框

bash
# 获取 Bearer Token,找到输出中 ‘token:’ 开头的后面部分
$ kubectl describe -n kube-system secrets dashboard-read-user

将输出的 Token 粘贴到 Headlamp 登录页。以上两个内置的token 仅用于演示;生产环境应根据实际角色创建最小权限的 RBAC 规则,避免长期使用高权限 Token。

参考


Guide/Helm

Helm

Helm致力于成为k8s集群的应用包管理工具,希望像linux 系统的RPM DPKG那样成功;确实在k8s上部署复杂一点的应用很麻烦,需要管理很多yaml文件(configmap,controller,service,rbac,pv,pvc等等),而helm能够整齐管理这些文档:版本控制,参数化安装,方便的打包与分享等。

  • 建议积累一定k8s经验以后再去使用helm;对于初学者来说手工去配置那些yaml文件对于快速学习k8s的设计理念和运行原理非常有帮助,而不是直接去使用helm,面对又一层封装与复杂度。
  • 本文基于helm 3(建议版本),helm 2 文档请看这里

安装 helm

在官方repo下载release版本中自带的二进制文件即可(以Linux amd64为例)

text
wget https://get.helm.sh/helm-v3.2.1-linux-amd64.tar.gz
mv ./linux-amd64/helm /usr/bin
  • 启用官方 charts 仓库
text
helm repo add stable https://kubernetes-charts.storage.googleapis.com/

国内镜像

text
helm repo add stable http://mirror.azure.cn/kubernetes/charts

使用 helm 安装应用

helm3 安装命令与 helm2 稍有变化,个人习惯先下载对应charts到本地然后按照固定目录格式安装,以创建一个redis集群举例:

  • 创建 redis-cluster 目录
bash
mkdir -p /opt/charts/redis-cluster
cd /opt/charts/redis-cluster
  • 下载最新stalbe/redis-ha
text
helm repo update
helm pull stable/redis-ha
  • 解压 charts,复制 values.yaml设置
text
tar zxvf redis-ha-*.tgz
cp redis-ha/values.yaml .
  • 创建 start.sh 脚本记录启动命令
text
cat > start.sh << EOF
#!/bin/sh
set -x

ROOT=$(cd `dirname $0`; pwd)
cd $ROOT

helm install redis \
	--create-namespace \
	--namespace dependency \
	-f ./values.yaml \
	./redis-ha
EOF
  • 查看当前目录结构如下
text
tree .
.
├── redis-ha		# redis-ha 原始charts目录
├── start.sh		# 启动命名脚本
└── values.yaml		# 个性化参数配置
  • 修改当前目录的 values.yaml 为你的个性化配置
bash
#举例values.yaml 配置如下,没有启用PV
#cat values.yaml
image:
  repository: redis
  tag: 5.0.6-alpine

replicas: 2

## Redis specific configuration options
redis:
  port: 6379
  masterGroupName: "mymaster"       # must match ^[\\w-\\.]+$) and can be templated
  config:
    ## For all available options see http://download.redis.io/redis-stable/redis.conf
    min-replicas-to-write: 1
    min-replicas-max-lag: 5   # Value in seconds
    maxmemory: "4g"       # Max memory to use for each redis instance. Default is unlimited.
    maxmemory-policy: "allkeys-lru"  # Max memory policy to use for each redis instance. Default is volatile-lru.
    repl-diskless-sync: "yes"
    rdbcompression: "yes"
    rdbchecksum: "yes"

  resources:
    requests:
      memory: 200Mi
      cpu: 100m
    limits:
      memory: 4000Mi

## Sentinel specific configuration options
sentinel:
  port: 26379
  quorum: 1

  resources:
    requests:
      memory: 200Mi
      cpu: 100m
    limits:
      memory: 200Mi

hardAntiAffinity: true

## Configures redis with AUTH (requirepass & masterauth conf params)
auth: false

persistentVolume:
  enabled: false

hostPath:
  path: "/data/mcs-redis/{{ .Release.Name }}"
  • 执行安装
text
bash ./start.sh
  • 查看安装
text
helm ls -A
NAME 	NAMESPACE 	REVISION	UPDATED                                	STATUS  	CHART         	APP VERSION
redis	dependency	1       	2020-05-28 20:57:31.166002853 +0800 CST	deployed	redis-ha-4.4.4	5.0.6

# 查看k8s上资源
kubectl get pod,svc -n dependency
NAME                          READY   STATUS    RESTARTS   AGE
pod/redis-redis-ha-server-0   2/2     Running   0          119s
pod/redis-redis-ha-server-1   2/2     Running   0          104s

NAME                                TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)              AGE
service/redis-redis-ha              ClusterIP   None          <none>        6379/TCP,26379/TCP   119s
service/redis-redis-ha-announce-0   ClusterIP   10.68.41.65   <none>        6379/TCP,26379/TCP   119s
service/redis-redis-ha-announce-1   ClusterIP   10.68.64.49   <none>        6379/TCP,26379/TCP   119s

Guide/Hpa

Horizontal Pod Autoscaling

自动水平伸缩,是指运行在k8s上的应用负载(POD),可以根据资源使用率进行自动扩容、缩容;我们知道应用的资源使用率通常都有高峰和低谷,所以k8s的HPA特性应运而生;它也是最能体现区别于传统运维的优势之一,不仅能够弹性伸缩,而且完全自动化!

根据 CPU 使用率或自定义 metrics 自动扩展 Pod 数量(支持 replication controller、deployment);k8s1.6版本之前是通过kubelet来获取监控指标,1.6版本之后是通过api server、heapster或者kube-aggregator来获取监控指标。

Metrics支持

根据不同版本的API中,HPA autoscale时靠以下指标来判断资源使用率:

  • autoscaling/v1: CPU
  • autoscaling/v2alpha1
    • 内存
    • 自定义metrics
    • 多metrics组合: 根据每个metric的值计算出scale的值,并将最大的那个值作为扩容的最终结果

基础示例

本实验环境基于k8s 1.8 和 1.9,仅使用autoscaling/v1 版本API,注意确保k8s 集群插件kubedns 和 heapster 工作正常。

bash
# 创建deploy和service
$ kubectl run php-apache --image=pilchard/hpa-example --requests=cpu=200m --expose --port=80

# 创建autoscaler
$ kubectl autoscale deploy php-apache --cpu-percent=50 --min=1 --max=10

# 等待3~5分钟查看hpa状态
$ kubectl get hpa php-apache
NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0% / 50%   1         10        1          3m

# 增加负载
$ kubectl run --rm -it load-generator --image=busybox /bin/sh
Hit enter for command prompt
$ while true; do wget -q -O- http://php-apache; done;

# 等待约5分钟查看hpa显示负载增加,且副本数目增加为4
$ kubectl get hpa php-apache
NAME         REFERENCE               TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   430% / 50%   1         10        4          4m

# 注意k8s为了避免频繁增删pod,对副本的增加速度有限制
# 实验过程可以看到副本数目从1到4到8到10,大概都需要4~5分钟的缓冲期
$ kubectl get hpa php-apache
NAME         REFERENCE               TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   86% / 50%   1         10        8          9m
$ kubectl get hpa php-apache
NAME         REFERENCE               TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   52% / 50%   1         10        10         12m

# 清除负载,CTRL+C 结束上述循环程序,稍后副本数目变回1
$ kubectl get hpa php-apache
NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0% / 50%   1         10        1          17m

Guide/Index

使用指南

附加组件安装

基础特性演示


Guide/Ingress

Ingress简介

本文档已过期,安装最新版本,请参考相关官方文档。

ingress就是从外部访问k8s集群的入口,将用户的URL请求转发到不同的service上。ingress相当于nginx反向代理服务器,它包括的规则定义就是URL的路由信息;它的实现需要部署Ingress controller(比如 traefik ingress-nginx 等),Ingress controller通过apiserver监听ingress和service的变化,并根据规则配置负载均衡并提供访问入口,达到服务发现的作用。

  • 未配置ingress:

集群外部 -> NodePort -> K8S Service

  • 配置ingress:

集群外部 -> Ingress -> K8S Service

  • 注意:ingress 本身也需要部署Ingress controller时使用以下几种方式让外部访问

    • 使用NodePort方式
    • 使用hostPort方式
    • 使用LoadBalancer地址方式
  • 以下讲解基于Traefik,如果想要了解ingress-nginx的原理与实践,推荐阅读博客烂泥行天下的相关文章

部署 Traefik

Traefik 提供了一个简单好用 Ingress controller,下文侧重讲解 ingress部署和测试例子。请查看yaml配置 traefik-ingress.yaml,参考traefik 官方k8s例子

安装 traefik ingress-controller

bash
kubectl create -f /etc/kubeasz/manifests/ingress/traefik/traefik-ingress.yaml
  • 注意需要配置 RBAC授权
  • 注意trafik pod中 80端口为 traefik ingress-controller的服务端口,8080端口为 traefik 的管理WEB界面;为后续配置方便指定80 端口暴露NodePort端口为 23456(对应于在hosts配置中NODE_PORT_RANGE范围内可用端口)

验证 traefik ingress-controller

bash
# kubectl get deploy -n kube-system traefik-ingress-controller
NAME                         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
traefik-ingress-controller   1         1         1            1           4m

# kubectl get svc -n kube-system traefik-ingress-service
NAME                      TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                       AGE
traefik-ingress-service   NodePort   10.68.69.170   <none>        80:23456/TCP,8080:34815/TCP   4m
  • 可以看到traefik-ingress-service 服务端口80暴露的nodePort确实为23456

测试 ingress

  • 首先创建测试用K8S应用,并且该应用服务不用nodePort暴露,而是用ingress方式让外部访问
bash
kubectl run test-hello --image=nginx:alpine --expose --port=80
##
# kubectl get deploy test-hello
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
test-hello   1         1         1            1           56s
# kubectl get svc test-hello
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
test-hello   ClusterIP   10.68.124.115   <none>        80/TCP    1m
  • 然后为这个应用创建 ingress,kubectl create -f /etc/kubeasz/manifests/ingress/test-hello.ing.yaml
bash
# test-hello.ing.yaml内容
apiVersion: networking.k8s.io/v1beta1 
kind: Ingress
metadata:
  name: test-hello
spec:
  rules:
  - host: hello.test.com
    http:
      paths:
      - path: /
        backend:
          serviceName: test-hello
          servicePort: 80
  • 集群内部尝试访问: curl -H Host:hello.test.com 10.68.69.170(traefik-ingress-service的服务地址) 能够看到欢迎页面 Welcome to nginx!;
  • 在集群外部尝试访问(假定集群一个NodeIP为 192.168.1.1): curl -H Host:hello.test.com 192.168.1.1:23456,也能够看到欢迎页面 Welcome to nginx!,说明ingress测试成功

为 traefik WEB 管理页面创建 ingress 规则

kubectl create -f /etc/kubeasz/manifests/ingress/traefik/traefik-ui.ing.yaml

bash
# traefik-ui.ing.yaml内容
---
apiVersion: networking.k8s.io/v1beta1 
kind: Ingress
metadata:
  name: traefik-web-ui
  namespace: kube-system
spec:
  rules:
  - host: traefik-ui.test.com
    http:
      paths:
      - path: /
        backend:
          serviceName: traefik-ingress-service
          servicePort: 8080
  • 在集群外部可以使用 curl -H Host:traefik-ui.test.com 192.168.1.1:23456 尝试访问WEB管理页面,返回 [Found](/dashboard/).说明 traefik-ui的ingress配置生效了。

  • 在客户端主机也可以通过修改本机 hosts 文件,如上例子,增加两条记录:

text
192.168.1.1	hello.test.com
192.168.1.1	traefik-ui.test.com

打开浏览器输入域名 http://hello.test.com:23456 和 http://traefik-ui.test.com:23456 就可以访问k8s的应用服务了。

可选1: 使用`LoadBalancer`服务类型来暴露ingress,自有环境(非公有云)可以参考[metallb文档](metallb.md)

bash
# 修改traefik-ingress 使用 LoadBalancer服务
$ sed -i 's/NodePort$/LoadBalancer/g' /etc/kubeasz/manifests/ingress/traefik/traefik-ingress.yaml
# 创建traefik-ingress
$ kubectl apply -f /etc/kubeasz/manifests/ingress/traefik/traefik-ingress.yaml
# 验证
$ kubectl get svc --all-namespaces |grep traefik
kube-system   traefik-ingress-service   LoadBalancer   10.68.163.243   192.168.1.241   80:23456/TCP,8080:37088/TCP   1m

这时可以修改客户端本机 hosts文件:(如上例192.168.1.241)

text
192.168.1.241     hello.test.com
192.168.1.241     traefik-ui.test.com

打开浏览器输入域名 http://hello.test.com 和 http://traefik-ui.test.com可以正常访问。

可选2: 部署`ingress-service`的负载均衡

  • 利用 nginx/haproxy 等集群,可以做代理转发以去掉 23456这个端口。如果你的集群根据本项目部署了高可用方案,那么可以利用LB 节点haproxy 来做,当然如果生产环境K8S应用已经部署非常多,建议还是使用独立的 nginx/haproxy集群。

具体参考配置转发 ingress nodePort,如上配置访问集群MASTER_IP的80端口时,由haproxy代理转发到实际的node节点暴露的nodePort端口上了。这时可以修改客户端本机 hosts文件如下:(假定 MASTER_IP=192.168.1.10)

text
192.168.1.10     hello.test.com
192.168.1.10    traefik-ui.test.com

打开浏览器输入域名 http://hello.test.com 和 http://traefik-ui.test.com可以正常访问。

下一步[配置https ingress](ingress-tls.md)