01.系统初始化和全局变量

集群机器

  • zhangjun-k8s01:172.27.137.240
  • zhangjun-k8s02:172.27.137.239
  • zhangjun-k8s03:172.27.137.238

注意:

  1. 本文档中的 etcd 集群、master 节点、worker 节点均使用这三台机器;
  2. 需要在所有机器上执行本文档的初始化命令;
  3. 需要使用 root 账号执行这些命令;
  4. 如果没有特殊指明,本文档的所有操作均在 zhangjun-k8s01 节点上执行,然后远程分发文件和执行命令;

主机名

设置永久主机名称,然后重新登录:

  1. hostnamectl set-hostname zhangjun-k8s01 # 将 zhangjun-k8s01 替换为当前主机名
  • 设置的主机名保存在 /etc/hostname 文件中;

如果 DNS 不支持解析主机名称,则需要修改每台机器的 /etc/hosts 文件,添加主机名和 IP 的对应关系:

  1. cat >> /etc/hosts <<EOF
  2. 172.27.137.240 zhangjun-k8s01
  3. 172.27.137.239 zhangjun-k8s02
  4. 172.27.137.238 zhangjun-k8s03
  5. EOF

添加 docker 账户

在每台机器上添加 docker 账户:

  1. useradd -m docker

无密码 ssh 登录其它节点

如果没有特殊指明,本文档的所有操作均在 zhangjun-k8s01 节点上执行,然后远程分发文件和执行命令,所以需要添加该节点到其它节点的 ssh 信任关系。

设置 zhangjun-k8s01 的 root 账户可以无密码登录所有节点

  1. ssh-keygen -t rsa
  2. ssh-copy-id root@zhangjun-k8s01
  3. ssh-copy-id root@zhangjun-k8s02
  4. ssh-copy-id root@zhangjun-k8s03

更新 PATH 变量

将可执行文件目录添加到 PATH 环境变量中:

  1. echo 'PATH=/opt/k8s/bin:$PATH' >>/root/.bashrc
  2. source /root/.bashrc

安装依赖包

在每台机器上安装依赖包:

CentOS:

  1. yum install -y epel-release
  2. yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget

Ubuntu:

  1. apt-get install -y conntrack ipvsadm ntp ipset jq iptables curl sysstat libseccomp
  • ipvs 依赖 ipset;
  • ntp 保证各机器系统时间同步;

关闭防火墙

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

  1. systemctl stop firewalld
  2. systemctl disable firewalld
  3. iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
  4. iptables -P FORWARD ACCEPT

关闭 swap 分区

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

  1. swapoff -a
  2. sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

关闭 SELinux

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

  1. setenforce 0
  2. sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

关闭 dnsmasq(可选)

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

  1. systemctl stop dnsmasq
  2. systemctl disable dnsmasq

加载内核模块

  1. modprobe ip_vs_rr
  2. modprobe br_netfilter

优化内核参数

  1. cat > kubernetes.conf <<EOF
  2. net.bridge.bridge-nf-call-iptables=1
  3. net.bridge.bridge-nf-call-ip6tables=1
  4. net.ipv4.ip_forward=1
  5. net.ipv4.tcp_tw_recycle=0
  6. vm.swappiness=0 # 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它
  7. vm.overcommit_memory=1 # 不检查物理内存是否够用
  8. vm.panic_on_oom=0 # 开启 OOM
  9. fs.inotify.max_user_instances=8192
  10. fs.inotify.max_user_watches=1048576
  11. fs.file-max=52706963
  12. fs.nr_open=52706963
  13. net.ipv6.conf.all.disable_ipv6=1
  14. net.netfilter.nf_conntrack_max=2310720
  15. EOF
  16. cp kubernetes.conf /etc/sysctl.d/kubernetes.conf
  17. sysctl -p /etc/sysctl.d/kubernetes.conf
  • 必须关闭 tcp_tw_recycle,否则和 NAT 冲突,会导致服务不通;
  • 关闭 IPV6,防止触发 docker BUG;

设置系统时区

  1. # 调整系统 TimeZone
  2. timedatectl set-timezone Asia/Shanghai
  3. # 将当前的 UTC 时间写入硬件时钟
  4. timedatectl set-local-rtc 0
  5. # 重启依赖于系统时间的服务
  6. systemctl restart rsyslog
  7. systemctl restart crond

关闭无关的服务

  1. systemctl stop postfix && systemctl disable postfix

设置 rsyslogd 和 systemd journald

systemd 的 journald 是 Centos 7 缺省的日志记录工具,它记录了所有系统、内核、Service Unit 的日志。

相比 systemd,journald 记录的日志有如下优势:

  1. 可以记录到内存或文件系统;(默认记录到内存,对应的位置为 /run/log/jounal);
  2. 可以限制占用的磁盘空间、保证磁盘剩余空间;
  3. 可以限制日志文件大小、保存的时间;

journald 默认将日志转发给 rsyslog,这会导致日志写了多份,/var/log/messages 中包含了太多无关日志,不方便后续查看,同时也影响系统性能。

  1. mkdir /var/log/journal # 持久化保存日志的目录
  2. mkdir /etc/systemd/journald.conf.d
  3. cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
  4. [Journal]
  5. # 持久化保存到磁盘
  6. Storage=persistent
  7. # 压缩历史日志
  8. Compress=yes
  9. SyncIntervalSec=5m
  10. RateLimitInterval=30s
  11. RateLimitBurst=1000
  12. # 最大占用空间 10G
  13. SystemMaxUse=10G
  14. # 单日志文件最大 200M
  15. SystemMaxFileSize=200M
  16. # 日志保存时间 2 周
  17. MaxRetentionSec=2week
  18. # 不将日志转发到 syslog
  19. ForwardToSyslog=no
  20. EOF
  21. systemctl restart systemd-journald

创建相关目录

创建目录:

  1. mkdir -p /opt/k8s/{bin,work} /etc/{kubernetes,etcd}/cert

升级内核

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

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

解决方案如下:

  1. 升级内核到 4.4.X 以上;
  2. 或者,手动编译内核,disable CONFIG_MEMCG_KMEM 特性;
  3. 或者,安装修复了该问题的 Docker 18.09.1 及以上的版本。但由于 kubelet 也会设置 kmem(它 vendor 了 runc),所以需要重新编译 kubelet 并指定 GOFLAGS=”-tags=nokmem”;
    1. git clone --branch v1.14.1 --single-branch --depth 1 https://github.com/kubernetes/kubernetes
    2. cd kubernetes
    3. KUBE_GIT_VERSION=v1.14.1 ./build/run.sh make kubelet GOFLAGS="-tags=nokmem"

这里采用升级内核的解决办法:

  1. rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
  2. # 安装完成后检查 /boot/grub2/grub.cfg 中对应内核 menuentry 中是否包含 initrd16 配置,如果没有,再安装一次!
  3. yum --enablerepo=elrepo-kernel install -y kernel-lt
  4. # 设置开机从新内核启动
  5. grub2-set-default 0

安装内核源文件(可选,在升级完内核并重启机器后执行):

  1. # yum erase kernel-headers
  2. yum --enablerepo=elrepo-kernel install kernel-lt-devel-$(uname -r) kernel-lt-headers-$(uname -r)

关闭 NUMA

  1. cp /etc/default/grub{,.bak}
  2. vim /etc/default/grub # 在 GRUB_CMDLINE_LINUX 一行添加 `numa=off` 参数,如下所示:
  3. diff /etc/default/grub.bak /etc/default/grub
  4. 6c6
  5. < GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet"
  6. ---
  7. > GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet numa=off"

重新生成 grub2 配置文件:

  1. cp /boot/grub2/grub.cfg{,.bak}
  2. grub2-mkconfig -o /boot/grub2/grub.cfg

分发集群配置参数脚本

后续使用的环境变量都定义在文件 environment.sh 中,请根据自己的机器、网络情况修改。然后,把它拷贝到所有节点的 /opt/k8s/bin 目录:

  1. source environment.sh
  2. for node_ip in ${NODE_IPS[@]}
  3. do
  4. echo ">>> ${node_ip}"
  5. scp environment.sh root@${node_ip}:/opt/k8s/bin/
  6. ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"
  7. done

参考

  1. 系统内核相关参数参考:https://docs.openshift.com/enterprise/3.2/admin_guide/overcommit.html
  2. 3.10.x 内核 kmem bugs 相关的讨论和解决办法:
    1. https://github.com/kubernetes/kubernetes/issues/61937
    2. https://support.mesosphere.com/s/article/Critical-Issue-KMEM-MSPH-2018-0006
    3. https://pingcap.com/blog/try-to-fix-two-linux-kernel-bugs-while-testing-tidb-operator-in-k8s/