文章目录

一、环境准备

1、机器规划

IP地址机器名称机器配置操作系统机器角色安装软件
192.168.6.1k8snode012C2GCentOS 7.9master+worker+etcdkube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubelet、kube-proxy
192.168.6.2k8snode022C2GCentOS 7.9master+worker+etcdkube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubelet、kube-proxy
192.168.6.3k8snode032C2GCentOS 7.9master+worker+etcdkube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubelet、kube-proxy
192.168.6.253负载均衡VIP
10.254.0.1/16service网络
10.0.0.0/16pod网络
10.254.0.2coredns地址

此处使用haproxy + keepalived的方式实现实现kube-apiserver的高可用性,VIP为192.168.6.253;三个节点同时为master和worker及etcd集群节点。

2、软件版本

软件版本官方下载地址
kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxyv1.22.1https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG
docker-cev20.10.8https://download.docker.com/linux/centos/7/x86_64/stable/Packages
etcdv3.5.0https://github.com/etcd-io/etcd/releases
calico(网络插件)v3.20.0https://docs.projectcalico.org/manifests/calico-etcd.yaml
coredns(dns插件)1.8.4https://raw.githubusercontent.com/coredns/deployment/master/kubernetes/coredns.yaml.sed
cfsslv1.6.1https://github.com/cloudflare/cfssl/releases
haproxy1.5.18yum安装
keepalivedv1.3.5yum安装

3、目录结构

目录节点说明
/opt/etcd/ssl所有etcd集群运行时所需要的证书
/opt/etcd/conf所有etcd集群运行时所需要的配置文件
/opt/etcd/bin所有etcd集群运行时所需要的二进制文件
/opt/kubernetes/ssl所有k8s集群运行时所需要的证书
/opt/kubernetes/conf所有k8s集群运行时所需要的配置文件
/opt/kubernetes/bin所有k8s集群运行时所需要的二进制文件(组件的二进制文件)
/var/log/kubernetes所有k8s集群运行时日志的存放目录
/opt/cfssl所有cfssl二进制运行文件目录
/root/k8s/{etcd,k8s,cfssl,ssl}k8snode01部署集群时所使用的目录
/opt/calicok8snode01calico组件安装目录
/opt/corednsk8snode01coredns组件安装目录

4、系统环境配置

  1. 修改主机名
    修改主机名及IP,其对应关系如下:

    主机名称IP地址
    k8snode01192.168.6.1
    k8snode02192.168.6.2
    k8snode03192.168.6.3
  2. 配置hosts文件
    将以下内容同时添加到三台主机上的/etc/hosts文件中:

    cat >> /etc/hosts << EOF
    192.168.6.1 k8snode01
    192.168.6.2 k8snode02
    192.168.6.3 k8snode03
    EOF
    
  3. 关闭防火墙和selinux

    systemctl stop firewalld
    systemctl disable firewalld
    setenforce 0
    sed -i 's/^SELINUX=.\*/SELINUX=disabled/' /etc/selinux/config
    
  4. 关闭交换分区

    #临时关闭
    swapoff -a
    sed -ri 's/.*swap.*/#&/' /etc/fstab
    echo "vm.swappiness=0" >> /etc/sysctl.conf
    sysctl -p
    
  5. 时间同步

     yum install -y ntp ntpdata
     #修改/etc/ntp.conf文件内的server选项,如下:
     server ntp1.aliyun.com iburst
     server ntp2.aliyun.com iburst
     server ntp3.aliyun.com iburst
    
     systemctl start ntpd
     systemctl enable ntpd
    
  6. 配置系统环境变量

    cat >> /etc/profile << 'EOF'
    export ETCD_HOME=/opt/etcd
    export CFSSL_HOME=/opt/cfssl
    export K8S_HOME=/opt/kubernetes
    export PATH=$ETCD_HOME/bin:$CFSSL_HOME:$K8S_HOME/bin:$PATH
    EOF
    
    source /etc/profile
    
  7. 配置免密钥登陆

    #在k8snode01上执行以下命令
    ssh-keygen -t rsa
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8snode01
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8snode02
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8snode03
    
  8. 安装IPVS

    yum -y install epel-release
    yum -y install ipvsadm ipset conntrack
    
    cat >/etc/modules-load.d/ipvs.conf <<EOF 
    ip_vs 
    ip_vs_lc 
    ip_vs_wlc 
    ip_vs_rr 
    ip_vs_wrr 
    ip_vs_lblc 
    ip_vs_lblcr 
    ip_vs_dh 
    ip_vs_sh 
    ip_vs_fo 
    ip_vs_nq 
    ip_vs_sed
    ip_vs_ftp
    nf_conntrack
    ip_tables 
    ip_set 
    xt_set 
    ipt_set 
    ipt_rpfilter 
    ipt_REJECT 
    ipip 
    EOF
    
    #查看相关模块是否已加载成功
    lsmod | grep ip_vs
    

    注意,在内核版本4.19以后,nf_conntrack_ipv4改名为nf_conntrack

  9. 升级系统内核

    #安装ELRepo仓库
    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
    
    #安装长期支持版(5.4.222-1)
    yum -y --enablerepo=elrepo-kernel install kernel-lt kernel-lt-devel
    
    #设置GRUB默认的内核启动版本
    grub2-set-default 0
    

    k8s对内核版本的最低要求为4.18.

  10. 配置内核参数

    cat > /etc/sysctl.d/k8s.conf <<EOF
    net.ipv4.ip_forward = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    fs.may_detach_mounts = 1
    vm.overcommit_memory=1
    vm.panic_on_oom=0
    fs.inotify.max_user_watches=89100
    fs.file-max=52706963
    fs.nr_open=52706963
    net.netfilter.nf_conntrack_max=2310720
    net.ipv4.tcp_keepalive_time = 600
    net.ipv4.tcp_keepalive_probes = 3
    net.ipv4.tcp_keepalive_intvl =15
    net.ipv4.tcp_max_tw_buckets = 36000
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_max_orphans = 327680
    net.ipv4.tcp_orphan_retries = 3
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_max_syn_backlog = 16384
    net.ipv4.ip_conntrack_max = 131072
    net.ipv4.tcp_max_syn_backlog = 16384
    net.ipv4.tcp_timestamps = 0
    net.core.somaxconn = 16384
    EOF
    
    sysctl --system
    
  11. 创建所需目录

      	#etcd运行时所需的证书目录及配置文件
       mkdir -p /opt/etcd/{ssl,conf,bin}
       #k8s组件运行时所需要的文件
       mkdir -p /opt/kubernetes/{ssl,conf,bin}
       #kubernetes日志目录
       mkdir /var/log/kubernetes
       #cfssl安装目录
       mkdir /opt/cfssl
       #搭建集群时用的的目录,只在k8snode01节点上创建此目录
       mkdir -p /root/k8s/{etcd,k8s,cfssl,ssl}
    

