前言

由于容器的限制, 如果完全使用容器来部署 k8s, 那么其中关于一些 mount 操作, 就会因为容器 Mount Namespace 的存在而导致无法进行, 所以在 k8s 的部署中, 部分组件是通过 二进制包的形式直接运行在宿主机上, 如 kubeadm, kubelet, kubectl 三个组件

预检查

# 以centos为例

## 禁用防火墙
systemctl stop firewalld
systemctl disable firewalld

## 禁用SELINUX
setenforce 0
cat /etc/selinux/config  # 修改为disabled永久关闭
SELINUX=disabled

## 开机自动启用部分内核模块
# 安装bridge-util软件,加载bridge模块,加载br_netfilter模块
yum install -y bridge-utils
modprobe bridge
modprobe br_netfilter
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
modprobe -- bridge
modprobe -- br_netfilter  # 开机自动加载, 启用网桥透明防火墙
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4

## 调整内核参数. 创建/etc/sysctl.d/k8s.conf文件,添加如下内容:
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0  # 由于tcp_tw_recycle与kubernetes的NAT冲突,必须关闭!否则会导致服务不通。
net.ipv6.conf.all.disable_ipv6 = 1  #关闭不使用的ipv6协议栈,防止触发docker BUG.
EOF
sysctl -p /etc/sysctl.d/k8s.conf  # 使内核配置生效

## 安装ipset, ipvsadm 用于设置与管理ipvs
yum install ipset ipvsadm -y

## 同步系统服务器时间
yum install chrony -y
systemctl enable chronyd
systemctl start chronyd
# 执行 chronyc sources 确认同步服务器时间成功

## 关闭swap分区
swapoff -a  # 临时关闭
# 修改/etc/fstab文件,注释掉 SWAP 的自动挂载
sed -i 's/.*swap.*/#&/' /etc/fstab
# 使用free -m确认 swap 已经关闭。swappiness 参数调整,修改/etc/sysctl.d/k8s.conf添加下面一行:
# vm.swappiness=0  # 禁止使用swap空间, 只有当系统OOM时才允许使用它
# 然后再次执行 sysctl -p /etc/sysctl.d/k8s.conf

## 升级稳定的内核 
uname -r # 查看当前内核
rpm --import <https://www.elrepo.org/RPM-GPG-KEY-elrepo.org>
rpm -Uvh <http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm>
# yum --disablerepo="*" --enablerepo="elrepo-kernel" list available # 列出当前可见的内核
yum --enablerepo=elrepo-kernel install kernel-lt # kernel-lt 是长期稳定支持版, ml是主线最新版
# 设置从新安装的内核启动
awk -F\\' '$1=="menuentry " {print $2}' /etc/grub2.cfg # 查看最新内核的排序
grub2-set-default 0 # 设置为默认内核

安装docker

# 以centos为例

yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager \\
    --add-repo \\
    <https://download.docker.com/linux/centos/docker-ce.repo>
# 查看合适的docker版本
yum list docker-ce --showduplicates | sort -r
# 安装
yum install -y docker-ce

# ubuntu
apt-get install -y docker.io

安装

下载kubeadm

## ubuntu
curl -s <https://packages.cloud.google.com/apt/doc/apt-key.gpg> | apt-key add -
cat > /etc/apt/sources.list.d/kubernetes.list <<EOF
# deb <http://apt.kubernetes.io/> kubernetes-xenial main
deb <http://mirrors.ustc.edu.cn/kubernetes/apt> kubernetes-xenial mai
EOF
apt-get install -y kubeadm # 会附带下载 kubectl kubelet
systemctl enable kubelet

## centos
cat > /etc/yum.repos.d/kubernetes.repo <<EOF 
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
        <http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg>
EOF
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable kubelet.service

安装

## master
kubeadm config print init-defaults > kubeadm.yaml
# 修改 localAPIEndpoint.advertiseAddress 的值为 master 节点内网ip
# 修改 networking.podSubnet 的值为 192.168.0.0/16, 设置pod子网范围
# 修改 imageRepository 的值, 替换成国内的源 registry.cn-hangzhou.aliyuncs.com/google_containers
# 添加如下内容
# apiVersion: kubeproxy.config.k8s.io/v1alpha1
# kind: KubeProxyConfiguration
# mode: ipvs  # kube-proxy 模式

以下是案例参考文件

apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.0.212  # master ip
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  name: txz-data0
  # 注视掉, 允许master分配POD
  #taints:
  #- effect: NoSchedule
  #  key: node-role.kubernetes.io/master
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS   # 默认使用的dns类型, kubeadm会自动安装
etcd:
  local:
    dataDir: /var/lib/etcd
#imageRepository: k8s.gcr.io
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers  # 替换成阿里源
kind: ClusterConfiguration
kubernetesVersion: v1.17.0
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
  podSubnet: 10.244.0.0/16  # POD的子网范围
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs  # kube-proxy 模式

配置完成之后继续执行如下命令

## master
sudo kubeadm init --config=kubeadm.yaml
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

## node
kubeadm config print join-defaults > /tmp/join.config.yaml
sed -i 's/kube-apiserver/<master ip>/g' /tmp/join.config.yaml
kubeadm join --config=/tmp/join.config.yaml

kubeadm init 的工作流程

当你执行 kubeadm init 指令后,kubeadm 首先要做的,是一系列的检查工作,以确定这台机器可以用来部署 Kubernetes。这一步检查,我们称为“Preflight Checks”,它可以为你省掉很多后续的麻烦。

其实,Preflight Checks 包括了很多方面,比如: