高可用K8S搭建(Ubuntu18.04)

内容纲要

注意

本文资料整理自网络,对其中过时部分进行修正!
运行环境为:KVM 虚拟机(先根据下文第一部分制作基础镜像,再用基础镜像克隆为各个 master、worker 节点,可以节省时间)
适用版本为:
操作系统:Ubuntu18.04
Kubeadm:GitVersion:"v1.17.3"
K8S组件版本如下:
kube-apiserver:v1.17.4
kube-controller-manager:v1.17.4
kube-scheduler:v1.17.4
kube-proxy:v1.17.4
pause:3.1
etcd:3.4.3-0
coredns:1.6.5

第一部分—-基础镜像准备

Harbor 安装

详见

确保节点之中不可以有重复的主机名、MAC 地址或 product_uuid

hostname 修改
  • Ubuntu:hostnamectl set-hostname xxx
    查看 product_uuid

    sudo cat /sys/class/dmi/id/product_uuid

关闭防火墙(生产环境不建议关闭)

systemctl stop ufw
systemctl disable ufw
注意 ↓
生产环境,建议启用防火墙,并开启 etcd、apiserver等多个端口

关闭 swap

查看 swap:$cat /proc/swaps
注释 swap 设置:$vim /etc/fstab
关闭 swap:$swapoff -a

禁用 GRUB ipv6

编辑:$vim /etc/default/grub
修改:

GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""

GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1"
GRUB_CMDLINE_LINUX="ipv6.disable=1"

更新:$update-grub

设置对应时区(如上海)

执行:$ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

设置 DNS

编辑:$vim /etc/systemd/resolved.conf
修改:

# 地址来自阿里 DNS
DNS=223.5.5.5 223.6.6.6 

升级操作系统内核

参考自青木のJava小屋

查看本机内核:$uname -a

