kubernetes集群安装指南:环境准备及初始化系统

本系列文档将介绍使用二进制文件部署最新 kubernetes v1.14.2 集群所有步骤,而不是使用 kubeadm 等自动化方式来部署集群。主要适合于有一定 kubernetes 基础,想通过一步步部署的方式来学习和了解系统相关配置、运行原理的同学。也同样适用于测试或生产自建kubernetes集群等应用场景。

一 环境准备


1.1 版本信息

  • OS 系统: Centos 7.6

  • kubernetes版本:v1.14.2

  • Etcd数据库:v3.3.13

  • Network插件:Flanneld 0.11.0

  • Docker 版本: 18.09.6-CE

  • K8s插件:CoreDns,Heapster,Influxdb,Grafana,Dashboard,elk,Metrics-server

  • Docker仓库:Harbor

1.2 架构概览:

kubernetes集群安装指南:环境准备及初始化系统
其中:

负载均衡

采用keepalived主主模式结合haproxy tcp四层代理为kube apiserver提供高可用架构,内网使用内网VIP地址作为集群内所有组件访问地址;外网采用外网vip地址访问,主要为Internet 客户端访问

master集群:

使用keepalived+haproxy部署apiserver集群高可用;其他组件kube-controller-manager,kube-sheduler利用etcd选举机制,与apiserver组件部署同一node上,在分别部署了三个节点,组成高可用集群;

etcd集群:

同master节点所有组件部署在同一主机上,分别部署了三个节点,使用TLS开启HTTPS双向认证组成etcd高可用集群;

网络:

使用Flanneld打通master节点和node节点间网络,以便集群各个节点网络互通(亦可以使用calico网络);

客户端:

在devops机器上部署了kubectl以及kubens,其中kubectl主要是对kubernetes的object资源进行rest操作,kubens主要是用于ns切换

docker镜像仓库:

使用 vmware harboar作为docker私有镜像镜像;提供私有镜像pull,push,从而对私有的镜像进行管理

相关服务器信息如下图1所示:
主机名 内网IP 外网IP 服务器角色 部署软件或应用
devops-k8s-n01 10.10.10.21 192.168.20.21 运维控制发布机 kubectl, kubens, ansible, cffss
lvs-ha-n01 10.10.10.30 192.168.20.30 slb负载均衡器 keepalived, haproxy, bind
lvs-ha-n02 10.10.10.31 192.168.20.31 slb负载均衡器 keepalived, haproxy, bind
master-k8s-n01 10.10.10.22 192.168.20.22 master节点01 master节点所有组件, flanneld插件
master-k8s-n02 10.10.10.23 192.168.20.23 master节点02 master节点相关组件, flanneld插件
master-ks8-n03 10.10.10.24 192.168.20.24 master节点03 master节点相关组件, flanneld插件
worker-k8s-n01 10.10.10.40 192.168.20.40 worker节点01 worker节点相关组件, flanneld插件
worker-k8s-n02 10.10.10.41 192.168.20.41 worker节点02 worker节点相关组件, flanneld插件
docker-hub-server 10.10.10.20 192.168.20.20 docker镜像仓库 docker, docker-compose, harbor

1.3. 组件访问策略

1.3.1 kube-apiserver:
  • 基于Keepalived+ Haproxy 四层透明代理实现高可用;

  • 开启非安全端口 8080 和关闭匿名访问,基于token访问;

  • 在安全端口 6443 接收 https 请求;

  • 严格的认证和授权策略 (x509、token、RBAC);

  • 开启 bootstrap token 认证,支持 kubelet TLS bootstrapping;

  • 使用 https 访问 kubelet、etcd,加密通信;
1.3.2 kube-controller-manager:
  • 3 节点高可用;

  • 开启安全端口,在安全端口 10252 接收 https 请求;

  • 使用 kubeconfig 访问 apiserver 的安全端口;

  • 自动 approve kubelet 证书签名请求 (CSR),证书过期后自动轮转;

  • 各 controller 使用自己的 ServiceAccount 访问 apiserver;
1.3.3 kube-scheduler:
  • 3 节点高可用;
  • 使用 kubeconfig 访问 apiserver 的安全端口;