二、创建集群根证书

采用比较常用的CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate Authority (CA) 证书和秘钥文件,CA 是自签名的证书,用来签名后续创建的其它 TLS 证书。

证书可以在任意节点生成,然后再拷贝到其他及节点;在这里使用k8snode01节点生成证书,生成证书时所使用的目录为/root/k8s/ssl目录。

在创建CA证书的过程中,如果没有特别说明,则工作目录为:/root/k8s/ssl。因此,在进行下面的操作前需要将目录切换至/root/k8s/ssl

下载并安装cfssl

工具下载地址:

  • cfssl_linux-amd64:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64

  • cfssljson_linux-amd64:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64

  • cfssl-certinfo_linux-amd64:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl-certinfo_1.6.1_linux_amd64

cfssl下载目录为:/root/k8s/cfssl

安装cfssl:

cp /root/k8s/cfssl/cfssl_1.6.1_linux_amd64 /opt/cfssl/cfssl
cp /root/k8s/cfssl/cfssljson_1.6.1_linux_amd64 /opt/cfssl/cfssljson
cp /root/k8s/cfssl/cfssl-certinfo_1.6.1_linux_amd64 /opt/cfssl/cfssl-certinfo

chmod +x /opt/cfssl/cfssl
chmod +x /opt/cfssl/cfssljson
chmod +x /opt/cfssl/cfssl-certinfo

创建CA签名请求文件ca-csr.json

ca-csr.json中csr含义是:Certificate Signing Request,证书签名请求;因此看到 xx-csr.json,你就要知道该文件是证书签名请求文件,有了它,cfssl就可以生成证书和证书私钥了。

{
	"CN": "kubernetes",
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "k8s",
			"OU": "system"
		}
	],
	"ca": {
		"expiry": "87600h"
	}
}

CN:Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;

O:Organization,组织名称,公司名称;kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group)

C:Country, 国家。

ST: State,州,省。

L: Locality,地区,城市。

OU: Organization Unit Name,组织单位名称,公司部门。

生成CA根证书及其私钥

cfssl gencert -initca ca-csr.json  | cfssljson -bare ca

执行上述命令后当前目录下会生成三个文件:ca.csrca-csr.jsonca-key.pemca.pem

配置CA证书签发策略

在使用CA证书签发其他证书时会用到一个策略文件ca-config.json:

{
	"signing": {
		"default": {
			"expiry": "175200h"
		},
		"profiles": {
			"kubernetes": {
				"usages": [
					"signing",
					"key encipherment",
					"server auth",
					"client auth"
				],
				"expiry": "175200h"
			}
		}
	}
}

signing:表示该证书可用于签名其它证书,生成的 ca.pem 证书中 CA=TRUE。

profiles: 指定证书使用场景,同一个文件中可以有多个profiles,后续签名生成证书及其私钥时需要指定该场景(profile)名称。

server auth:表示 client 可以用该证书对 server 提供的证书进行验证。

client auth:表示 server 可以用该证书对 client 提供的证书进行验证。

expiry: 175200h表示20年有效期。

三、部署etcd集群

etcd 是k8s集群最重要的组件,用来存储k8s的所有服务信息, etcd 挂了,集群就挂了,我们这里三台节点上全部部署etcd,实现etcd高可用;

etcd集群采用raft算法选举Leader, 由于Raft算法在做决策时需要多数节点的投票,所以etcd一般部署集群推荐奇数个节点,推荐的数量为3、5或者7个节点构成一个集群。

下载并安装

cd /root/k8s/etcd
wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
tar -xvf etcd-v3.5.0-linux-amd64.tar.gz
cp ./etcd-v3.5.0-linux-amd64/etcd* /opt/etcd/bin
scp ./etcd-v3.5.0-linux-amd64/etcd* root@k8snode02:/opt/etcd/bin
scp ./etcd-v3.5.0-linux-amd64/etcd* root@k8snode03:/opt/etcd/bin

创建etcd证书签名请求文件

进入目录/root/k8s/ssl,创建新的文件etcd-csr.json,将以下内容添加到文件中:

{
	"CN": "etcd",
	"hosts": [
		"127.0.0.1",
		"192.168.6.1",
		"192.168.6.2",
		"192.168.6.3",
		"192.168.6.4",
		"192.168.6.5"
	],
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "k8s",
			"OU": "system"
		}
	]
}

生成证书及私钥

cd /root/k8s/ssl

cfssl gencert -ca=/root/k8s/ssl/ca.pem \
-ca-key=/root/k8s/ssl/ca-key.pem \
-config=/root/k8s/ssl/ca-config.json \
-profile=kubernetes etcd-csr.json | cfssljson -bare etcd

分发证书

cd /root/k8s/ssl
cp ./ca* ./etcd* /opt/etcd/ssl
scp ./ca* ./etcd* root@k8snode02:/opt/etcd/ssl
scp ./ca* ./etcd* root@k8snode03:/opt/etcd/ssl

正常情况下只需要copy这三个文件即可,ca.pem、etcd-key.pem、etcd.pem。

创建配置文件

创建配置文件模板etcd.conf,并将以下内容写入文件中:

#[Member]
ETCD_NAME="JIE_NAME"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://IP_ADDR:2380"
ETCD_LISTEN_CLIENT_URLS="https://IP_ADDR:2379,http://127.0.0.1:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://IP_ADDR:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://IP_ADDR:2379"
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.6.1:2380,etcd2=https://192.168.6.2:2380,etcd3=https://192.168.6.3:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"

ETCD_NAME:节点名称,集群中唯一
ETCD_DATA_DIR:数据目录
ETCD_LISTEN_PEER_URLS:集群通信监听地址
ETCD_LISTEN_CLIENT_URLS:客户端访问监听地址
ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址
ETCD_INITIAL_CLUSTER:集群节点地址
ETCD_INITIAL_CLUSTER_TOKEN:集群Token
ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态,new是新集群,existing表示加入已有集群

创建启动服务文件

