KVM虚拟化日志

  • 首页
  • HPC
  • K8S
  • Python
  • 数据库
  • 登录
专注HPC、虚拟化、DevOps、云原生技术
  1. 首页
  2. Ansible
  3. 正文

kubeasz快速创建生产级K8S集群

2025/04/17 76点热度 0人点赞 0条评论

为了便于学习k8s相关技术,需要构建一个简易的k8s学习集群,使用下面的方法我们可以实现快速拉起一套准生产的k8s集群,相较于k3s等all in one集群,有更多的细节和可见性,更加适合学习和理解相关概念。

- 3主2从k8s集群
- 独立的3节点etcd集群
- 独立的2个负载均衡节点
- 独立的NFS存储

## 环境准备

需要准备10台虚拟机,以及一台能够使用ansible的控制节点,我们全部使用Ubuntu 24.04 LTS作为操作系统

| 用途 | 数量 |
| :--------------: | :--: |
| 负载均衡 4C4G | 2 |
| ETCD集群 4C4G | 3 |
| Master节点 4C4G | 3 |
| Worker节点 8C16G | 2 |

## 节点规划

k8s的高可用由控制平面决定,kube-apiserver无状态,提供API服务,通过负载均衡,我们可以实现kube-apiserver的高可用

etcd是k8s集群的分布式存储,使用raft算法实现高可用和数据一致性

nginx是常见的负载均衡器,为一组kube-apiserver提供转发(负载均衡)服务。我们还需要考虑nginx自身的高可用,keepalived是一个基于VRRP协议的解决方案,将多台服务器组成一个虚拟服务器,使用虚拟IP(VIP)绑定到这个虚拟服务器上,然后通过VRRP协议实现IP地址在服务器间的漂移

| IP地址 | 主机名 | 用途 |
| :----------: | :-------------------------: | :---------: |
| 192.168.2.51 | k8s_slb1.cs.metahere.xyz | 负载均衡 |
| 192.168.2.52 | k8s_slb2.cs.metahere.xyz | |
| 192.168.2.53 | k8s_etcd1.cs.metahere.xyz | etcd |
| 192.168.2.54 | k8s_etcd2.cs.metahere.xyz | |
| 192.168.2.55 | k8s_etcd3.cs.metahere.xyz | |
| 192.168.2.56 | k8s_master1.cs.metahere.xyz | k8s控制节点 |
| 192.168.2.57 | k8s_master2.cs.metahere.xyz | |
| 192.168.2.58 | k8s_master3.cs.metahere.xyz | |
| 192.168.2.59 | k8s_worker1.cs.metahere.xyz | k8s负载节点 |
| 192.168.2.60 | k8s_worker2.cs.metahere.xyz | |

## 网络规划

| 网络 | 作用 |
| :------------: | :-----------: |
| 192.168.2.50 | 负载均衡器VIP |
| 192.168.2.0/24 | k8s宿主机网段 |
| 172.16.0.0/14 | Pod网段 |
| 10.88.0.0/16 | Servic网段 |

## ansible环境准备

首先编写inventory

Shell
1
2
3
4
5
6
7
8
9
10
11
12
[slb]
k8s_slb1.cs.metahere.xyz
k8s_slb2.cs.metahere.xyz
 
[etcd]
k8s_etcd[1:3].cs.metahere.xyz
 
[master]
k8s_master[1:3].cs.metahere.xyz
 
[worker]
k8s_worker[1:2].cs.metahere.xyz

 

确保ansible控制节点能够使用以一个免密的普通用户SSH远程登录到这些节点,这个普通用户应当具有sudo权限

## 时间同步

确保所有服务器上的时间同步

Shell
1
2
3
4
ansible all -i inventory -m apt -a "name=chrony state=present" -b
ansible all -i inventory -m shell -a "sudo timedatectl set-timezone Asia/Shanghai" -b
ansible all -i inventory -m shell -a "chronyc makestep" -b
ansible all -i inventory -m shell -a "date -R" -b

 

## 使用kubeasz部署k8s集群

准备执行环境

Shell
1
2
3
4
5
6
7
8
9
10
11
12
# 下载kubeasz
export release=3.6.6
wget https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
chmod +x ./ezdown
# 下载容器镜像等
./ezdown -D
# 下载额外的镜像
./ezdown -X nfs-provisioner
./ezdown -X prometheus
# 启动容器
./ezdown -S
source ~/.bashrc

 

初始化集群配置

Shell
1
docker exec -it kubeasz ezctl new k8s_htl

 

完成后将会生成目录/etc/kubeasz/clusters/k8s_htl,需要手动配置

修改/etc/kubeasz/clusters/k8s_htl/hosts配置etcd、master、worker、ex-lb以及网段规划等

YAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 'etcd' cluster should have odd member(s) (1,3,5,...)
[etcd]
192.168.2.53
192.168.2.54
192.168.2.55
 
# master node(s), set unique 'k8s_nodename' for each node
# CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
# and must start and end with an alphanumeric character
[kube_master]
192.168.2.56 k8s_nodename='master-01'
192.168.2.57 k8s_nodename='master-02'
192.168.2.58 k8s_nodename='master-03'
 
# work node(s), set unique 'k8s_nodename' for each node
# CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
# and must start and end with an alphanumeric character
[kube_node]
192.168.2.59 k8s_nodename='worker-01'
192.168.2.60 k8s_nodename='worker-02'
 
# [optional] harbor server, a private docker registry
# 'NEW_INSTALL': 'true' to install a harbor server; 'false' to integrate with existed one
[harbor]
#192.168.1.8 NEW_INSTALL=false
 
# [optional] loadbalance for accessing k8s from outside
[ex_lb]
192.168.2.51 LB_ROLE=backup EX_APISERVER_VIP=192.168.2.50 EX_APISERVER_PORT=8443
192.168.2.52 LB_ROLE=master EX_APISERVER_VIP=192.168.2.50 EX_APISERVER_PORT=8443
 
# K8S Service CIDR, not overlap with node(host) networking
SERVICE_CIDR="10.88.0.0/16"
 
# Cluster CIDR (Pod CIDR), not overlap with node(host) networking
CLUSTER_CIDR="172.16.0.0/16"
 
# Cluster DNS Domain
CLUSTER_DNS_DOMAIN="htl.cluster.local"
```
 
修改/etc/kubeasz/clusters/k8s_htl/config.yml配置k8s参数,我们需要配置的是其中的镜像下载地址(国内环境需要使用代理)、用于自签证书的IP或者域名(后续使用外部的端口映射或者域名时需要),其他参数需要自行按照需求修改。
 
```bash
INSECURE_REG:
- "http://easzlab.io.local:5000"
- "https://docker.cs.metahere.xyz"
- "https://artifactory.internal.kvmcn.com:50443"
- "https://dockerhub.mirror.432000.xyz"
- "https://dk1.cedu.ac.cn"
- "https://pulldocker.chillifish.cn"
- "https://harbor.cs.metahere.xyz"
 
MASTER_CERT_HOSTS:
- "192.168.2.50"
- "k8s.cs.metahere.xyz"
- "k8s.cs.432000.xyz"
- "k8s.cs.kvmcn.com"

 

开始安装,将会执行ansible roles开始安装etcd和k8s节点,

Shell
1
dk ezctl setup k8s_htl all

 

## 配置kube-api-server的高可用

我们规划了3个master节点,在集群内部已经实现了高可用,但是在集群外部例如我们需要通过其他方式调用k8s API时,也需要考虑到这一点,kubeasz实现了简单的配置方法

Shell
1
dk ezctl setup k8s_htl ex-lb

 

完成后你可以在lb节点查看负载均衡服务的状态

bash
ss -ltp
systemctl status l4lb

## 配置nfs存储

我们需要使用NFS作为持久化的存储,首先配置一个nfs服务器,有条件可以使用netapp或者其他的文件服务器

Shell
1
2
3
4
5
6
7
8
9
10
sudo apt install nfs-kernel-server -y
systemctl status nfs-mountd.service
 
sudo mkdir -p /k8s_data
sudo chown nobody:nogroup /k8s_data
sudo chmod 777 /k8s_data
sudo vim /etc/exports
/k8s_data *(rw,sync,insecure,no_subtree_check,no_root_squash)
sudo exportfs -ra
sudo systemctl enable --now nfs-kernel-server

 

修改/etc/kubeasz/clusters/k8s_htl/config.yml增加nfs相关配置

Shell
1
2
3
4
5
6
nfs_provisioner_install: "yes"
nfs_provisioner_namespace: "kube-system"
nfs_provisioner_ver: "v4.0.2"
nfs_storage_class: "managed-nfs-storage"
nfs_server: "192.168.2.49"
nfs_path: "/k8s_data"

 

开始配置

Shell
1
dk ezctl setup k8s_htl 07

 

验证

Shell
1
kubectl get pod --all-namespaces | grep nfs-client

 

## 配置ingress controller

为了暴露服务到集群外部供用户使用,我们使用ngin作为ingress controller

Shell
1
2
3
4
5
6
7
8
9
10
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm search repo ingress-nginx/ingress-nginx --versions
 
# 使用NodePort暴露ingress的端口
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace nginx --create-namespace \
--set controller.service.type=NodePort
 
kubectl get pods --namespace=nginx

 

