环境准备
3个节点,以下基于 Centos 7.6 系统, 内核版本:3.10.0-957.12.2.e17.x86_64
HOST | NODE | CPU | MEM |
192.168.1.111 | master | 最低要求2核2C | 最低要求2GB |
192.168.1.112 | node1 | 最低要求2核2C | 最低要求2GB |
192.168.1.113 | node2 | 最低要求2核2C | 最低要求2GB |
环境初始化-master -node节点都需要操作
host文件信息:
cat >>/etc/hosts<<EOF 192.168.1.111 master 192.168.1.112 node1 192.168.1.113 node2 EOF
集群免密钥设置:
yum -y install expect ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa for i in 192.168.1.111 192.168.1.112 192.168.1.113;do expect -c " spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$i expect { "*yes/no*" {send "yes "; exp_continue} "*password*" {send "Flyaway.123 "; exp_continue} "*Password*" {send "Flyaway.123 ";} } " done
配置时间同步/关闭防火墙:
#同步节点时间; yum install ntpdate -y ntpdate pool.ntp.org #临时关闭selinux和防火墙; sed -i '/SELINUX/s/enforcing/disabled/g' /etc/sysconfig/selinux setenforce 0 systemctl stop firewalld.service systemctl disable firewalld.service
hostname:
# 节点的 hostname 必须使用标准的 DNS 命名,另外千万不用什么默认的 localhost 的 hostname,会导致各种错误出现的。在 Kubernetes 项目里,机器的名字以及一切存储在 Etcd 中的 API 对象,都必须使用标准的 DNS 命名(RFC 1123)。可以使用命令 hostnamectl set-hostname ydzs-node1 来修改 hostname。 # 修改对应节点主机名; hostnamectl set-hostname master && ssh node1 "hostnamectl set-hostname node1" && ssh node2 "hostnamectl set-hostname node2" # 拷贝 hosts 文件到 node 节点: for i in node1 node2;do scp -r /etc/hosts $i:/etc/ ;done
由于开启内核 ipv4 转发需要加载 br_netfilter 模块,所以加载下该模块:
modprobe br_netfilter
创建 /etc/sysctl.d/k8s.conf 文件,添加如下内容:
net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 # bridge-nf 解释: # bridge-nf 使得 netfilter 可以对 Linux 网桥上的 IPv4/ARP/IPv6 包过滤。比如,设置net.bridge.bridge-nf-call-iptables=1后,二层的网桥在转发包时也会被 iptables的 FORWARD 规则所过滤。常用的选项包括: # net.bridge.bridge-nf-call-arptables:是否在 arptables 的 FORWARD 中过滤网桥的 ARP 包 # net.bridge.bridge-nf-call-ip6tables:是否在 ip6tables 链中过滤 IPv6 包 # net.bridge.bridge-nf-call-iptables:是否在 iptables 链中过滤 IPv4 包 # net.bridge.bridge-nf-filter-vlan-tagged:是否在 iptables/arptables 中过滤打了 vlan 标签的包。
执行如下命令使文件生效:
sysctl -p /etc/sysctl.d/k8s.conf
安装ipvs:
$ 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 EOF $ chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4 # 安装 ipset ipvsadm 管理工具(便于查看 ipvs 的代理规则) yum install ipset ipvsadm chrony -y # 同步服务器时间 systemctl enable chronyd && systemctl start chronyd && chronyc sources
关闭 swap 分区:
$ swapoff -a #修改/etc/fstab文件,注释掉 SWAP 的自动挂载,使用free -m确认 swap 已经关闭。swappiness 参数调整,修改/etc/sysctl.d/k8s.conf添加下面一行: vm.swappiness=0 #执行sysctl -p /etc/sysctl.d/k8s.conf使修改生效。
# 将 k8s.conf 文件 拷贝到 node 节点 for i in node1 node2;do scp -r /etc/sysctl.d/k8s.conf $i:/etc/sysctl.d/ ;done ssh node1 "sysctl -p /etc/sysctl.d/k8s.conf" && ssh node2 "sysctl -p /etc/sysctl.d/k8s.conf"
部署docker:
yum install -y yum-utils device-mapper-persistent-data lvm2 # 如果下面命令执行超时,可以使用阿里云的源代替:http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo $ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo $ yum list docker-ce --showduplicates | sort -r # 安装 docker-ce: yum install docker-ce -y && mkdir /etc/docker # 配置 docker 镜像加速器: cat >> /etc/docker/daemon.json<<EOF { "exec-opts": ["native.cgroupdriver=systemd"], "registry-mirrors" : [ "https://ot2k4d59.mirror.aliyuncs.com/" ] } EOF # 解释 cgroup 驱动 #由于默认情况下 kubelet 使用的 cgroupdriver 是 systemd,所以需要保持 docker 和kubelet 的 cgroupdriver 一致,我们这里修改 docker 的 cgroupdriver=systemd。如果不修改 docker 则需要修改 kubelet 的启动配置,需要保证两者一致。
启动 docker:
for i in start enable status; do systemctl $i docker ;done
配置 Kubeadm 源:
# yum 安装 kubeadm 工具时 默认是从 k8s.io 官网下载,对于不能科学**网的来说 比较头疼,所以提供了如下 阿里源 无需科学**网也可进行下载:
# 可以科学**网 选这个 cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF # 不能科学**网选择这个 cat <<EOF > /etc/yum.repos.d/kubernetes.repo [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
安装 kubeadm、kubelet、kubectl:
# --disableexcludes 禁掉除了kubernetes之外的别的仓库 # 安装 v1.16.2 版本: yum install -y kubelet-1.16.2 kubeadm-1.16.2 kubectl-1.16.2 --disableexcludes=kubernetes kubeadm version # 设置 kubelet 开机启动: systemctl enable --now kubelet
集群初始化
在 master 节点配置 kubeadm 初始化文件, 可以通过如下命令导出默认的初始化配置:
# 为了方便管理 k8s 创建 k8s-install 目录 mkdir k8s-install # 导出初始化配置文件
cd k8s-install/ kubeadm config print init-defaults > kubeadm.yaml
修改 kubeadm.yaml文件:
# 然后根据我们自己的需求修改配置,比如修改 imageRepository 的值,kube-proxy 的模式为 ipvs,另外需要注意的是我们这里是准备安装 flannel 网络插件的,需要将 networking.podSubnet 设置为10.244.0.0/16: 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.1.111 # apiserver 节点内网IP bindPort: 6443 nodeRegistration: criSocket: /var/run/dockershim.sock name: master # 默认读取当前master节点的hostname 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 etcd: local: dataDir: /var/lib/etcd imageRepository: registry.aliyuncs.com/google_containers # 修改成阿里云镜像源 kind: ClusterConfiguration kubernetesVersion: v1.16.2 networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 # Pod 网段,flannel插件需要使用这个网段 serviceSubnet: 10.96.0.0/12 scheduler: {} --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs # kube-proxy 模式
# 配置提示:
对于上面的资源清单的文档比较杂,要想完整了解上面的资源对象对应的属性,可以查看对应的 godoc 文档,地址: https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2。
修改配置 kubeadm.yaml 文件后, 进行初始化:
$ kubeadm init --config kubeadm.yaml [preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...` To see the stack trace of this error execute with --v=5 or higher [init] Using Kubernetes version: v1.16.2 [preflight] Running pre-flight checks [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Activating the kubelet service [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key x[certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [ydzs-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.151.30.11] xxx[certs] Generating "apiserver-kubelet-client" certificate and key x[certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [ydzs-master localhost] and IPs [10.151.30.11 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [ydzs-master localhost] and IPs [10.151.30.11 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 39.504262 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.16" in namespace kube-system with the configuration for the kubelets in the cluster [kubelet-check] Initial timeout of 40s passed. [upload-certs] Skipping phase. Please see --upload-certs [mark-control-plane] Marking the node ydzs-master as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node ydzs-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: abcdef.0123456789abcdef [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy 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: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.1.111:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:a292e66049e45264f848186d2fa3582dc360f3b5006cc160f137b5d436e078c2
拷贝 kubeconfig 文件:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubeadm init 命令执行流程图:
添加 node 节点
记住初始化集群上面的配置和操作要提前做好,将 master 节点上面的 $HOME/.kube/config 文件拷贝到 node 节点对应的文件中,安装 kubeadm、kubelet、kubectl(可选),然后执行上面初始化完成后提示的 join 命令即可:
$ kubeadm join 192.168.1.111:6443 --token abcdef.0123456789abcdef > --discovery-token-ca-cert-hash sha256:a292e66049e45264f848186d2fa3582dc360f3b5006cc160f137b5d436e078c2 [preflight] Running pre-flight checks [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.16" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Activating the kubelet service [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
join 命令:
如果忘记了上面的 join 命令可以使用 kubeadm token create --print-join-command
重新获取。
kubeadm join 命令执行流程图:
添加 node 节点后 查看:
$ kubectl get nodes NAME STATUS ROLES AGE VERSION master NotReady master 39m v1.16.2 node1 NotReady none1 106s v1.16.2 node1 NotReady none2 106s v1.16.2
网络方案(CNI)两种网络-我们这里选择Flannel 以下作为介绍
1、Calico 推荐方案,支持网络策略
为什么部署CNI网络?
部署CNI是为了不同主机之间的Pod进行通信,因为kubernetes资源调度是需要通信进行计算服务器资源情况进行分配的 Calico是一个纯三层的数据中心网络方案,Calico支持广泛的平台,包括Kubernetes、OpenStack等。 Calico 在每一个计算节点利用 Linux Kernel 实现了一个高效的虚拟路由器( vRouter) 来负责数据转发,<br>而每个 vRouter 通过 BGP 协议负责把自己上运行的 workload 的路由信息向整个 Calico 网络内传播。 此外,Calico 项目还实现了 Kubernetes 网络策略,提供ACL功能
下载官方默认配置文件
https://docs.projectcalico.org/manifests/calico.yaml
下载完后还需要修改里面配置项:
- 定义Pod网络(CALICO_IPV4POOL_CIDR),与前面初始化集群网络pod CIDR配置一样,后面集群所有的pod都会使用这个网络进行分配地址
- 选择工作模式(CALICO_IPV4POOL_IPIP),支持**BGP(Never)**、**IPIP(Always)**、**CrossSubnet**(开启BGP并支持跨子网)
IPIP 隧道模式(overlay网络),基于以太网基础上承载容器数据表
BGP 纯路由方案,要求在二层网络中,比较推荐的模式(对性能要求高的环境)
CrossSubnet 跨网段走IPIP,同网段走BGP
修改完后应用清单和查看状态:
kubectl apply -f calico.yaml
kubectl get pods -n kube-system
2、Flannel 老版本推荐使用
Flannel是CoreOS维护的一个网络组件,Flannel为每个Pod提供全局唯一的IP,Flannel使用ETCD来存储Pod子网与Node IP之间的关系。
flanneld守护进程在每台主机上运行,并负责维护ETCD信息和路由数据包。
yaml下载地址: (国外下载地址比较慢,可以考虑更换为国内的镜像下载地址,推荐 在阿里源下载)
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
可以看到是 NotReady 状态,这是因为还没有安装网络插件,接下来安装网络插件,可以在文档 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/ 中选择我们自己的网络插件,这里我们安装 flannel:
$ wget https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml
# 因为有节点是多网卡,所以需要在资源清单文件中指定内网网卡
# 搜索到名为 kube-flannel-ds-amd64 的 DaemonSet,在kube-flannel容器下面
$ vi kube-flannel.yml
......
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.11.0-amd64
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --iface=eth0 # 如果是多网卡的话,指定内网网卡的名称
......
$ kubectl apply -f kube-flannel.yml # 安装 flannel 网络插件
# 稍等一会查看 Pod 运行状态:
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-667f964f9b-wb5fn 1/1 Running 0 20m
coredns-667f964f9b-xmwn2 1/1 Running 0 20m
etcd-ydzs-master 1/1 Running 0 19m
kube-apiserver-ydzs-master 1/1 Running 0 19m
kube-controller-manager-ydzs-master 1/1 Running 0 19m
kube-flannel-ds-amd64-8l2wr 1/1 Running 0 12m
kube-flannel-ds-amd64-vwhbh 1/1 Running 0 12m
kube-proxy-8r4d2 1/1 Running 0 17m
kube-proxy-rbjv7 1/1 Running 0 20m
kube-scheduler-ydzs-master 1/1 Running 0 20m
# Flannel 网络插件
当我们部署完网络插件后执行 ifconfig 命令,正常会看到新增的cni0
与flannel1
这两个虚拟设备,但是如果没有看到cni0
这个设备也不用太担心,我们可以观察/var/lib/cni
目录是否存在,如果不存在并不是说部署有问题,而是该节点上暂时还没有应用运行,我们只需要在该节点上运行一个 Pod 就可以看到该目录会被创建,并且cni0
设备也会被创建出来。
Dashboard
v1.16.2 版本的集群需要安装最新的 2.0+ 版本的 Dashboard:
# 推荐使用下面这种方式 $ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta5/aio/deploy/recommended.yaml $ vi recommended.yaml # 修改Service为NodePort类型 ...... kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: ports: - port: 443 targetPort: 8443 nodePort: 30001 #手工绑定端口 selector: k8s-app: kubernetes-dashboard type: NodePort # 加上type=NodePort变成NodePort类型的服务 # 创建及查看: kubectl apply -f recommended.yaml kubectl get pods -n kubernetes-dashboard -l k8s-app=kubernetes- kubectl get svc -n kubernetes-dashboard
登录 Dashboard UI 界面:(注意使用https协议访问,http不可行,master IP+手工绑定的端口,如没有手工绑定端口 会随机生成一个端口)
https://192.168.1.111:30001
创建一个具有全局所有权限的用户来登录Dashboard:(admin.yaml) 可选:
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: admin annotations: rbac.authorization.kubernetes.io/autoupdate: "true" roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: admin namespace: kubernetes-dashboard --- apiVersion: v1 kind: ServiceAccount metadata: name: admin namespace: kubernetes-dashboard
创建:
$ kubectl apply -f admin.yaml $ kubectl get secret -n kubernetes-dashboard|grep admin-token admin-token-lwmmx kubernetes.io/service-account-token 3 1d $ kubectl get secret admin-token-lwmmx -o jsonpath={.data.token} -n kubernetes-dashboard |base64 -d# 会生成一串很长的base64后的字符串
使用上面的 base64 解码后的字符串作为 token 登录 Dashboard 即可,新版本还新增了一个暗黑模式:
清理:
如果 集群安装过程中遇到了其他问题,我们可以使用下面的命令来进行重置:
$ kubeadm reset $ ifconfig cni0 down && ip link delete cni0 $ ifconfig flannel.1 down && ip link delete flannel.1 $ rm -rf /var/lib/cni/