使用kubespray搭建生产级高可用集群

简介

之前都是使用kubeadm去搭建kubernetes集群的,虽然说是简单很多了,但是对于一些操作比如添加一个节点,删除一个节点,还有节点安装前的一些初始化操作都是很繁杂的,不是难,是因为节点一多,有时候就要使用ansible去一个一个推送,不是特别的方便,除了kubeadm,kubernetes还推荐了另外一种给予ansible的安装工具kubespray,这个时候如果你是从openstack时代过来的,你会不得不想到这个项目https://github.com/openstack/openstack-ansible,历史总是惊人的相似,想当年,用openstack-ansible去部署openstack的时候我还刚毕业,一眨眼2年就这样子过去了。

环境介绍

下面是我的环境

主机名 ip 配置 系统
k8s-master1.bboysoul.cn 10.10.10.161 4c4g centos7
k8s-master2.bboysoul.cn 10.10.10.162 4c4g centos7
k8s-master3.bboysoul.cn 10.10.10.163 4c4g centos7
k8s-slave1.bboysoul.cn 10.10.10.164 4c4g centos7
k8s-slave2.bboysoul.cn 10.10.10.165 4c4g centos7
k8s-slave3.bboysoul.cn 10.10.10.166 4c4g centos7

没错6个节点 3个主节点 3个从节点 k8s-master1.bboysoul.cn用来做ansible部署节点

基础环境的要求

官方要求你的基础环境至少要下面这样

  • 你想安装的kubernetes要v1.16以上,这里我们使用默认的v1.18.5,你可以在下面这个文件修改集群的版本./inventory/sample/group_vars/k8s-cluster
  • Ansible v2.9+, Jinja 2.11+ 和 python-netaddr 要安装在机器上
  • 目标机器要允许访问互联网,对于大中华局域网最好使用离线安装
  • 目标机器配置了ipv4转发
  • 防火墙(firewalld)是关闭的
  • 推荐使用root安装

硬件配置

master内存: 大于1500m
slave内存: 大于1024m

安装前配置

配置免密登陆哦

ssh-keygen

ssh-copy-id root@10.10.10.161
ssh-copy-id root@10.10.10.162
ssh-copy-id root@10.10.10.163
ssh-copy-id root@10.10.10.164
ssh-copy-id root@10.10.10.165
ssh-copy-id root@10.10.10.166

接着下载下项目

git clone https://github.com/kubernetes-sigs/kubespray.git

安装ansible

yum install ansible

安装python3-pip

yum install python3-pip

配置k8s群组

sudo vim /etc/ansible/hosts

添加

1
2
3
4
5
6
7
8
[k8s]

10.10.10.161 ansible_ssh_user=root
10.10.10.162 ansible_ssh_user=root
10.10.10.163 ansible_ssh_user=root
10.10.10.164 ansible_ssh_user=root
10.10.10.165 ansible_ssh_user=root
10.10.10.166 ansible_ssh_user=root

测试

ansible k8s -m ping

配置ipv4转发

ansible k8s -m shell -a 'echo net.ipv4.ip_forward = 1 >> /etc/sysctl.conf && sysctl -p'

关闭防火墙

ansible k8s -m shell -a 'systemctl stop firewalld && systemctl disable firewalld'

安装依赖生成主机配置

安装依赖

pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/

生成主机配置文件

cp -rfp inventory/sample inventory/mycluster

declare -a IPS=(10.10.10.161 10.10.10.162 10.10.10.163 10.10.10.164 10.10.10.165 10.10.10.166)

CONFIG_FILE=inventory/mycluster/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]}

修改一下主机配置文件,把master节点改为3个

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
all:
hosts:
node1:
ansible_host: 10.10.10.161
ip: 10.10.10.161
access_ip: 10.10.10.161
node2:
ansible_host: 10.10.10.162
ip: 10.10.10.162
access_ip: 10.10.10.162
node3:
ansible_host: 10.10.10.163
ip: 10.10.10.163
access_ip: 10.10.10.163
node4:
ansible_host: 10.10.10.164
ip: 10.10.10.164
access_ip: 10.10.10.164
node5:
ansible_host: 10.10.10.165
ip: 10.10.10.165
access_ip: 10.10.10.165
node6:
ansible_host: 10.10.10.166
ip: 10.10.10.166
access_ip: 10.10.10.166
children:
kube-master:
hosts:
node1:
node2:
node3:
kube-node:
hosts:
node1:
node2:
node3:
node4:
node5:
node6:
etcd:
hosts:
node1:
node2:
node3:
k8s-cluster:
children:
kube-master:
kube-node:
calico-rr:
hosts: {}

离线下载配置

对于我们国家的运维来说很多人都死在这一步,但是好在现在的镜像站什么的都很多,没有的自己直接搭建镜像站就好,但是前提是你要有一个国外的服务器

文档说你只需要修改下面这些参数既可实现在局域网内安装k8s

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
# Registry overrides
gcr_image_repo: "{{ registry_host }}"
docker_image_repo: "{{ registry_host }}"
quay_image_repo: "{{ registry_host }}"