创建配置文件etcd.service,并将以下内容写入文件中:

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=-/opt/etcd/conf/etcd.conf
WorkingDirectory=/var/lib/etcd/
ExecStart=/opt/etcd/bin/etcd \
    --cert-file=/opt/etcd/ssl/etcd.pem \
    --key-file=/opt/etcd/ssl/etcd-key.pem \
    --trusted-ca-file=/opt/etcd/ssl/ca.pem \
    --peer-cert-file=/opt/etcd/ssl/etcd.pem \
    --peer-key-file=/opt/etcd/ssl/etcd-key.pem \
    --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
    --peer-client-cert-auth \
    --client-cert-auth
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
User=etcd

[Install]
WantedBy=multi-user.target

创建运行用户及组

以下操作需要在所有的etcd集群节点上运行。

adduser -Ms /sbin/nologin etcd
mkdir /var/lib/etcd/
chown -R etcd:etcd /var/lib/etcd

分发文件

#!/bin/bash

NODE_NAMES=("etcd1" "etcd2" "etcd3")
NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

#替换模板文件中的变量,为各节点创建 systemd unit 文件
for (( i=0; i < 3; i++ ));do
    echo ">>> ${NODE_IPS[i]}"
    sed -e "s/JIE_NAME/${NODE_NAMES[i]}/g" -e "s/IP_ADDR/${NODE_IPS[i]}/g" ./etcd.conf > ./etcd-${NODE_IPS[i]}.conf
    scp ./etcd-${NODE_IPS[i]}.conf root@${NODE_IPS[i]}:/opt/etcd/conf/etcd.conf
    scp ./etcd.service root@${NODE_IPS[i]}:/etc/systemd/system/etcd.service
    ssh root@${NODE_IPS[i]} "chown -R etcd:etcd /opt/etcd"
    rm -f ./etcd-${NODE_IPS[i]}.conf
done

启动集群

systemctl daemon-reload
systemctl enable etcd
systemctl start etcd

验证集群状态

etcdctl --cacert=/opt/etcd/ssl/ca.pem \
--cert=/opt/etcd/ssl/etcd.pem \
--key=/opt/etcd/ssl/etcd-key.pem \
--endpoints="https://192.168.6.1:2379,https://192.168.6.2:2379,https://192.168.6.3:2379" \
endpoint status --write-out=table

四、部署haproxy+keepalived高可用

部署keepalived

1、安装keepalived

yum install -y keepalived

2、配置keepalived

keepalived的配置文件位置:/etc/keepalived/keepalived.conf

#备份配置文件
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bk

#主节点(k8snode01)执行以下命令
cat > /etc/keepalived/keepalived.conf <<EOF 
! Configuration File for keepalived

global_defs {
   router_id k8s
}

vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 3
    weight -2
    fall 10
    rise 2
}

vrrp_instance VI-kube-master {
    state MASTER 
    interface enp0s8
    virtual_router_id 51
    priority 250
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass ceb1b3ec013d66163d6ab
    }
    virtual_ipaddress {
        192.168.6.253
    }
    track_script {
        check_haproxy
    }
}
EOF

#从节点(k8snode02、k8snode03)执行以下命令
cat > /etc/keepalived/keepalived.conf <<EOF 
! Configuration File for keepalived

global_defs {
   router_id k8s
}

vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 3
    weight -2
    fall 10
    rise 2
}

vrrp_instance VI-kube-master {
    state BACKUP
    interface enp0s8
    virtual_router_id 51
    priority 250
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass ceb1b3ec013d66163d6ab
    }
    virtual_ipaddress {
        192.168.6.253
    }
    track_script {
        check_haproxy
    }
}
EOF

主节点与从节点在配置上唯一不同的是state,在主节点上state的值为MASTER,在从节点上state的值为BACKUP

3、启动并检查keepalived服务

systemctl start keepalived.service
systemctl status keepalived.service
systemctl enable keepalived.service

启动keepalived服务后,使用命令ip a s enp0s8就可以在k8snode01的enp0s8网卡上看到VIP。

部署HAproxy

1、安装haproxy

在所有主节点上执行以下命令:

yum install -y haproxy

2、配置haproxy

在所有主节点上执行以下命令:

#备份配置文件
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bk

cat > /etc/haproxy/haproxy.cfg << EOF
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2
    
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon 
       
    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------  
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
#---------------------------------------------------------------------
# kubernetes apiserver frontend which proxys to the backends
#--------------------------------------------------------------------- 
frontend kubernetes-apiserver
    mode                 tcp
    bind                 *:16443
    option               tcplog
    default_backend      kubernetes-apiserver    
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend kubernetes-apiserver
    mode        tcp
    balance     roundrobin
    server      k8snode01 192.168.6.1:6443 check
    server      k8snode02 192.168.6.2:6443 check
    server      k8snode03 192.168.6.3:6443 check
#---------------------------------------------------------------------
# collection haproxy statistics message
#---------------------------------------------------------------------
listen stats
    bind                 *:1080
    stats auth           admin:awesomePassword
    stats refresh        5s
    stats realm          HAProxy\ Statistics
    stats uri            /admin?stats
EOF

配置文件中指定了haproxy运行的端口为16443端口,因此16443端口为集群的入口。

3、启动并检查服务

systemctl start haproxy
systemctl enable haproxy.service

#检测服务状态
[root@k8snode02 ~]# netstat -tunlp | grep haproxy
tcp        0      0 0.0.0.0:1080            0.0.0.0:*               LISTEN      7375/haproxy        
tcp        0      0 0.0.0.0:16443           0.0.0.0:*               LISTEN      7375/haproxy        
udp        0      0 0.0.0.0:55425           0.0.0.0:*                           7374/haproxy

五、部署master节点

部署Kube-apiserver

创建csr请求文件kube-apiserver-csr.json
{
	"CN": "kubernetes",
	"hosts": [
		"127.0.0.1",
		"192.168.6.1",
		"192.168.6.2",
		"192.168.6.3",
		"192.168.6.4",
		"192.168.6.5",
		"192.168.6.253",
        "10.254.0.1",
		"kubernetes",
		"kubernetes.default",
		"kubernetes.default.svc",
		"kubernetes.default.svc.cluster",
		"kubernetes.default.svc.cluster.local"
	],
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "k8s",
			"OU": "system"
		}
	]
}

如果 hosts 字段不为空则需要指定授权使用该证书的 IP 或域名列表。

由于该证书后续被 kubernetes master 集群使用,需要将master节点的IP都填上,同时还需要填写 service 网络的首个IP。(一般是 kube-apiserver 指定的 service-cluster-ip-range 网段的第一个IP,如 10.254.0.1)。

生成token文件token.csv
cd /root/k8s/k8s/config

cat > token.csv << EOF
$(head -c 16 /dev/urandom | od -An -t x | tr -d ' '),kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
生成证书
cfssl gencert \
-ca=/root/k8s/ssl/ca.pem -ca-key=/root/k8s/ssl/ca-key.pem -config=/root/k8s/ssl/ca-config.json \
-profile=kubernetes /root/k8s/ssl/kube-apiserver-csr.json | cfssljson -bare /root/k8s/ssl/kube-apiserver
生成 apiserver RBAC 审计配置文件audit-policy.yaml
# Log all requests at the Metadata level.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
创建配置文件kube-apiserver.conf
KUBE_APISERVER_OPTS="--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
--anonymous-auth=false \
--bind-address=local_ip \
--secure-port=6443 \
--advertise-address=local_ip \
--insecure-port=0 \
--authorization-mode=Node,RBAC \
--runtime-config=api/all=true \
--enable-bootstrap-token-auth \
--service-cluster-ip-range=10.254.0.1/16 \
--token-auth-file=/opt/kubernetes/conf/token.csv \
--service-node-port-range=30000-50000 \
--tls-cert-file=/opt/kubernetes/ssl/kube-apiserver.pem  \
--tls-private-key-file=/opt/kubernetes/ssl/kube-apiserver-key.pem \
--client-ca-file=/opt/kubernetes/ssl/ca.pem \
--kubelet-client-certificate=/opt/kubernetes/ssl/kube-apiserver.pem \
--kubelet-client-key=/opt/kubernetes/ssl/kube-apiserver-key.pem \
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
--service-account-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \
--service-account-issuer=https://kubernetes.default.svc.cluster.local \
--etcd-cafile=/opt/etcd/ssl/ca.pem \
--etcd-certfile=/opt/etcd/ssl/etcd.pem \
--etcd-keyfile=/opt/etcd/ssl/etcd-key.pem \
--etcd-servers=https://192.168.6.1:2379,https://192.168.6.2:2379,https://192.168.6.3:2379 \
--enable-swagger-ui=true \
--allow-privileged=true \
--apiserver-count=3 \
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/var/log/kubernetes/kube-apiserver-audit.log \
--event-ttl=1h \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=4"
创建服务启动文件kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=etcd.service
Wants=etcd.service

[Service]
EnvironmentFile=-/opt/kubernetes/conf/kube-apiserver.conf
ExecStart=/opt/kubernetes/bin/kube-apiserver $KUBE_APISERVER_OPTS
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
分发文件
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

SSL_PATH='/root/k8s/ssl'
BIN_PATH='/root/k8s/k8s/kubernetes/server/bin'
BIN_FILE='kube-apiserver'

#替换模板文件中的变量,为各节点创建 systemd unit 文件
for (( i=0; i < 3; i++ ));do
    echo ">>> ${NODE_IPS[i]}"
    sed -e "s/local_ip/${NODE_IPS[i]}/g" /root/k8s/k8s/config/kube-apiserver.conf > /root/k8s/k8s/config/kube-apiserver-${NODE_IPS[i]}.conf
    scp /root/k8s/k8s/config/kube-apiserver-${NODE_IPS[i]}.conf root@${NODE_IPS[i]}:/opt/kubernetes/conf/kube-apiserver.conf
    scp /root/k8s/k8s/config/token.csv root@${NODE_IPS[i]}:/opt/kubernetes/conf/token.csv
    scp /root/k8s/k8s/config/kube-apiserver.service root@${NODE_IPS[i]}:/etc/systemd/system/kube-apiserver.service
    scp /root/k8s/k8s/config/audit-policy.yaml root@${NODE_IPS[i]}:/opt/kubernetes/conf/audit-policy.yaml

    scp ${SSL_PATH}/ca* root@${NODE_IPS[i]}:/opt/kubernetes/ssl
    scp ${SSL_PATH}/kube-apiserver* root@${NODE_IPS[i]}:/opt/kubernetes/ssl
    scp ${BIN_PATH}/${BIN_FILE} root@${NODE_IPS[i]}:/opt/kubernetes/bin
done
启动服务
systemctl daemon-reload
systemctl enable kube-apiserver
systemctl start kube-apiserver

部署kubectl

创建csr请求文件admin-csr.json
{
	"CN": "admin",
	"hosts": [],
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "system:masters",        
			"OU": "system"
		}
	]
}
生成证书
cfssl gencert \
-ca=/root/k8s/ssl/ca.pem -ca-key=/root/k8s/ssl/ca-key.pem -config=/root/k8s/ssl/ca-config.json \
-profile=kubernetes /root/k8s/ssl/admin-csr.json | cfssljson -bare /root/k8s/ssl/admin
分发证书

将生成的admin证书分发到所有需要安装kbuectl节点中:

#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

SSL_PATH='/root/k8s/ssl'

#替换模板文件中的变量,为各节点创建 systemd unit 文件
for (( i=0; i < 3; i++ ));do
    echo ">>> ${NODE_IPS[i]}"
    scp ${SSL_PATH}/admin* root@${NODE_IPS[i]}:/opt/kubernetes/ssl
    scp /root/k8s/k8s/kubernetes/server/bin/kubectl root@${NODE_IPS[i]}:/opt/kubernetes/bin
done
创建kubeconfig配置文件
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.6.253:16443 \
--kubeconfig=/root/k8s/k8s/config/kube.config

kubectl config set-credentials admin \
--client-certificate=/opt/kubernetes/ssl/admin.pem \
--client-key=/opt/kubernetes/ssl/admin-key.pem \
--embed-certs=true \
--kubeconfig=/root/k8s/k8s/config/kube.config

kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=/root/k8s/k8s/config/kube.config

kubectl config use-context kubernetes --kubeconfig=/root/k8s/k8s/config/kube.config
分发kubeconfig配置文件
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p ~/.kube"
    scp /root/k8s/k8s/config/kube.config root@${node_ip}:~/.kube/config
done
授权kubernetes证书访问kubelet api权限
kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes
查看集群组件状态

上面步骤完成后,kubectl就可以与kube-apiserver通信了:

kubectl cluster-info
kubectl get componentstatuses
kubectl get all --all-namespaces
配置kubectl子命令补全
yum install -y bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
kubectl completion bash > ~/.kube/completion.bash.inc
source '/root/.kube/completion.bash.inc'
source $HOME/.bash_profile

部署kube-controller-manager

创建csr请求文件kube-controller-manager-csr.json
{
	"CN": "system:kube-controller-manager",
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"hosts": [
		"127.0.0.1",
		"192.168.6.1",
		"192.168.6.2",
		"192.168.6.3",
		"192.168.6.4",
		"192.168.6.5",
        "localhost"
	],
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "system:kube-controller-manager",
			"OU": "system"
		}
	]
}
生成证书
cd /root/k8s/ssl

cfssl gencert \
-ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json \
-profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
分发证书
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
	#分发证书
	scp /root/k8s/ssl/kube-controller-manager* root@${node_ip}:/opt/kubernetes/ssl
done
创建kube-controller-manager的kubeconfig
#设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.6.253:16443 \
--kubeconfig=/root/k8s/k8s/config/kube-controller-manager.kubeconfig

#设置客户端认证参数
kubectl config set-credentials system:kube-controller-manager \
--client-certificate=/opt/kubernetes/ssl/kube-controller-manager.pem \
--client-key=/opt/kubernetes/ssl/kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=/root/k8s/k8s/config/kube-controller-manager.kubeconfig

#设置上下文参数
kubectl config set-context system:kube-controller-manager \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=/root/k8s/k8s/config/kube-controller-manager.kubeconfig

#设置默认上下文
kubectl config use-context system:kube-controller-manager \
--kubeconfig=/root/k8s/k8s/config/kube-controller-manager.kubeconfig
创建配置文件kube-controller-manager.conf
KUBE_CONTROLLER_MANAGER_OPTS="--port=0 \
--secure-port=10257 \
--bind-address=127.0.0.1 \
--kubeconfig=/opt/kubernetes/conf/kube-controller-manager.kubeconfig \
--service-cluster-ip-range=10.254.0.0/16 \
--cluster-name=kubernetes \
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \
--allocate-node-cidrs=true \
--cluster-cidr=10.0.0.0/16 \
--experimental-cluster-signing-duration=87600h \
--root-ca-file=/opt/kubernetes/ssl/ca.pem \
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \
--leader-elect=true \
--feature-gates=RotateKubeletServerCertificate=true \
--controllers=*,bootstrapsigner,tokencleaner \
--horizontal-pod-autoscaler-sync-period=10s \
--tls-cert-file=/opt/kubernetes/ssl/kube-controller-manager.pem \
--tls-private-key-file=/opt/kubernetes/ssl/kube-controller-manager-key.pem \
--use-service-account-credentials=true \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=2"

–experimental-cluster-signing-duration:指定证书过期时间;

–feature-gates=RotateKubeletServerCertificate:开启自动续期证书;

创建启动文件kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/opt/kubernetes/conf/kube-controller-manager.conf
ExecStart=/opt/kubernetes/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
分发文件
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
	#分发kubeconfig文件
	scp /root/k8s/k8s/config/kube-controller-manager.kubeconfig root@${node_ip}:/opt/kubernetes/conf
	#分发conf文件
	scp /root/k8s/k8s/config/kube-controller-manager.conf root@${node_ip}:/opt/kubernetes/conf
	#分发service文件
	scp /root/k8s/k8s/config/kube-controller-manager.service root@${node_ip}:/usr/lib/systemd/system
	#分发二进制文件
	scp /root/k8s/k8s/kubernetes/server/bin/kube-controller-manager root@${node_ip}:/opt/kubernetes/bin
done
启动服务
systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl start kube-controller-manager
systemctl status kube-controller-manager

部署kube-scheduler

创建csr请求文件kube-scheduler-csr.json
{
	"CN": "system:kube-scheduler",
	"hosts": [
		"127.0.0.1",
		"192.168.6.1",
		"192.168.6.2",
		"192.168.6.3",
		"192.168.6.4",
		"192.168.6.5",
		"localhost"
	],
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "system:kube-scheduler",
			"OU": "system"
		}
	]
}
生成证书
cd /root/k8s/ssl

cfssl gencert \
-ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json \
-profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler

ls kube-scheduler*.pem
创建kube-scheduler的kubeconfig
#设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=/root/k8s/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.6.253:16443 \
--kubeconfig=/root/k8s/k8s/config/kube-scheduler.kubeconfig

#设置客户端认证参数
kubectl config set-credentials system:kube-scheduler \
--client-certificate=/root/k8s/ssl/kube-scheduler.pem \
--client-key=/root/k8s/ssl/kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=/root/k8s/k8s/config/kube-scheduler.kubeconfig

#设置上下文参数
kubectl config set-context system:kube-scheduler \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=/root/k8s/k8s/config/kube-scheduler.kubeconfig

#设置默认上下文
kubectl config use-context system:kube-scheduler \
--kubeconfig=/root/k8s/k8s/config/kube-scheduler.kubeconfig
创建配置文件kube-scheduler.conf
KUBE_SCHEDULER_OPTS="--address=127.0.0.1 \
--kubeconfig=/opt/kubernetes/conf/kube-scheduler.kubeconfig \
--leader-elect=true \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=2"
创建服务启动文件kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/opt/kubernetes/conf/kube-scheduler.conf
ExecStart=/opt/kubernetes/bin/kube-scheduler $KUBE_SCHEDULER_OPTS
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
分发文件
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    #分发证书
	scp /root/k8s/ssl/kube-scheduler* root@${node_ip}:/opt/kubernetes/ssl
	#分发kubeconfig文件
	scp /root/k8s/k8s/config/kube-scheduler.kubeconfig root@${node_ip}:/opt/kubernetes/conf
	#分发conf文件
	scp /root/k8s/k8s/config/kube-scheduler.conf root@${node_ip}:/opt/kubernetes/conf
	#分发service文件
	scp /root/k8s/k8s/config/kube-scheduler.service root@${node_ip}:/usr/lib/systemd/system
	#分发二进制文件
	scp /root/k8s/k8s/kubernetes/server/bin/kube-scheduler root@${node_ip}:/opt/kubernetes/bin
done
启动服务
systemctl daemon-reload
systemctl enable kube-scheduler
systemctl start kube-scheduler
systemctl status kube-scheduler

六、部署node节点

部署docker

下载docker rpm包

下载docker-ce:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-20.10.8-3.el7.x86_64.rpm

下载containerd.io:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.9-3.1.el7.x86_64.rpm

下载docker-ce-cli:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-20.10.8-3.el7.x86_64.rpm

下载docker-ce-rootless-extras:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-rootless-extras-20.10.8-3.el7.x86_64.rpm

下载docker-scan-plugin:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-scan-plugin-0.8.0-3.el7.x86_64.rpm

/root/k8s/docker

wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-20.10.8-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.9-3.1.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-20.10.8-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-rootless-extras-20.10.8-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-scan-plugin-0.8.0-3.el7.x86_64.rpm
分发docker安装包
scp -r /root/k8s/docker root@k8snode01:/tmp/docker
scp -r /root/k8s/docker root@k8snode02:/tmp/docker
scp -r /root/k8s/docker root@k8snode03:/tmp/docker
卸载旧版本docker
yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine

在所有node节点上执行。

安装docker
yum install -y /tmp/docker/*

在所有node节点上执行。

修改docker源和驱动
mkdir /etc/docker

cat > /etc/docker/daemon.json << EOF
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "registry-mirrors": [
        "https://1nj0zren.mirror.aliyuncs.com",
        "https://kfwkfulq.mirror.aliyuncs.com",
        "https://2lqq34jg.mirror.aliyuncs.com",
        "https://pee6w651.mirror.aliyuncs.com",
        "http://hub-mirror.c.163.com",
        "https://docker.mirrors.ustc.edu.cn",
        "http://f1361db2.m.daocloud.io",
        "https://registry.docker-cn.com"
    ]
}
EOF

在所有node节点执行此命令。

启动docker服务
systemctl daemon-reload
systemctl enable docker
systemctl start docker
systemctl status docker

部署kubelet

创建kubelet-bootstrap.kubeconfig
#获取token,token在安装apiserver是生成
BOOTSTRAP_TOKEN=$(awk -F "," '{print $1}' /opt/kubernetes/conf/token.csv)

#设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.6.253:16443 \
--kubeconfig=/root/k8s/k8s/config/kubelet-bootstrap.kubeconfig

#设置客户端认证参数
kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=/root/k8s/k8s/config/kubelet-bootstrap.kubeconfig

#设置上下文参数
kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=/root/k8s/k8s/config/kubelet-bootstrap.kubeconfig

#设置默认上下文
kubectl config use-context default \
--kubeconfig=/root/k8s/k8s/config/kubelet-bootstrap.kubeconfig
角色绑定

kubelet 启动时向 kube-apiserver 发送 TLS bootstrapping 请求,需要先将 bootstrap token 文件中的 kubelet-bootstrap 用户赋予 system:node-bootstrapper cluster 角色(role), 然后 kubelet 才能有权限创建认证请求(certificate signing requests):

kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

–user=kubelet-bootstrap 是部署kube-apiserver时创建bootstrap-token.csv文件中指定的用户,同时也需要写入bootstrap.kubeconfig 文件

创建配置文件kubelet.json
{
	"kind": "KubeletConfiguration",
	"apiVersion": "kubelet.config.k8s.io/v1beta1",
	"authentication": {
		"x509": {
			"clientCAFile": "/opt/kubernetes/ssl/ca.pem"
		},
		"webhook": {
			"enabled": true,
			"cacheTTL": "2m0s"
		},
		"anonymous": {
			"enabled": false
		}
	},
	"authorization": {
		"mode": "Webhook",
		"webhook": {
			"cacheAuthorizedTTL": "5m0s",
			"cacheUnauthorizedTTL": "30s"
		}
	},
	"address": "local_ip",
	"port": 10250,
	"readOnlyPort": 10255,
	"cgroupDriver": "systemd",
	"hairpinMode": "promiscuous-bridge",
	"serializeImagePulls": false,
	"featureGates": {
		"RotateKubeletServerCertificate": true
	},
	"clusterDomain": "cluster.local.",
	"clusterDNS": ["10.254.0.2"]
}
创建启动文件kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/opt/kubernetes/bin/kubelet \
	--bootstrap-kubeconfig=/opt/kubernetes/conf/kubelet-bootstrap.kubeconfig \
	--cert-dir=/opt/kubernetes/ssl \
	--kubeconfig=/opt/kubernetes/conf/kubelet.kubeconfig \
	--config=/opt/kubernetes/conf/kubelet.json \
	--network-plugin=cni \
	--pod-infra-container-image=k8s.gcr.io/pause:3.2 \
	--alsologtostderr=true \
	--logtostderr=false \
	--log-dir=/var/log/kubernetes \
	--v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
分发文件
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")
SRC_K8S_CONFIG='/root/k8s/k8s/config'
DEST_K8S_CONFIG='/opt/kubernetes/conf'

SRC_K8S_BIN='/root/k8s/k8s/kubernetes/server/bin'
DEST_K8S_BIN='/opt/kubernetes/bin'

for (( i=0; i < 3; i++ ));do
    echo ">>> ${NODE_IPS[i]}"
    
    #分发kubelet.json文件
    sed "s/local_ip/${NODE_IPS[i]}/g" ${LOCAL_K8S_CONFIG}/kubelet.json > ${SRC_K8S_CONFIG}/kubelet-${NODE_IPS[i]}.json
    scp ${SRC_K8S_CONFIG}/kubelet-${NODE_IPS[i]}.json root@${NODE_IPS[i]}:${DEST_K8S_CONFIG}/kubelet.json
    rm -f ${SRC_K8S_CONFIG}/kubelet-${NODE_IPS[i]}.json
    
    #分发kubelet-bootstrap.kubeconfig文件
    scp ${SRC_K8S_CONFIG}/kubelet-bootstrap.kubeconfig root@${NODE_IPS[i]}:${DEST_K8S_CONFIG}
    
    #分发kubelet.service文件
    scp ${SRC_K8S_CONFIG}/kubelet.service root@${NODE_IPS[i]}:/usr/lib/systemd/system
    ssh root@${NODE_IPS[i]} "mkdir /var/lib/kubelet"
    
    #分发二进制文件
    scp ${SRC_K8S_BIN}/kubelet root@${NODE_IPS[i]}:${DEST_K8S_BIN} 
done
启动服务
systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet
systemctl status kubelet
查看未授权的csr请求
kubectl get csr

执行以上命令后可以看到三个csr请求(处于”Pending”状态):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-33XBlYpW-1654785072068)(C:\Users\xuwq\AppData\Roaming\Typora\typora-user-images\image-20210911194812802.png)]

授权csr请求

kubelet 首次启动向 kube-apiserver 发送证书签名请求,必须由 kubernetes 系统允许通过后,才会将该 node 加入到集群。执行以下命令可授权csr请求:

kubectl certificate approve node-csr-6ExtaLX1zmSeMJBX4NcB7-mbx6FcWnm5R4326q1G-Jg

命令执行过程及结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mWtTTwaN-1654785072090)(C:\Users\xuwq\AppData\Roaming\Typora\typora-user-images\image-20210911195310533.png)]

查看node节点状态
[root@k8snode01 scripts]# kubectl get nodes
NAME        STATUS     ROLES    AGE     VERSION
k8snode01   NotReady   <none>   2m24s   v1.22.1
k8snode02   NotReady   <none>   2m38s   v1.22.1
k8snode03   NotReady   <none>   2m13s   v1.22.1

由于还没有安装网络,所以node节点还处于NotReady状态。

部署kube-proxy

kube-proxy的作用主要是负责service的实现,具体来说,就是实现了内部从pod到service和外部的从node port向service的访问。

新版本目前 kube-proxy 组件全部采用 ipvs 方式负载,所以为了 kube-proxy 能正常工作需要预先处理一下 ipvs 配置以及相关依赖(每台 node 都要处理)。

配置ipvs
  1. 安装ipvs所需工具

    yum -y install ipvsadm ipset conntrack
    
  2. 开启ipvs支持

    #手动加载
    modprobe -- ip_vs
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- ip_vs_sh
    modprobe -- nf_conntrack_ipv4
    lsmod | grep ip_vs
    lsmod | grep nf_conntrack_ipv4
    
    #开机自动加载
    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
    
创建csr请求文件kube-proxy-csr.json
{
	"CN": "system:kube-proxy",
	"hosts": [],
	"key": {
		"algo": "rsa",
		"size": 2048
	},
	"names": [
		{
			"C": "CN",
			"ST": "BeiJing",
			"L": "BeiJing",
			"O": "system:kube-proxy",
			"OU": "system"
		}
	]
}
生成证书
cd /root/k8s/ssl

cfssl gencert \
-ca=ca.pem -ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy

ls kube-proxy*
创建kubeconfig文件
cd /root/k8s/ssl

kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://192.168.6.253:16443 \
--kubeconfig=/root/k8s/k8s/config/kube-proxy.kubeconfig

kubectl config set-credentials kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=/root/k8s/k8s/config/kube-proxy.kubeconfig

kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=/root/k8s/k8s/config/kube-proxy.kubeconfig

kubectl config use-context default \
--kubeconfig=/root/k8s/k8s/config/kube-proxy.kubeconfig
创建kube-proxy配置文件kube-proxy.yaml
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: local_ip
metricsBindAddress: local_ip:10249
healthzBindAddress: local_ip:10256
clientConnection:
  kubeconfig: /opt/kubernetes/conf/kube-proxy.kubeconfig
clusterCIDR: 10.0.0.0/16
kind: KubeProxyConfiguration
mode: "ipvs"
kubeProxyIPTablesConfiguration:
  masqueradeAll: false
创建服务启动文件kube-proxy.service
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
ExecStart=/opt/kubernetes/bin/kube-proxy \
  --config=/opt/kubernetes/conf/kube-proxy.yaml \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
分发文件
#!/bin/bash

NODE_IPS=("192.168.6.1" "192.168.6.2" "192.168.6.3")

SRC_K8S_CONFIG='/root/k8s/k8s/config'
DEST_K8S_CONFIG='/opt/kubernetes/conf'

for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    #分发证书
	scp /root/k8s/ssl/kube-proxy* root@${node_ip}:/opt/kubernetes/ssl
	#分发kubeconfig文件
	scp ${SRC_K8S_CONFIG}/kube-proxy.kubeconfig root@${node_ip}:${DEST_K8S_CONFIG}
	#分发conf文件
	sed "s/local_ip/${node_ip}/g" ${SRC_K8S_CONFIG}/kube-proxy.yaml > ${SRC_K8S_CONFIG}/kube-proxy-${node_ip}.yaml
    scp ${SRC_K8S_CONFIG}/kube-proxy-${node_ip}.yaml root@${node_ip}:${DEST_K8S_CONFIG}/kube-proxy.yaml
    rm -f ${SRC_K8S_CONFIG}/kube-proxy-${node_ip}.yaml
	#分发service文件
	scp ${SRC_K8S_CONFIG}/kube-proxy.service root@${node_ip}:/usr/lib/systemd/system
	#分发二进制文件
	scp /root/k8s/k8s/kubernetes/server/bin/kube-proxy root@${node_ip}:/opt/kubernetes/bin
done
启动服务
systemctl daemon-reload
systemctl enable kube-proxy
systemctl restart kube-proxy
systemctl status kube-proxy
查看ipvs路由规则
[root@k8snode01 scripts]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.254.0.1:443 rr
  -> 192.168.6.1:6443             Masq    1      0          0         
  -> 192.168.6.2:6443             Masq    1      0          0         
  -> 192.168.6.3:6443             Masq    1      0          0

检查LVS状态,可以看到已经创建了一个LVS集群,将来自10.254.0.1:443的请求转到三台master的6443端口,而6443就是api-server的端口。

配置网络组件

下载calico
cd /opt/kubernetes/conf
curl https://docs.projectcalico.org/manifests/calico-etcd.yaml -o calico.yaml
配置etcd
  1. 生成etcd证书base64编码
    使用以下命令对etcd的证书etcd-key.pem、etcd.pem、ca.pem进行base64编码:

    cat /etc/kubernetes/ssl/etcd-key.pem | base64 | tr -d '\n'
    
  2. 配置etcd证书base64编码

    # vim calico-etcd.yaml
    ...
    apiVersion: v1
    kind: Secret
    type: Opaque
    metadata:
      name: calico-etcd-secrets
      namespace: kube-system
    data:
      # Populate the following with etcd TLS configuration if desired, but leave blank if
      # not using TLS for etcd.
      # The keys below should be uncommented and the values populated with the base64
      # encoded contents of each file that would be associated with the TLS data.
      # Example command for encoding a file contents: cat <file> | base64 -w 0
      etcd-key: 填写上面的加密字符串
      etcd-cert: 填写上面的加密字符串
      etcd-ca: 填写上面的加密字符串
    ...
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: calico-config
      namespace: kube-system
    data:
      # Configure this with the location of your etcd cluster.
      etcd_endpoints: "https://192.168.1.2:2379"
      # If you're using TLS enabled etcd uncomment the following.
      # You must also populate the Secret below with these files.
      etcd_ca: "/calico-secrets/etcd-ca"       #这三个值不需要修改
      etcd_cert: "/calico-secrets/etcd-cert"   #这三个值不需要修改
      etcd_key: "/calico-secrets/etcd-key"     #这三个值不需要修改
    
  3. 创建Calico相关资源

    #创建Calico相关资源
    kubectl apply -f /opt/kubernetes/conf/calico.yaml
    
    #删除Calico相关资源
    kubectl delete -f /opt/kubernetes/conf/calico.yaml
    
查看网络状态
[root@k8snode02 ~]# kubectl get pod -n kube-system -o wide
NAME                                       READY   STATUS    RESTARTS      AGE    IP            NODE        NOMINATED NODE   READINESS GATES
calico-kube-controllers-59db5cf8fd-j6dlz   1/1     Running   0             128m   192.168.6.1   k8snode01   <none>           <none>
calico-node-brdnp                          1/1     Running   0             128m   192.168.6.3   k8snode03   <none>           <none>
calico-node-d74n5                          1/1     Running   1 (28m ago)   128m   192.168.6.1   k8snode01   <none>           <none>
calico-node-v7bnm                          1/1     Running   0             128m   192.168.6.2   k8snode02   <none>           <none>
查看node是否为就绪状态
[root@k8snode02 ~]# kubectl get nodes
NAME        STATUS   ROLES    AGE   VERSION
k8snode01   Ready    <none>   18h   v1.22.1
k8snode02   Ready    <none>   18h   v1.22.1
k8snode03   Ready    <none>   18h   v1.22.1
遇到的问题

问题一:

描述:

failed pulling image "k8s.gcr.io/pause:3.2"

通过命令kubectl describe pods -n kube-system calico-kube-controllers-59db5cf8fd-j6dlz获取到如下错误:

在这里插入图片描述

解决方法:

手动去docker.io仓库搜索pause:3.2镜像进行下载,并通过docker tag命令将镜像标签修改为k8s.gcr.io/pause:3.2

参考资料:

(5条消息) Kubernetes:如何解决从k8s.gcr.io拉取镜像失败问题_Bob Liu的程序人生-CSDN博客

问题二:

描述:

0/3 nodes are available: 3 node(s) had taint {node.kubernetes.io/not-ready: }, that the pod didn't tolerate.

解决方法:

kubectl taint nodes --all node.kubernetes.io/not-ready=:NoSchedule-

参考资料:

污点和容忍度 | Kubernetes

部署coredns

下载coredns
cd /opt/coredns
wget https://raw.githubusercontent.com/coredns/deployment/master/kubernetes/coredns.yaml.sed
mv coredns.yaml.sed coredns.yaml
修改配置文件

修改一:

#修改前
forward . UPSTREAMNAMESERVER {
	max_concurrent 1000
}
#修改后
forward . /etc/resolv.conf {
	max_concurrent 1000
}

修改二:

#修改前
kubernetes CLUSTER_DOMAIN REVERSE_CIDRS {
	fallthrough in-addr.arpa ip6.arpa
}
#修改后
kubernetes cluster.local in-addr.arpa ip6.arpa {
	fallthrough in-addr.arpa ip6.arpa
}

修改三:

#修改前
clusterIP: CLUSTER_DNS_IP
#修改后,10.254.0.2(kubelet配置文件中的clusterDNS)
clusterIP: 10.254.0.2
创建对应资源
kubectl apply -f /opt/coredns/coredns.yaml

kubectl delete -f /opt/coredns/coredns.yaml
查看资源创建
[root@k8snode01 coredns]# kubectl get all -n kube-system                          
NAME                                           READY   STATUS    RESTARTS      AGE
pod/calico-kube-controllers-59db5cf8fd-j6dlz   1/1     Running   1 (15m ago)   3h
pod/calico-node-brdnp                          1/1     Running   0             3h
pod/calico-node-d74n5                          1/1     Running   2 (15m ago)   3h
pod/calico-node-v7bnm                          1/1     Running   0             3h
pod/coredns-675db8b7cc-5kbxj                   1/1     Running   0             8s

NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
service/kube-dns   ClusterIP   10.254.0.2   <none>        53/UDP,53/TCP,9153/TCP   8s

NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/calico-node   3         3         3       3            3           kubernetes.io/os=linux   3h

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/calico-kube-controllers   1/1     1            1           3h
deployment.apps/coredns                   1/1     1            1           9s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/calico-kube-controllers-59db5cf8fd   1         1         1       3h
replicaset.apps/coredns-675db8b7cc                   1         1         1       9s
查看日志
kubectl logs -n kube-system pod/coredns-675db8b7cc-5kbxj
验证
  1. 部署nginx
    新建文件nginx.yaml,并将以下内容添加进文件中:

    ---
    apiVersion: v1
    kind: ReplicationController
    metadata:
      name: nginx-controller
    spec:
      replicas: 2
      selector:
        name: nginx
      template:
        metadata:
          labels:
            name: nginx
        spec:
          containers:
            - name: nginx
              image: nginx:1.19.6
              ports:
                - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service-nodeport
    spec:
      ports:
        - port: 80
          targetPort: 80
          nodePort: 30001
          protocol: TCP
      type: NodePort
      selector:
        name: nginx
    
  2. 创建nginx资源

    kubectl apply -f ./nginx.yaml
    
  3. 查看资源

    [root@k8snode01 ~]# kubectl get svc
    NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    kubernetes               ClusterIP   10.254.0.1      <none>        443/TCP        2d16h
    nginx-service-nodeport   NodePort    10.254.248.81   <none>        80:30001/TCP   10s
    [root@k8snode01 ~]# kubectl get pods
    NAME                     READY   STATUS              RESTARTS   AGE
    nginx-controller-8t689   0/1     ContainerCreating   0          22s
    nginx-controller-mnmzf   0/1     ContainerCreating   0          22s
    
  4. 进入nginx-controller-8t689

    kubectl exec -it nginx-controller-8t689 -- /bin/bash
    
  5. ping域名

    ping -c 5 nginx-service-nodeport
    

    如果成功,则表示dns部署成功。

  6. 使用浏览器打开nginx页面
    在浏览器中输入网址http://192.168.6.1:30001即可打开nginx首页。

参考资料

证书相关资料:

https://segmentfault.com/a/1190000038276488

集群部署资料:

kubernetes高可用集群安装(二进制安装、v1.20.2版)【附源码】_Rainbowhhy_51CTO博客

K8S 从入门到放弃系列文章目录(Kubernetes 1.14) - 小哥boy - 博客园 (cnblogs.com)

K8S/18_Kubernetes搭建高可用集群 · 陌溪/LearningNotes - 码云 - 开源中国 (gitee.com)

其他资料:

(5条消息) Kubernetes TLS bootstrapping 那点事_paopaohll的博客-CSDN博客

Configuration APIs | Kubernetes

calico网络:

Install Calico networking and network policy for on-premises deployments (projectcalico.org)

Install Calico networking and network policy for on-premises deployments (projectcalico.org)

在现有集群中部署calico踩坑记录 - shininglight - 博客园 (cnblogs.com)

安装 Calico 网络和网络策略,以便进行现场部署 (projectcalico.org)

Configure calicoctl to connect to an etcd datastore (projectcalico.org)

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