创建一个deployment用于验证

Shell
1
2
3
4
5
6
7
8
9
10
kubectl create deployment demo --image=httpd --port=80
kubectl expose deployment demo
 
kubectl create ingress demo-localhost --class=nginx \
--rule="demo.localdev.me/*=demo:80"
 
kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80
 
# 验证结果是否成功,应该输出一个It works!
curl --resolve demo.localdev.me:8080:127.0.0.1 http://demo.localdev.me:8080

 

## 配置ingress controller的高可用

前面我们配置了kube api server的高可用,现在我们还需要配置ingress的高可用,实现服务的不间断访问

![img](http://typora-pics.432000.xyz/uPic/20250417155533_1*KIVa4hUVZxg-8Ncabo8pdg.png)

kubeasz已经实现了这部分的简化操作,我们只需要简单的修改配置文件,即可实现

首先我们需要知道ingress controller的服务端口,结果如下,80端口被映射到

Shell
1
2
3
kubectl get service ingress-nginx-controller --namespace=nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.88.193.16 80:31539/TCP,443:30179/TCP 2d16h

 

修改kubeasz的配置文件

Shell
1
2
3
4
5
6
7
8
9
vim /etc/kubeasz/roles/ex-lb/defaults/main.yml
# 启用 ingress NodePort服务的负载均衡 (yes/no)
INGRESS_NODEPORT_LB: "yes"
# ingress NodePort 的端口号
INGRESS_NODEPORT_LB_PORT: 31539
# 启用 ingress tls NodePort服务的负载均衡 (yes/no)
INGRESS_TLS_NODEPORT_LB: "yes"
# ingress tls NodePort 的端口号
INGRESS_TLS_NODEPORT_LB_PORT: 30179

 

重新配置ex-lb即可,需要按照之前的方式继续到lb节点上查询服务和端口开放状态

Shell
1
dk ezctl setup k8s_htl ex-lb

 

## 配置cert-manager实现服务的自动SSL配置

![README-2021-10-14-20-29-31](http://typora-pics.432000.xyz/uPic/20250417160933_README-2021-10-14-20-29-31.svg)

首先需要安装cert-manager

Shell
1
2
3
4
5
6
7
8
helm repo add jetstack https://charts.jetstack.io --force-update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.17.0 \
--set crds.enabled=true \
--set prometheus.enabled=true \
--set webhook.timeoutSeconds=30

 

创建issuer,我使用cloudflare托管了1个域名,使用cloudflare的API Key创建一个证书签发器,编辑cloudflare-cluster-issuer.yaml

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
stringData:
api-token: ''
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns01
spec:
acme:
privateKeySecretRef:
name: letsencrypt-dns01
email: lixxxx@qq.com
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
key: api-token
name: cloudflare-api-token-secret

 

然后我们应用它即可

Shell
1
2
3
kubectl apply -f cloudflare-cluster-issuer.yaml
kubectl get clusterissuer
kubectl logs -n cert-manager deployment/cert-manager -f

 

我们在上一节创建了一个简易的httpd服务,我们可以使用它来测试自动的ssl证书签发,创建一个demo-ingress.yaml

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-dns01"
namespace: default
spec:
rules:
- host: demo.cs.metahere.xyz
http:
paths:
- backend:
service:
port:
number: 80
name: demo
path: /
pathType: Prefix
tls:
- hosts:
- demo.cs.metahere.xyz
secretName: demo-http-tls
ingressClassName: nginx

 

应用这个ingress

Shell
1
kubectl apply -f demo-ingress.yaml

 

我们需要还需要设置DNS解析到负载均衡VIP的记录,为了简化后续的操作成本,我们在cloudflare中解析*.cs.metahere.xyz*到192.168.2.50

![image-20250417162700039](http://typora-pics.432000.xyz/uPic/20250417162700_image-20250417162700039.png)

等待几分钟后访问demo.cs.metahere.xyz

![image-20250417162723865](http://typora-pics.432000.xyz/uPic/20250417162724_image-20250417162723865.png)

![image-20250417162754789](http://typora-pics.432000.xyz/uPic/20250417162754_image-20250417162754789.png)

可以看到证书是签发成功的,这里可能会遇到的坑比如

- ingress和service需要在同一个namespace
- let's encrypt的速率限制
- cloudflare的API KEY权限不足/不正确(需要配置API KEY对于DNS区域的读写权限,stringData会自动Base64无需手动Base64编码)

标签: ansible k8s
最后更新:2025/10/22

牛牛很忙

这个人很懒,什么都没留下

点赞
下一篇 >
标签聚合
cad fcfs eda iac k8s vcenter ansible terraform

COPYRIGHT © 2025 KVM虚拟化日志. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang