提要

经公司技术团队研究,计划把现有服务转移部署到 K8S,但前期先在测试环境部署一套并运转一段时间,以测试具体性能以及可行性。
此处使用 Kubeadm 方式部署 K8S


介绍

Kubernetes (后续简称 k8s) 是 Google (2014年6月) 开源的一个容器编排引擎,使用 Go 语言开发,它支持自动化部署、大规模可伸缩、以及云平台中多个主机上的容器化应用进行管理。其目标是让部署容器化的应用更加简单并且高效,提供了资源调度、部署管理、服务发现、扩容缩容、状态监控、维护等一整套功能,努力成为跨主机集群的自动化部署、自动化扩展以及运行应用程序容器的平台。
Kubeadm 是一个 K8s 部署工具,提供 kubeadm initkubeadm join,用于快速部署 Kubernetes 集群。


组件

Master 组件

· API Server:负责整个集群的统一入口,协调各个组件工作,以 RESTful API 提供接口服务,所有对象资源的增删改查和监听操作都交给 API Server 处理后再提交给 Etcd 存储。
· Kube-Scheduler:根据调度算法为新创建的 Pod 选择一个 Node 节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
· Controller-Manager:负责集群中常规后台任务,一个资源对应一个控制器,而 Controller-Manager 则负责管理这些控制器。
· Etcd:分布式键值存储系统,用于保存集群状态数据,比如 PodService 等对象信息。

Node 组件

· Kubelet:是 MasterNode 节点上的 Agent,管理本机运行容器的生命周期,比如创建容器、Pod 挂载数据卷、下载 secret、获取容器和节点状态等,Kubelet 将每个 Pod 转换成一组容器。
· Kube-Proxy:在 Node 节点上实现 Pod 网络代理,维护网络规则和四层负载均衡工作。
· Docker:容器引擎,运行容器。


机器分配

主机名 IP 地址 组件
k8s-master-1-220 192.168.31.220 kube-apiserver,kube-controller-manager,kube-scheduler,kubectl,kubelet,docker,etcd
k8s-master-2-221 192.168.31.221 kube-apiserver,kube-controller-manager,kube-scheduler,kubectl,kubelet,docker,etcd
k8s-master-3-226 192.168.31.226 kube-apiserver,kube-controller-manager,kube-scheduler,kubectl,kubelet,docker,etcd
k8s-node-1-222 192.168.31.222 kubectl,kubelet,kube-proxy,docker
k8s-node-2-223 192.168.31.223 kubectl,kubelet,kube-proxy,docker
k8s-lb-1-224 192.168.31.224 Nginx,Keepalived,主节点
k8s-lb-2-225 192.168.31.225 Nginx,Keepalived,备节点
lb-vip 192.168.31.250 VIP

集群拓扑图

001.png


网络规划

子网 网段 备注
NodeSubnet 192.168.31.0/24 宿主机节点子网
ServiceSubnet 10.96.0.0/12 SVC 子网
PodSubnet 10.244.0.0/16 POD 子网

节点初始化(所有节点)

# 关闭所有机器 SElinux
sed -i 's/enforcing/disabled/' /etc/selinux/config

# 关闭swap
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld

# 修改最大文件打开数和最大进程数
cat >> /etc/sysctl.conf <<EOF
* - nofile 65535
* - nproc 65536
EOF
sed -i 's#4096#65536#g' /etc/security/limits.d/20-nproc.conf

# 修正系统时间
(crontab -l;echo '*/30 * * * * /usr/sbin/ntpdate ntp1.aliyun.com && /usr/sbin/hwclock -w') | crontab

/usr/sbin/ntpdate ntp1.aliyun.com

# 内核参数调优
cat >> /etc/sysctl.conf <<EOF
net.ipv4.tcp_fin_timeout = 2
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.ip_local_port_range = 4000 65000
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.core.somaxconn = 16384
net.core.netdev_max_backlog = 16384
net.ipv4.tcp_max_orphans = 16384
net.netfilter.nf_conntrack_max = 25000000
net.netfilter.nf_conntrack_tcp_timeout_established = 180
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
EOF
sysctl -p >/dev/null 2>&1

# 添加 hosts 
cat >> /etc/hosts << EOF
192.168.31.220 k8s-master-1-220
192.168.31.221 k8s-master-2-221
192.168.31.226 k8s-master-3-226
192.168.31.222 k8s-node-1-222
192.168.31.223 k8s-node-2-223
192.168.31.224 k8s-lb-1-224
192.168.31.225 k8s-lb-2-225
192.168.31.250 lb-vip
EOF