kubeadm_download_url: "{{ files_repo }}/kubernetes/{{ kube_version }}/kubeadm"
kubectl_download_url: "{{ files_repo }}/kubernetes/{{ kube_version }}/kubectl"
kubelet_download_url: "{{ files_repo }}/kubernetes/{{ kube_version }}/kubelet"
# etcd is optional if you **DON'T** use etcd_deployment=host
etcd_download_url: "{{ files_repo }}/kubernetes/etcd/etcd-{{ etcd_version }}-linux-amd64.tar.gz"
cni_download_url: "{{ files_repo }}/kubernetes/cni/cni-plugins-linux-{{ image_arch }}-{{ cni_version }}.tgz"
crictl_download_url: "{{ files_repo }}/kubernetes/cri-tools/crictl-{{ crictl_version }}-{{ ansible_system | lower }}-{{ image_arch }}.tar.gz"
# If using Calico
calicoctl_download_url: "{{ files_repo }}/kubernetes/calico/{{ calico_ctl_version }}/calicoctl-linux-{{ image_arch }}"

# CentOS/Redhat
## Docker
docker_rh_repo_base_url: "{{ yum_repo }}/docker-ce/$releasever/$basearch"
docker_rh_repo_gpgkey: "{{ yum_repo }}/docker-ce/gpg"
## Containerd
extras_rh_repo_base_url: "{{ yum_repo }}/centos/$releasever/extras/$basearch"
extras_rh_repo_gpgkey: "{{ yum_repo }}/containerd/gpg"

# Fedora
## Docker
docker_fedora_repo_base_url: "{{ yum_repo }}/docker-ce/{{ ansible_distribution_major_version }}/{{ ansible_architecture }}"
docker_fedora_repo_gpgkey: "{{ yum_repo }}/docker-ce/gpg"
## Containerd
containerd_fedora_repo_base_url: "{{ yum_repo }}/containerd"
containerd_fedora_repo_gpgkey: "{{ yum_repo }}/docker-ce/gpg"

# Debian
## Docker
docker_debian_repo_base_url: "{{ debian_repo }}/docker-ce"
docker_debian_repo_gpgkey: "{{ debian_repo }}/docker-ce/gpg"
## Containerd
containerd_debian_repo_base_url: "{{ ubuntu_repo }}/containerd"
containerd_debian_repo_gpgkey: "{{ ubuntu_repo }}/containerd/gpg"
containerd_debian_repo_repokey: 'YOURREPOKEY'

# Ubuntu
## Docker
docker_ubuntu_repo_base_url: "{{ ubuntu_repo }}/docker-ce"
docker_ubuntu_repo_gpgkey: "{{ ubuntu_repo }}/docker-ce/gpg"
## Containerd
containerd_ubuntu_repo_base_url: "{{ ubuntu_repo }}/containerd"
containerd_ubuntu_repo_gpgkey: "{{ ubuntu_repo }}/containerd/gpg"
containerd_ubuntu_repo_repokey: 'YOURREPOKEY'

# If using helm
helm_stable_repo_url: "{{ helm_registry }}"

因为我是centos而且也不需要启动helm,所以修改下面的参数就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Registry overrides
gcr_image_repo: "{{ registry_host }}"
docker_image_repo: "{{ registry_host }}"
quay_image_repo: "{{ registry_host }}"

kubeadm_download_url: "{{ files_repo }}/kubernetes/{{ kube_version }}/kubeadm"
kubectl_download_url: "{{ files_repo }}/kubernetes/{{ kube_version }}/kubectl"
kubelet_download_url: "{{ files_repo }}/kubernetes/{{ kube_version }}/kubelet"
# etcd is optional if you **DON'T** use etcd_deployment=host
etcd_download_url: "{{ files_repo }}/kubernetes/etcd/etcd-{{ etcd_version }}-linux-amd64.tar.gz"
cni_download_url: "{{ files_repo }}/kubernetes/cni/cni-plugins-linux-{{ image_arch }}-{{ cni_version }}.tgz"
crictl_download_url: "{{ files_repo }}/kubernetes/cri-tools/crictl-{{ crictl_version }}-{{ ansible_system | lower }}-{{ image_arch }}.tar.gz"
# If using Calico
calicoctl_download_url: "{{ files_repo }}/kubernetes/calico/{{ calico_ctl_version }}/calicoctl-linux-{{ image_arch }}"

# CentOS/Redhat
## Docker
docker_rh_repo_base_url: "{{ yum_repo }}/docker-ce/$releasever/$basearch"
docker_rh_repo_gpgkey: "{{ yum_repo }}/docker-ce/gpg"
## Containerd
extras_rh_repo_base_url: "{{ yum_repo }}/centos/$releasever/extras/$basearch"
extras_rh_repo_gpgkey: "{{ yum_repo }}/containerd/gpg"

搭建整个集群其实我花在这里的时间是最久的,azure的镜像站已经不对外提供服务了,所以我这里的做法就是把所有的镜像在国外的服务器下载好,然后重新tag,上传到阿里云的镜像仓库上,关于kubeadm和kubectl我也是直接下载,然后上传到阿里云的oss上

最终是下面这个样子

vim inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml

添加

1
2
3
4
5
6
7
8
9
10
11
12
kube_image_repo: "registry.cn-hangzhou.aliyuncs.com/bboysoul-docker"
gcr_image_repo: "gcr.mirrors.ustc.edu.cn"
docker_image_repo: "ksast115s.mirror.aliyuncs.com"
quay_image_repo: "quay.mirrors.ustc.edu.cn"

kubeadm_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/kubeadm"
kubectl_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/kubectl"
kubelet_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/kubelet"
etcd_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/etcd-v3.3.12-linux-amd64.tar.gz"
cni_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/cni-plugins-linux-amd64-v0.8.6.tgz"
crictl_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/crictl-v1.18.0-linux-amd64.tar.gz"
calicoctl_download_url: "https://bboysoul-k8s.oss-cn-hangzhou.aliyuncs.com/calicoctl-linux-amd64"

注意上面的地址目前都不能使用

修改完成之后,我们最好先把每个节点需要下载的镜像全部下载下来,防止之后部署出现问题

ansible-playbook -i inventory/mycluster/hosts.yaml cluster.yml -t download -b -v

还有如果你不知道要下载什么镜像,也可以用这个脚本,碰到不能下载的,你再去国外服务器下载然后重新tag

部署集群

这里我推荐修改下集群的名字

vim inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml

cluster_name: bboysoul.cn

脚本跑完没问题之后就可以部署了

ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml

最后如果你的集群在部署的时候出现了什么问题的话,比如我就碰到了apiserver的镜像因为网络问题没有下载完全导致不能启动的问题,可以使用下面的命令重置集群

ansible-playbook -i inventory/mycluster/hosts.yaml reset.yml

因为不管是重置集群还是安装集群都是一个比较费时间的活,所以我推荐使用screen开一个会话来执行命令,防止因为网络的链接断开导致集群部署失败

给集群的apiserver添加负载均衡

对于一个高可用的集群来说,最重要的是要避免单点故障,我们上面搭建的kubernetes,架构是下面这个样子的

因为始终访问master1会导致master1的负载增高,这就会导致集群的利用率还有性能下降,所以我们最好组合成下面这种状态

这样3个节点的apiserver都得到了利用,避免了因为一个节点不可用,导致的单点故障,同时分摊了请求,集群的利用率得到了提高

使用kubespray做到这一点也很简单,首先我们重置集群

ansible-playbook -i inventory/mycluster/hosts.yaml reset.yml

之后安装haproxy

这里我就直接在master1上安装了,如果是生产,那肯定是单独的一台机器

yum install haproxy

编辑配置文件

vim /etc/haproxy/haproxy.cfg

在最后添加上

1
2
3
4
5
6
7
8
9
10
listen kubernetes-apiserver-https
bind 10.10.10.161:8383
mode tcp
option log-health-checks
timeout client 3h
timeout server 3h
server master1 10.10.10.161:6443 check check-ssl verify none inter 10000
server master2 10.10.10.162:6443 check check-ssl verify none inter 10000
server master3 10.10.10.163:6443 check check-ssl verify none inter 10000
balance roundrobin

因为我就直接是一个节点,我就不创建什么vip了,真正生产应该是下面这个状态

重启haproxy

systemctl restart haproxy

当然你使用nginx也是可以的

yum install nginx

vim /etc/nginx/nginx.conf

添加

1
2
3
4
5
6
7
8
9
10
11
stream {
upstream k8s-apiserver {
server 10.10.10.161:6443;
server 10.10.10.162:6443;
server 10.10.10.163:6443;
}
server {
listen 8080;
proxy_pass k8s-apiserver;
}
}

因为我这边习惯使用nginx,所以就使用nginx做负载了,注意是4层代理不是7层的

接着编辑kubespray配置文件

vim inventory/mycluster/group_vars/all/all.yml

添加修改

1
2
3
4
apiserver_loadbalancer_domain_name: "k8s-api.bboysoul.cn"
loadbalancer_apiserver:
address: 10.10.10.161
port: 8080

之后直接部署

ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml

当然,如果你懒得重新部署的话也可以直接修改配置去添加loadblance

最后部署完成之后你可以看你的kubectl配置文件

cat ~/.kube/config

会发现链接地址变成了

server: https://k8s-api.bboysoul.cn:8080

删除一个节点,添加一个节点

相对于kubeadm,kubespray删除节点也很简单,详细的可以看下面

https://github.com/kubernetes-sigs/kubespray/blob/master/docs/nodes.md

使用下面命令删除node6

ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root remove-node.yml -e node=node6

如果你要重新添加node6,那么直接运行安装的命令就好了

ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml

升级集群

其实这个也很好操作,修改

vim inventory/sample/group_vars/k8s-cluster/k8s-cluster.yml

kube_version: v1.18.5

然后运行

ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root upgrade-cluster.yml

就可以了

详细看下面

https://github.com/kubernetes-sigs/kubespray/blob/master/docs/upgrades.md

欢迎关注Bboysoul的博客www.bboy.app

Have Fun

欢迎关注我的其它发布渠道