注意 ↓
可以根据实际情况[选择版本](http://kernel.ubuntu.com/~kernel-ppa/mainline/)

执行:$dpkg -i xxx.deb升级内核(可使用通配符)

清理旧内核:$dpkg --list | grep linux | awk '{print $2}' | grep 旧内核版本 | xargs apt purge -y

注意 ↓
内核操作风险较大,请一步步确认没问题再执行!

启用 IPVS 内核模块

执行:

echo > /etc/modules-load.d/ipvs.conf
module=(ip_vs
        ip_vs_rr
        ip_vs_wrr
        ip_vs_sh
        ip_vs_lc
        br_netfilter
        nf_conntrack)
for kernel_module in ${module[@]};do
    /sbin/modinfo -F filename $kernel_module |& grep -qv ERROR && echo $kernel_module >> /etc/modules-load.d/ipvs.conf || :
done

查看:$lsmod | grep ip_vs
输出如下信息为成功 ↓

ip_vs_sh               16384  0
ip_vs_wrr              16384  0
ip_vs_rr               16384  0
ip_vs                 147456  6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack          143360  6 xt_conntrack,nf_nat,ipt_MASQUERADE,nf_nat_ipv4,nf_conntrack_netlink,ip_vs
libcrc32c              16384  5 nf_conntrack,nf_nat,btrfs,raid456,ip_vs

内核参数调整

cat > /etc/sysctl.conf << EOF
# http://github.com/moby/moby/issues/31208 
# ipvsadm -l --timout
# 修复ipvs模式下长连接timeout问题 小于900即可
net.ipv4.tcp_keepalive_time = 800
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.ip_forward = 1
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.bridge.bridge-nf-call-arptables = 1
vm.swappiness = 0
vm.max_map_count=262144
EOF

确保 iptables 工具不使用 nftables 后端

切换旧版(Ubuntu)
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy

docker-ce 安装

安装依赖系统工具:$apt install -y apt-transport-http ca-certificates curl software-properties-common
安装GPG证书:$curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
写入源:$add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
执行:$apt update
安装 docker-ce:$apt install -y docker-ce(另可指定版本号安装指定版本)
设置镜像加速,可以选择阿里云镜像加速服务,详见阿里云镜像加速页面文档

docker-compose 安装

执行:

curl -L http://github.com/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Kubeadm 套件安装(国内)

新增源文件:$vim /etc/apt/sources.list.d/kubernetes.list
写入源:$deb http://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
执行:$apt update 得到错误信息的 key 的末尾8位
执行:$gpg --keyserver keyserver.ubuntu.com --recv-keys 【8位key】
执行:$gpg --export --armor 【8位key】 | sudo apt-key add -
再次执行:$apt update
安装 Kubeadm 套件:$apt install -y kubelet kubeadm kubectl

第二部分—-高可用集群搭建

注意 ↓
本文高可用模式为:ETCD 高可用 + API-Server 高可用
ETCD:由于 ETCD 使用 Raft 算法,所以节点一般为奇数个,本文使用3个节点
API-Server:本文使用3个节点

Nginx 本地代理

用于访问 master 节点,并在其中某些 master 节点不可用时,自动访问可用节点。
可以部署在每一台 K8S 节点上部署,也可另外部署外部 Nginx 负载均衡节点,本文在每台 K8S 节点上均有部署

配置 master 节点 hosts
cat >> /etc/hosts << EOF
127.0.0.1 server.k8s.local
10.0.0.65 server1.k8s.local
10.0.0.66 server2.k8s.local
10.0.0.67 server3.k8s.local
EOF
注意 ↓
IP 请跟请根据实际情况替换
编写 Nginx 配置文件
mkdir -p /etc/nginx
cat > /etc/nginx/nginx.conf << EOF
worker_processes auto;
user root;
events {
    worker_connections  20240;
    use epoll;
}
error_log /var/log/nginx_error.log info;

stream {
    upstream kube-servers {
        hash $remote_addr consistent;
        server server1.k8s.local:6443 weight=5 max_fails=1 fail_timeout=3s;
        server server2.k8s.local:6443 weight=5 max_fails=1 fail_timeout=3s;
        server server3.k8s.local:6443 weight=5 max_fails=1 fail_timeout=3s;
    }

    server {
        listen 8443 reuseport;
        proxy_connect_timeout 3s;
        # 加大timeout
        proxy_timeout 3000s;
        proxy_pass kube-servers;
    }
}
EOF
启动 Nginx
docker run --restart=always \
-v /etc/apt/sources.list:/etc/apt/sources.list \
-v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf \
--name kps \
--net host \
-it \
-d \
nginx

高可用外部 ETCD 集群搭建

注意 ↓
由于 etcd 不需要对外开放,所以本文不使用 tls
启动参数[注意事项](http://qingmu.io/2019/05/17/Deploy-a-highly-available-cluster-with-kubeadm/#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9):
--auto-compaction-retention
由于ETCD数据存储多版本数据,随着写入的主键增加历史版本需要定时清理,默认的历史数据是不会清理的,数据达到2G就不能写入,必须要清理压缩历史数据才能继续写入;所以根据业务需求,在上生产环境之前就提前确定,历史数据多长时间压缩一次;推荐一小时压缩一次数据这样可以极大的保证集群稳定,减少内存和磁盘占用

--max-request-bytes
etcd Raft消息最大字节数,ETCD默认该值为1.5M; 但是很多业务场景发现同步数据的时候1.5M完全没法满足要求,所以提前确定初始值很重要;由于1.5M导致我们线上的业务无法写入元数据的问题,我们紧急升级之后把该值修改为默认32M,但是官方推荐的是10M,大家可以根据业务情况自己调整

--quota-backend-bytes
ETCD db数据大小,默认是2G,当数据达到2G的时候就不允许写入,必须对历史数据进行压缩才能继续写入;参加1里面说的,我们启动的时候就应该提前确定大小,官方推荐是8G,这里我们也使用8G的配置

在 etcd 集群个节点主机上运行如下命令(注意修改中括号内对应的信息):

mkdir -p /var/etcd
docker rm [name] -f
rm -rf /var/etcd/*
docker run --restart=always --net host -it --name [name] -d \
-v /var/etcd:/var/etcd \
-v /etc/localtime:/etc/localtime \
[仓库名]/etcd:[版本号] \
etcd --name [etcd name] \
--auto-compaction-retention "1h" --max-request-bytes "33554432" --quota-backend-bytes "8589934592" \
--data-dir=/var/etcd/etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://[本节点域名或IP]:2380 \
--advertise-client-urls http://[本节点域名或IP]:2379,http://[本节点域名或IP]:2380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "[本机 etcd name]=http://[本节点域名或IP]:2380,[其他etcd name1]=http://[其他节点域名或IP]:2380,[其他etcd name2]=http://[其他节点域名或IP]:2380" \
-initial-cluster-state new
测试 etcd 集群

进入正在运行的 etcd 容器:$docker exec -it [name] sh
查看集群状态:$etcdctl --write-out=table --endpoints="http://[节点域名或IP]:2379,http://[节点域名或IP]:2379,http://[节点域名或IP]:2379" endpoint status
查看集群健康:$etcdctl --write-out=table --endpoints="http://[节点域名或IP]:2379,http://[节点域名或IP]:2379,http://[节点域名或IP]:2379" endpoint health

测试集群可用性:

# 任意节点存入数据
etcdctl put /test/key "123"
# 任意节点取出数据,取出正常,集群可用
etcdctl get /test/key

API-Server(Master) 高可用

配置自定义 kubeadm-config.yaml
注意 ↓
注意修改对应的版本号,仓库路径等
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.17.0
imageRepository: [仓库路径]
apiServer:
  extraArgs:
    storage-backend: etcd3
  extraVolumes:
    - hostPath: /etc/localtime
      mountPath: /etc/localtime
      name: localtime
  certSANs:
    - "prod-server.k8s.local"
    - "server1.k8s.local"
    - "server2.k8s.local"
    - "server3.k8s.local"
    - "127.0.0.1"
    - "10.0.0.65"
    - "10.0.0.66"
    - "10.0.0.67"
    - "kubernetes"
    - "kubernetes.default"
    - "kubernetes.default.svc"
    - "kubernetes.default.svc.cluster"
    - "kubernetes.default.svc.cluster.local"
controllerManager:
  extraArgs:
    experimental-cluster-signing-duration: 867000h
  extraVolumes:
    - hostPath: /etc/localtime
      mountPath: /etc/localtime
      name: localtime
scheduler:
  extraVolumes:
    - hostPath: /etc/localtime
      mountPath: /etc/localtime
      name: localtime
networking:
  # pod 网段
  podSubnet: 172.224.0.0/12
  # SVC 网络
  serviceSubnet: 10.96.0.0/12
controlPlaneEndpoint: server.k8s.local:8443
etcd:
  external:
    endpoints:
      - http://server1.k8s.local:2379
      - http://server2.k8s.local:2379
      - http://server3.k8s.local:2379
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
ipvs:
  scheduler: lc
  minSyncPeriod: 5s
  syncPeriod: 15s
初始化 Master

执行:$kubeadm init --config=kubeadm-config.yaml --upload-certs

注意 ↓
--config=kubeadm-config.yaml 为上一步骤编写的文件
--upload-certs 参数将证书上传到 etcd 中,后续不需要手动分发

初始化结束,控制台输出:
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:
复制并执行下列命令:可以以普通用户操作集群
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
http://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:
复制并执行下列命令:其余 master 可以加入到到该集群
kubeadm join server.k8s.local:8443 –token uue99t.w9cenfznjoo2e1u6 \
–discovery-token-ca-cert-hash sha256:afd406ce180ce4c9271c0e7b4c3381df72cd75e766f934fd439d101ae1022a43 \
–control-plane –certificate-key 1621bb7101d2fa4050779aaa753e89d49ee7db57129b6b4986c82b45fb4dcbe5

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs –upload-certs" to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:
复制并执行下列命令:worker 可以加入到到该集群
kubeadm join server.k8s.local:8443 –token uue99t.w9cenfznjoo2e1u6 \
–discovery-token-ca-cert-hash sha256:afd406ce180ce4c9271c0e7b4c3381df72cd75e766f934fd439d101ae1022a43

注意 ↓
以上命令中出现的 hash、key 需要跟使用者安装后出现的一致,不可直接复制使用!
Token 失效(24小时)可以使用命令重新生成 ↓
`kubeadm token create --print-join-command`

Master(--control-plane --certificate-key)(2小时失效)↓
`kubeadm init phase upload-certs --upload-certs --config kubeadm-config.yaml`
master 测试

执行:$kubectl get node 可以查看集群是否加入成功(可以显示加入集群内的所有节点)
执行:$kubectl get pod -A 可以查看所有集群内正在运行的pod(检查 apiserver、controller-manager、proxy、scheduler 是否是 running 状态,coredns 目前为 pending 状态)

结束

至此,高可用 K8S 安装成功。

甜点

集群重置:$kubeadm reset

注意 ↓
如果是外接 ETCD ,需要清空外接 ETCD 数据:$`etcdctl del "" --prefix`

参考链接
在阿里云的VPC部署高可用kubernetes

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注