1.3.4 kubelet:
  • 使用 kubeadm 动态创建 bootstrap token,而不是在 apiserver 中静态配置;
  • 使用 TLS bootstrap 机制自动生成 client 和 server 证书,过期后自动轮转;
  • 在 KubeletConfiguration 类型的 JSON 文件配置主要参数;
  • 关闭只读端口,在安全端口 10250 接收 https 请求,对请求进行认证和授权,拒绝匿名访问和非授权访问;
  • 使用 kubeconfig 访问 apiserver 的安全端口;
1.3.5 kube-proxy:
  • 使用 kubeconfig 访问 apiserver 的安全端口;
  • 在 KubeProxyConfiguration 类型的 JSON 文件配置主要参数;
  • 使用 ipvs 代理模式;

二 系统基本设置


2.1 域名设置

在bind配置文件里添加以下解析记录,这里以mo9.com为 域名后缀,bind服务安装此处忽略。

解析A记录字段 域名后缀 解析IP 备注
lvs-ha-n01 mo9.com 10.10.10.30 slb负载均衡器01,ssh主机使用
lvs-ha-n02 mo9.com 10.10.10.31 slb负载均衡器 02,ssh主机使用
master-k8s-n01 mo9.com 10.10.10.22 设置master节点01域名以方便metric数据采集
master-k8s-n02 mo9.com 10.10.10.23 设置master节点02域名以方便metric数据采集
master-k8s-n03 mo9.com 10.10.10.24 设置master节点03域名以方便metric数据采集
worker-k8s-n01 mo9.com 10.10.10.40 设置worker 节点01域名以方便metric数据采集
worker-k8s-n02 mo9.com 10.10.10.41 设置worker 节点01域名以方便metric数据采集
registry-mirrors mo9.com 10.10.10.20 docker镜像私有仓库域名,私有镜像上传下载使用
dev-kube-api mo9.com 10.10.10.100 apiserver集群访问域名, 所有组件通过该域名访问apiserver
dev-kube-api mo9.com 192.168.20.100 apiserver集群外网访问域名, 外网用户通过该域名访问

备注:
这里需要要添加相关主机的域名解析,因为kubelet配置里hostname值是主机名时,不设置会导致dashboard上看不到pod日志输出error,提示无法机械节点域名;亦可以将该值设置成ip,避免无法访问10250端口服务,当然可以通过hosts方式将上述信息写到每个node上的/etc/hosts文件内

2.2 机器主机名设置及DNS解析地址设置
主机名设置

将对应主机hostname信息设置成表1信息所示的主机名

hostnamectl set-hostname  主机名
各node主机dns解析设置

在各个Linux主机上将对应DNS解析服务器地址设置成如下信息

search mo9.com
nameserver  10.10.10.30
nameserver  10.10.10.31

备注:
设置search mo9.com是为了方便当通过ssh + 主机名时可以直接登录,dashboard访问worker节点便于解析对应的主机采集数据

2.3 SSH免密登陆配置

所有操作均在 devops-k8s-n01节点上执行,通过ansible执行所有操作,所以需要添加devops机器到其它节点的ssh免密登陆,关于ssh密码登陆此处不介绍

注意:

由于的主机关于dns解析,主机名设置,ssh免密登陆等基本配置,以及内核参数基本优化,在各Linux主机创建时通过系统初始化已配置完成。所以这里不再阐述!

三 k8s各节点主机初始化


这里所有的操作命令需要在kubernetes集群内所有的主机上执行,是安装kubernetes集群环境所需要的基本设置。
3.1 安装相关依赖包

yum install -y epel-release  conntrack ipvsadm \
    ipset jq sysstat curl libseccomp ntpdate ntp wget telnet rsync

备注:

这里的依赖包主要是为worker节点上kubelet,kube-proxy,docker,以及网络插件组件安装依赖的安装包,其他包为基本网络测试包,建议在集群内所以机器上执行,因为flanneld插件需要这些依赖包

3.2 关闭防火墙
在每台机器上关闭防火墙,清理防火墙规则,设置默认转发策略:

systemctl stop firewalld >>/dev/null 2>&1
systemctl disable firewalld >>/dev/null 2>&1
iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
iptables -P FORWARD ACCEPT