# 创建目录待用
mkdir -p /data​

# 允许 iptables 检查桥接流量
cat <<EOF | tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

sysctl --system

# 验证每个节点上 IP、MAC 地址和 product_uuid 的唯一性,保证其能相互正常通信
# 使用命令 ip link 或 ifconfig -a 来获取网络接口的 MAC 地址
ifconfig -a

# 使用命令 查看 product_uuid 校验
cat /sys/class/dmi/id/product_uuid

# 重启机器
init 6

部署 LB 节点(224,225)

Nginx 是一个主流 Web 服务和反向代理服务器,这里用四层实现对 Master 节点实现负载均衡。
Keepalived 是一个主流高可用软件,基于 VIP 绑定实现服务器双机热备,Keepalived 主要根据 Nginx 运行状态判断是否需要故障转移(漂移 VIP),例如当 Nginx 主节点挂掉,VIP 会自动绑定在 Nginx 备节点,从而保证 VIP 一直可用,实现 Nginx 的高可用。

# 安装软件包(主/备)
yum install epel-release -y
yum install nginx keepalived nginx-mod-stream -y

# Nginx 配置文件(主/备)
cat > /etc/nginx/nginx.conf << "EOF"
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}

# 四层负载均衡,为两台 Master 提供负载均衡
stream {
    log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
    access_log /var/log/nginx/k8s-access.log  main;
    upstream k8s-master {
       server 192.168.31.220:6443;
       server 192.168.31.221:6443;
    }
    server {
       listen 16443;
       proxy_pass k8s-master;
    }
}

http {
    log_format  main '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log  main;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    server {
        listen 80 default_server;
        server_name _;
        location / {
        }
    }
}
EOF

# keepalived 配置文件(主)
cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   } 
   script_user root
   enable_script_security
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id NGINX_MASTER
} 

# 指定 nginx 状态检测脚本
vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    # 指定为主
    state MASTER
    # 修改为实际网卡名称
    interface enp0s3
    # VRRP 路由 ID 实例,同网段中,每一个主从集群都要相同ID,且唯一
    virtual_router_id 51
    # 优先级
    priority 100
    # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
    advert_int 1
    authentication {
        auth_type PASS  
        auth_pass 1111
    }  
    # 虚拟IP
    virtual_ipaddress {
        192.168.31.250/24
    } 
    track_script {
        check_nginx
    } 
}
EOF

# 准备 nginx 状态检测脚本
# keepalived 根据脚本返回状态码(0 为工作正常,非 0 不正常)判断是否故障转移
cat > /etc/keepalived/check_nginx.sh  << "EOF"
#!/bin/bash
count=$(ss -antp |grep 16443 |egrep -cv "grep|$$")

if [ "$count" -eq 0 ];then
    exit 1
else
    exit 0
fi
EOF

# 授权
chmod +x /etc/keepalived/check_nginx.sh

# keepalived 配置文件(备)
cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   } 
   script_user root
   enable_script_security
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id NGINX_BACKUP
} 

# 指定 nginx 状态检测脚本
vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    # 指定为备
    state BACKUP
    # 修改为实际网卡名称
    interface enp0s3
    # VRRP 路由 ID 实例,同网段中,每一个主从集群都要相同ID,且唯一
    virtual_router_id 51
    # 优先级
    priority 90
    # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
    advert_int 1
    authentication {
        auth_type PASS  
        auth_pass 1111
    }  
    # 虚拟IP
    virtual_ipaddress {
        192.168.31.250/24
    } 
    track_script {
        check_nginx
    } 
}
EOF

# 准备 nginx 状态检测脚本
# keepalived 根据脚本返回状态码(0 为工作正常,非 0 不正常)判断是否故障转移
cat > /etc/keepalived/check_nginx.sh  << "EOF"
#!/bin/bash
count=$(ss -antp |grep 16443 |egrep -cv "grep|$$")

if [ "$count" -eq 0 ];then
    exit 1
else
    exit 0
fi
EOF

# 授权
chmod +x /etc/keepalived/check_nginx.sh

# 启动并设置开机自启(主/备)
systemctl daemon-reload
systemctl start nginx keepalived
systemctl enable nginx keepalived

# 查看 keepalived 工作状态(主)
ip a
inet 192.168.31.250/24 scope global secondary enp0s3

Master 节点与 Node 节点

安装 Docker

# 安装
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum -y install docker-ce

# 创建配置文件,为了加速 Docker 源或使用私有仓库
# 由于默认情况下 kubelet 使用的 cgroupdriver 是 systemd,所以需要保持 docker 和 kubelet 的 cgroupdriver 一致,我们这里修改 docker 的 cgroupdriver=systemd。如果不修改 docker 则需要修改 kubelet 的启动配置,需要保证两者一致。
mkdir /etc/docker
cat > /etc/docker/daemon.json << EOF
{
  "registry-mirrors": ["https://vnarzvrd.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF

# 设置开机启动并启动 Docker
systemctl daemon-reload && systemctl enable docker && systemctl start docker

安装 kubeadm,kubelet 和 kubectl

# 配置 YUM 源​
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# 安装 1.23 版本
yum install -y kubelet-1.23.9 kubeadm-1.23.9 kubectl-1.23.9

systemctl enable kubelet

# 配置 kubectl 命令自动补全
yum install -y bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

Master 节点部署

220 节点上操作

# 初始化​
kubeadm init \
  --apiserver-advertise-address=192.168.31.220 \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.23.9 \
  --service-cidr=10.96.0.0/12 \
  --pod-network-cidr=10.244.0.0/16 \
  --ignore-preflight-errors=all \
  --control-plane-endpoint=lb-vip:16443 \
  --upload-certs
  
• --apiserver-advertise-address 集群通告地址
• --image-repository 由于默认拉取镜像地址 k8s.gcr.io 国内无法访问,这里指定阿里云镜像仓库地址
• --kubernetes-version K8s 版本,与上面安装的一致
• --service-cidr 集群内部虚拟网络,Pod 统一访问入口
• --pod-network-cidr Pod 网络,,与下面部署的 CNI 网络组件 yaml 中保持一致
• --control-plane-endpoint 负载均衡器的地址与端口
• --upload-certs 启用自动分发证书
  
# 配置 kubectl
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

# 记录 Master 节点加入的命令
kubeadm join lb-vip:16443 --token dozkz5.h5ixk8avfumy97zv \
	--discovery-token-ca-cert-hash sha256:433583f8d0ba98638e74ec7c866d920f28cd65cfa105dbaa103c1868faa0ae01 \
	--control-plane --certificate-key a3f1e2c2ae42fec791249bf17e7d030c4ea8ac1b8a26b3664afbde0cecbc50ea
	
# 记录 Node 节点加入的命令
kubeadm join lb-vip:16443 --token dozkz5.h5ixk8avfumy97zv \
	--discovery-token-ca-cert-hash sha256:433583f8d0ba98638e74ec7c866d920f28cd65cfa105dbaa103c1868faa0ae01
	
# 创建新的加入 Token,因为每个 Token 只有 24 小时时效
kubeadm token create --print-join-command

其他节点加入集群

221,226 节点上操作

# 执行 Master 节点加入的命令
kubeadm join lb-vip:16443 --token dozkz5.h5ixk8avfumy97zv \
	--discovery-token-ca-cert-hash sha256:433583f8d0ba98638e74ec7c866d920f28cd65cfa105dbaa103c1868faa0ae01 \
	--control-plane --certificate-key a3f1e2c2ae42fec791249bf17e7d030c4ea8ac1b8a26b3664afbde0cecbc50ea
	
# 配置 kubectl
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

222,223 节点上操作

# 执行 Node 节点加入的命令
kubeadm join lb-vip:16443 --token dozkz5.h5ixk8avfumy97zv \
	--discovery-token-ca-cert-hash sha256:433583f8d0ba98638e74ec7c866d920f28cd65cfa105dbaa103c1868faa0ae01

220 上检查

kubectl get node
NAME               STATUS     ROLES                  AGE     VERSION
k8s-master-1-220   NotReady   control-plane,master   16m     v1.23.9
k8s-master-2-221   NotReady   control-plane,master   8m22s   v1.23.9
k8s-master-3-226   NotReady   control-plane,master   5m35s   v1.23.9
k8s-node-1-222     NotReady   <none>                 2m17s   v1.23.9
k8s-node-2-223     NotReady   <none>                 57s     v1.23.9

部署 CNI 网络组件

在节点加入到集群时你会发现其节点状态为 NotReady,部署 calico 插件可以让集群正常通信。
Calico 是一个纯三层的数据中心网络方案。
在每一个计算节点利用 Linux Kernel 实现了一个高效的虚拟路由器(vRouter)来负责数据转发,而每个 vRouter 通过 BGP 协议负责把自己运行的 workload 的路由信息向整个 Calico 网络内传播。
Calico 还实现了 Kubernetes 网络策略,提供 ACL 功能。

# 220 上操作
# 下载 calico 文件并修改内容​
mkdir -p /data/yaml && cd $_
curl https://docs.projectcalico.org/v3.23/manifests/calico.yaml -O

vim calico.yaml
# 多网卡服务器建议增加这条配置
# 使用本地路由来决定使用哪个 IP 地址来到达提供的目的地,此处可以使用 IP 地址或者域名
- name: IP_AUTODETECTION_METHOD
  value: can-reach=114.114.114.114
 
- name: CALICO_IPV4POOL_CIDR
  # 此处需要与前面 kubeadm init 的 --pod-network-cidr 指定的一样
  value: "10.244.0.0/16"
  
# 部署 Calico
kubectl apply -f calico.yaml

# 查看 Calico 部署状态
kubectl get pods -n kube-system

# 检查各个节点状态(Ready 则表示 Calico 正常部署)
kubectl get nodes
NAME               STATUS   ROLES                  AGE   VERSION
k8s-master-1-220   Ready    control-plane,master   40m   v1.23.9
k8s-master-2-221   Ready    control-plane,master   32m   v1.23.9
k8s-master-3-226   Ready    control-plane,master   29m   v1.23.9
k8s-node-1-222     Ready    <none>                 26m   v1.23.9
k8s-node-2-223     Ready    <none>                 24m   v1.23.9

部署 Web UI

部署 Dashboard

Dashboard 是官方提供的一个 UI,可用于基本管理 K8s 资源。

# 220 上操作
# 下载文件并修改内容
# 默认 Dashboard 只能集群内部访问,修改 Service 为 NodePort 类型,暴露到外部
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.1/aio/deploy/recommended.yaml

vim recommended.yaml
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 443
      targetPort: 8443
  selector:
    k8s-app: kubernetes-dashboard
  # 增加 type 参数    
  type: NodePort
  
# 部署 Dashboard
kubectl apply -f recommended.yaml

# 查看状态
kubectl get pods -n kubernetes-dashboard
kubectl get svc -n kubernetes-dashboard
NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
dashboard-metrics-scraper   ClusterIP   10.105.237.150   <none>        8000/TCP        3m59s
kubernetes-dashboard        NodePort    10.103.123.27    <none>        443:31270/TCP   4m

# 创建 service account 并绑定默认 cluster-admin 管理员集群角色
# 创建用户
kubectl create serviceaccount dashboard-admin -n kube-system

# 用户授权
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin

# 获取用户 Token,把 Token 记录下来待用
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')

浏览器测试 Dashboard

地址为:https://192.168.31.220:31270/

002.png


验证集群可用性

部署 Nginx

Kubernetes 集群中创建一个 pod,验证是否正常运行

# 220 上操作
# 创建一个 nginx 的 pod​
kubectl create deployment nginx --image=nginx
kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-85b98978db-mzgjb   1/1     Running   0          37s

# 端口映射
kubectl expose deployment nginx --port=80 --type=NodePort

# 查看映射的端口
kubectl get svc nginx
NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.111.161.79   <none>        80:30664/TCP   6s

# 进入 Nginx 容器
kubectl exec -it nginx-85b98978db-mzgjb bash

# 使用 curl 命令测试容器是否有网络
curl www.baidu.com

浏览器测试 Nginx

地址为:http://192.168.31.220:30664/

003.png

测试 DNS 是否正常

# 使用 busybox
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox sh

# 可以直接 nslookup nginx
nslookup nginx
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx
Address 1: 10.111.161.79 nginx.default.svc.cluster.local

至此,K8S 集群环境准备就绪!


文章作者: Runfa Li
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Linux 小白鼠
Linux Kubernetes Linux Centos7 Centos7 docker kubernetes k8s calico kubeadm
觉得文章不错,打赏一点吧,1分也是爱~
打赏
微信 微信
支付宝 支付宝