3.3 关闭 swap 分区
如果开启了 swap 分区,则worker节点上的kubelet 组件会启动失败(可以通过将参数 --fail-swap-on 设置为 false 来忽略 swap on),故需要在每台机器上关闭 swap 分区。同时注释 /etc/fstab 中相应的条目,防止开机自动挂载 swap 分区:

swapoff -a  >>/dev/null 2>&1
sed -i 's/.*swap.*/#&/' /etc/fstab

3.4 关闭 SELinux
关闭 SELinux,否则后续 K8S 挂载目录时可能报错 Permission denied:

setenforce  0 >>/dev/null 2>&1
sed -i "s/^SELINUX=enforcing/SELINUX=disabled/g" /etc/sysconfig/selinux  >>/dev/null 2>&1
sed -i "s/^SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config  >>/dev/null 2>&1
sed -i "s/^SELINUX=permissive/SELINUX=disabled/g" /etc/sysconfig/selinux >>/dev/null 2>&1
sed -i "s/^SELINUX=permissive/SELINUX=disabled/g" /etc/selinux/config  >>/dev/null 2>&1

3.5 关闭 dnsmasq(可选)
linux 系统开启了 dnsmasq 后(如 GUI 环境),将系统 DNS Server 设置为 127.0.0.1,这会导致 docker 容器无法解析域名,需要关闭它:

systemctl stop dnsmasq
systemctl disable dnsmasq

3.6 加载内核模块
主要是kube-proxy组件需要使用到ip_vs内核模块转发pods应用,实现endpoints路由;

sudo modprobe br_netfilter 
sudo modprobe ip_vs
sudo modprobe ip_conntrack 

3.7 优化内核参数

sudo sed -i '/net.ipv4.ip_forward/d' /etc/sysctl.conf
sudo sed -i '/net.bridge.bridge-nf-call-iptables/d'  /etc/sysctl.conf
sudo sed -i '/net.bridge.bridge-nf-call-ip6tables/d'  /etc/sysctl.conf
sudo sed -i '/net.ipv4.ip_forward/d'  /etc/sysctl.conf
sudo sed -i '/net.ipv4.tcp_tw_recycle/d'  /etc/sysctl.conf
sudo sed -i '/vm.swappiness/d'  /etc/sysctl.conf
sudo sed -i '/vm.overcommit_memory/d'  /etc/sysctl.conf
sudo sed -i '/vm.panic_on_oom/d'  /etc/sysctl.conf
sudo sed -i '/fs.inotify.max_user_watches/d'  /etc/sysctl.conf
sudo sed -i '/fs.file-max/d'  /etc/sysctl.conf
sudo sed -i '/fs.nr_open/d'  /etc/sysctl.conf
sudo sed -i '/net.ipv6.conf.all.disable_ipv6/d'  /etc/sysctl.conf
sudo sed -i '/net.netfilter.nf_conntrack_max/d'  /etc/sysctl.conf
cat >/etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720 
sysctl -p /etc/sysctl.d/kubernetes.conf  >>/dev/null 2>&1
  • sed操作主要是为了防止sysctl.conf配置与新增的内核参数冲突;
  • 必须关闭 tcp_tw_recycle,否则和 NAT 冲突,会导致服务不通;
  • 关闭 IPV6,防止触发 docker BUG;

3.8 设置系统时区

# 调整系统 TimeZone
timedatectl set-timezone Asia/Shanghai

# 将当前的 UTC 时间写入硬件时钟
timedatectl set-local-rtc 0
hwclock -w

# 更新服务时间
ntpdate ntp1.aliyun.com

# 重启依赖于系统时间的服务
systemctl restart rsyslog 
systemctl restart crond

3.9 关闭无关的服务

systemctl stop postfix && systemctl disable postfix

3.10 设置 rsyslogd 和 systemd journald(可选)

systemd 的 journald 是 Centos 7 缺省的日志记录工具,它记录了所有系统、内核、Service Unit 的日志。相比 systemd,journald 记录的日志有如下优势:

  • 可以记录到内存或文件系统;(默认记录到内存,对应的位置为 /run/log/jounal);
  • 可以限制占用的磁盘空间、保证磁盘剩余空间;
  • 可以限制日志文件大小、保存的时间;
  • journald 默认将日志转发给 rsyslog,这会导致日志写了多份,/var/log/messages 中包含了太多无关日志,不方便后续查看,同时也影响系统性能。
mkdir /var/log/journal # 持久化保存日志的目录
mkdir /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
[Journal]
# 持久化保存到磁盘
Storage=persistent

# 压缩历史日志
Compress=yes

SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000

# 最大占用空间 10G
SystemMaxUse=10G

# 单日志文件最大 200M
SystemMaxFileSize=200M

# 日志保存时间 2 周
MaxRetentionSec=2week

# 不将日志转发到 syslog
ForwardToSyslog=no
EOF
systemctl restart systemd-journald

3.11 创建k8s服务运行用户及相关目录

创建k8s组件服务运行用户
groupadd k8s
useradd -g k8s /var/lib/k8s -c "Kubernetes Service" -m -s /sbin/nologin  k8s

备注:kube-apiserver、controller-manager、scheduler、etcd为安全起见,使用k8s服务账号启动;但是所有的worker节点上组件以及相关网络组件因为需要使用root账号权限(如iptable设置)启动,因此worker节点上服务账号可以不创建!

创建k8s相关组件安装主目录以及证书存放目录
mkdir -p /data/apps/k8s && mkdir -p /etc/k8s/ssl

3.12 升级内核

CentOS 7.x 系统自带的 3.10.x 内核存在一些 Bugs,导致运行的 Docker、Kubernetes 不稳定,例如:

  • 高版本的 docker(1.13 以后) 启用了 3.10 kernel 实验支持的 kernel memory account 功能(无法关闭),当节点压力大如频繁启动和停止容器时会导致 cgroup memory leak;
  • 网络设备引用计数泄漏,会导致类似于报错:"kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1";

解决方案如下:

  • 升级内核到 4.4.X 以上;
  • 手动编译内核,disable CONFIG_MEMCG_KMEM 特性;
  • 安装修复了该问题的 Docker 18.09.1 及以上的版本。但由于 kubelet 也会设置 kmem(它 vendor 了 runc),所以需要重新编译 kubelet 并指定 GOFLAGS="-tags=nokmem";
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
sudo grub2-set-default 0 >>/dev/null 2>&1

3.13 关闭 NUMA

# Disable numa for system.
sudo sed -i "s:numa=off::" /etc/sysconfig/grub
sudo sed -i "s:centos/swap  rhgb:& numa=off:" /etc/sysconfig/grub
sudo grub2-mkconfig -o /boot/grub2/grub.cfg >>/dev/null 2>&1

4 控制机上安装ansible工具


由于所有操作都在devops机器上操作,为对所有机器进行命令操作,所有需要使用到ansible工具,将上述所有的命令根据服务器角色进行批量命令操作。

4.1 安装ansible工具

yum install ansible -y

4.2 根据服务器role创建ansible host文件进行分组

[master_k8s_vgs]
master-k8s-n01     ansible_host=10.10.10.22
master-k8s-n02     ansible_host=10.10.10.23
master-k8s-n03     ansible_host=10.10.10.24

[worker_k8s_vgs]
worker-k8s-n01     ansible_host=10.10.10.40
worker-k8s-n02     ansible_host=10.10.10.41

[slb_ha_vgs]
ha-lvs-n01     ansible_host=10.10.10.1
ha-lvs-n02     ansible_host=10.10.10.2

4.3 系统初始化设置

将上述系统优化里所有的命令对master_k8s_vgs,worker_k8s_vgs两个组里所有服务器初始化操作,这里将上述命令编写成一个k8s初始化脚本并执行ansible script脚本model,命令如下:

ansible master_k8s_vgs -m script -a "/home/gamaxwin/install_k8s_setup.sh" -b
ansible worker_k8s_vgs -m script -a "/home/gamaxwin/install_k8s_setup.sh" -b

至此k8s内所有的节点系统初始化基本完成,出于集群的安全,还需要为k8s创建TLS双向认证证书,请参考第二小节:kubernetes集群安装指南:创建CA证书及相关组件证书密钥