文章目录
一、实验环境
系统 | 主机名 | ip | 配置 | 运行服务 | 扮演角色 |
---|---|---|---|---|---|
Centos7.4 | master01 | 192.168.100.202 | 4G双核 | docker、etcd、kube-apiserver、kube-scheduler、kube-controller-manager、kubectl、kubelet、kube-nginx、flannel | master节点 |
Centos7.4 | master02 | 192.168.100.203 | 4G双核 | docker、etcd、kube-apiserver、kube-scheduler、kube-controller-manager、kubectl、kubelet、kube-nginx、flannel | master节点 |
Centos7.4 | worker01 | 192.168.100.205 | 2G单核 | docker、etcd、kubelet、proxy、flannel | worker节点 |
Centos7.4 | worker02 | 192.168.100.206 | 2G单核 | docker、etcd、kubelet、proxy、flannel | worker节点 |
以上主机全部都有桥接网卡,虚拟ip192.168.100.204,部署双master实现k8s高可用
二、实验步骤
1、先做基础配置
四台服务器都需要进行操作
#master01
[root@Centos7 ~]# hostnamectl set-hostname master01
[root@Centos7 ~]# su
[root@master01 ~]# cat <<aaa>> /etc/hosts
192.168.100.202 master01
192.168.100.203 master02
192.168.100.205 worker01
192.168.100.206 worker02
aaa
#master02
[root@Centos7 ~]# hostnamectl set-hostname master02
[root@Centos7 ~]# su
[root@master02 ~]# cat <<aaa>> /etc/hosts
> 192.168.100.202 master01
> 192.168.100.203 master02
> 192.168.100.205 worker01
> 192.168.100.206 worker02
> aaa
#worker01
[root@Centos7 ~]# hostnamectl set-hostname worker01
[root@Centos7 ~]# su
[root@worker01 ~]# cat <<aaa>> /etc/hosts
> 192.168.100.202 master01
> 192.168.100.203 master02
> 192.168.100.205 worker01
> 192.168.100.206 worker02
> aaa
#worker02
[root@Centos7 ~]# hostnamectl set-hostname worker02
[root@Centos7 ~]# su
[root@worker02 ~]# cat <<aaa>> /etc/hosts
> 192.168.100.202 master01
> 192.168.100.203 master02
> 192.168.100.205 worker01
> 192.168.100.206 worker02
> aaa
2、编写脚本进行初始化准备
2步骤的所有操作在master01上执行即可!!!!
#在master01上编写脚本
[root@master01 ~]# vim k8sinit.sh
#!/bin/sh
#****************************************************************#
# ScriptName: k8sinit.sh
# Initialize the machine. This needs to be executed on every machine.
# Mkdir k8s directory
yum -y install wget ntpdate && ntpdate ntp1.aliyun.com
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
yum -y install epel-release
mkdir -p /opt/k8s/bin/
mkdir -p /data/k8s/k8s
mkdir -p /data/k8s/docker
# Disable the SELinux.
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
# Turn off and disable the firewalld.
systemctl stop firewalld
systemctl disable firewalld
# Modify related kernel parameters & Disable the swap.
cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.tcp_tw_recycle = 0
vm.swappiness = 0
vm.overcommit_memory = 1
vm.panic_on_oom = 0
net.ipv6.conf.all.disable_ipv6 = 1
EOF
sysctl -p /etc/sysctl.d/k8s.conf >&/dev/null
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
modprobe br_netfilter
# Add ipvs modules
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 -- nf_conntrack
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules
bash /etc/sysconfig/modules/ipvs.modules
# Install rpm
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget gcc gcc-c++ make libnl libnl-devel libnfnetlink-devel openssl-devel vim
# ADD k8s bin to PATH
echo 'export PATH=/opt/k8s/bin:$PATH' >> /root/.bashrc
#保存退出
[root@master01 ~]# chmod +x k8sinit.sh
#在master01上配置免密登录其他主机
[root@master01 ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:hjslVhnFN3ZeWAhJR0xXQavf1L1OyF0L2USEqoELTgo root@master01
The key's randomart image is:
+---[RSA 2048]----+
| .o..o*BO*|
| o. =o*.o|
| + o.+ + |
| E o + . . * o|
| . + = S o + .=|
| . o * . . =.=|
| o o *.|
| . o |
| . |
+----[SHA256]-----+
[root@master01 ~]# ssh-copy-id 192.168.100.202
[root@master01 ~]# ssh-copy-id 192.168.100.203
[root@master01 ~]# ssh-copy-id 192.168.100.205
[root@master01 ~]# ssh-copy-id 192.168.100.206
#编写设置环境变量的脚本
[root@master01 ~]# vim environment.sh #其中的节点ip和网卡名称要记得修改,如果和环境配置相同则无需修改
!/bin/bash
# 生成 EncryptionConfig 所需的加密 key
export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
# 集群 MASTER 机器 IP 数组
export MASTER_IPS=(192.168.100.202 192.168.100.203)
# 集群 MASTER IP 对应的主机名数组
export MASTER_NAMES=(master01 master02)
# 集群 NODE 机器 IP 数组
export NODE_IPS=(192.168.100.205 192.168.100.206)
# 集群 NODE IP 对应的主机名数组
export NODE_NAMES=(worker01 worker02)
# 集群所有机器 IP 数组
export ALL_IPS=(192.168.100.202 192.168.100.203 192.168.100.205 192.168.100.206)
# 集群所有IP 对应的主机名数组
export ALL_NAMES=(master01 master02 worker01 worker02)
# etcd 集群服务地址列表
export ETCD_ENDPOINTS="https://192.168.100.202:2379,https://192.168.100.203:2379"
# etcd 集群间通信的 IP 和端口
export ETCD_NODES="master01=https://192.168.100.202:2380,master02=https://192.168.100.203:2380"
# kube-apiserver 的反向代理(kube-nginx)地址端口,这里填虚拟ip地址
export KUBE_APISERVER="https://192.168.100.204:16443"
# 节点间互联网络接口名称
export IFACE="ens32"
# etcd 数据目录
export ETCD_DATA_DIR="/data/k8s/etcd/data"
# etcd WAL 目录,建议是 SSD 磁盘分区,或者和 ETCD_DATA_DIR 不同的磁盘分区
export ETCD_WAL_DIR="/data/k8s/etcd/wal"
# k8s 各组件数据目录
export K8S_DIR="/data/k8s/k8s"
# docker 数据目录
export DOCKER_DIR="/data/k8s/docker"
## 以下参数一般不需要修改
# TLS Bootstrapping 使用的 Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
BOOTSTRAP_TOKEN="41f7e4ba8b7be874fcff18bf5cf41a7c"
# 最好使用 当前未用的网段 来定义服务网段和 Pod 网段
# 服务网段,部署前路由不可达,部署后集群内路由可达(kube-proxy 保证)
SERVICE_CIDR="10.20.0.0/16"
# Pod 网段,建议 /16 段地址,部署前路由不可达,部署后集群内路由可达(flanneld 保证)
CLUSTER_CIDR="10.10.0.0/16"
# 服务端口范围 (NodePort Range)
export NODE_PORT_RANGE="1-65535"
# flanneld 网络配置前缀
export FLANNEL_ETCD_PREFIX="/kubernetes/network"
# kubernetes 服务 IP (一般是 SERVICE_CIDR 中第一个IP)
export CLUSTER_KUBERNETES_SVC_IP="10.20.0.1"
# 集群 DNS 服务 IP (从 SERVICE_CIDR 中预分配)
export CLUSTER_DNS_SVC_IP="10.20.0.254"
# 集群 DNS 域名(末尾不带点号)
export CLUSTER_DNS_DOMAIN="cluster.local"
# 将二进制目录 /opt/k8s/bin 加到 PATH 中
export PATH=/opt/k8s/bin:$PATH
#保存退出
[root@master01 ~]# chmod +x environment.sh
[root@master01 ~]# source /root/environment.sh #执行脚本
[root@master01 ~]# for all_ip in ${ALL_IPS[@]}; do echo $all_ip; done #运行之前先执行这个命令,看能不能输出所有服务器的ip
[root@master01 ~]# ll
总用量 12
-rw-------. 1 root root 1264 1月 12 2021 anaconda-ks.cfg
-rwxr-xr-x 1 root root 2470 8月 5 16:28 environment.sh
-rwxr-xr-x 1 root root 1627 8月 5 16:19 k8sinit.sh
[root@master01 ~]# source environment.sh #没有的话重新执行
[root@master01 ~]# for all_ip in ${ALL_IPS[@]}; do echo $all_ip; done #就像这样可以输出所有服务器的ip即可
192.168.100.202
192.168.100.203
192.168.100.205
192.168.100.206
#执行循环语句,一次性把四台服务器进行环境准备
[root@master01 ~]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp -rp /etc/hosts root@${all_ip}:/etc/hosts
scp -rp k8sinit.sh root@${all_ip}:/root/
ssh root@${all_ip} "bash /root/k8sinit.sh"
done
运行时间较长,一定要有网络环境!
3、创建CA证书和密钥
3步骤操作全部都在master01上执行
#安装cfssl工具集
[root@master01 ~]# mkdir -p /opt/k8s/cert
[root@master01 ~]# curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /opt/k8s/bin/cfssl #下载cfssl软件
[root@master01 ~]# curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /opt/k8s/bin/cfssljson #下载json模板
[root@master01 ~]# curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /opt/k8s/bin/cfssl-certinfo
[root@master01 ~]# chmod u+x /opt/k8s/bin/*
[root@master01 ~]# cd /opt/k8s/bin/
[root@master01 bin]# ll
总用量 18808
-rwxr--r-- 1 root root 10376657 8月 6 10:09 cfssl
-rwxr--r-- 1 root root 6595195 8月 6 10:10 cfssl-certinfo
-rwxr--r-- 1 root root 2277873 8月 6 10:10 cfssljson
#创建根证书配置文件
[root@master01 bin]# cd
[root@master01 ~]# mkdir -p /opt/k8s/work
[root@master01 ~]# cd /opt/k8s/work
[root@master01 work]# cfssl print-defaults config > config.json
[root@master01 work]# cfssl print-defaults csr > csr.json
[root@master01 work]# cp config.json ca-config.json
[root@master01 work]# cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "876000h"
},
"profiles": {
"kubernetes": {
"expiry": "876000h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
#字段解释:
config.json:可以定义多个profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个profile;
• signing: 表示该证书可用于签名其它证书;生成的ca.pem 证书中CA=TRUE;
• server auth: 表示client 可以用该CA 对server 提供的证书进行校验;
• client auth: 表示server 可以用该CA 对client 提供的证书进行验证;
• "expiry": "876000h":表示证书有效期设置为 100 年。
# 创建根证书签名请求文件
[root@master01 work]# cp csr.json ca-csr.json
[root@master01 work]# cat > ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
],
"ca": {
"expiry": "876000h"
}
}
EOF
#字段解释:
• CN: Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名(User Name);浏览器使用该字段验证网站是否合法;
• C:country;
• ST:state;
• L:city;
• O: Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组(Group);
• OU:organization unit。
#生成CA密钥(ca-key.pem)和证书(ca.pem)
[root@master01 work]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2021/08/06 10:15:01 [INFO] generating a new CA key and certificate from CSR
2021/08/06 10:15:01 [INFO] generate received request
2021/08/06 10:15:01 [INFO] received CSR
2021/08/06 10:15:01 [INFO] generating key: rsa-2048
2021/08/06 10:15:02 [INFO] encoded CSR
2021/08/06 10:15:02 [INFO] signed certificate with serial number 671027392584519656097263783341319452729816665502
[root@master01 work]# echo $?
0
提示:生成证书后,Kubernetes集群需要双向TLS认证,则可将ca-key.pem和ca.pem拷贝到所有要部署的机器的/etc/kubernetes/ssl目录下。不同证书 csr 文件的 CN、C、ST、L、O、OU 组合必须不同,否则可能出现 PEER'S CERTIFICATE HAS AN INVALID SIGNATURE 错误;
后续创建证书的 csr 文件时,CN 都不相同(C、ST、L、O、OU 相同),以达到区分的目的;
#分发证书
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}; do echo ">>> ${all_ip}"; ssh root@${all_ip} "mkdir -p /etc/kubernetes/cert"; scp ca*.pem ca-config.json root@${all_ip}:/etc/kubernetes/cert; done
>>> 192.168.100.202
ca-key.pem 100% 1679 1.6MB/s 00:00
ca.pem 100% 1367 56.8KB/s 00:00
ca-config.json 100% 388 75.1KB/s 00:00
>>> 192.168.100.203
ca-key.pem 100% 1679 1.1MB/s 00:00
ca.pem 100% 1367 1.5MB/s 00:00
ca-config.json 100% 388 594.7KB/s 00:00
>>> 192.168.100.205
ca-key.pem 100% 1679 1.6MB/s 00:00
ca.pem 100% 1367 1.4MB/s 00:00
ca-config.json 100% 388 429.7KB/s 00:00
>>> 192.168.100.206
ca-key.pem 100% 1679 1.6MB/s 00:00
ca.pem 100% 1367 1.5MB/s 00:00
ca-config.json 100% 388 629.1KB/s 00:00
4、部署ETCD集群
4步骤全部都在master01节点上运行
#安装ETCD
etcd 是基于 Raft 的分布式 key-value 存储系统,由 CoreOS 开发,常用于服务发现、共享配置以及并发控制(如 leader 选举、分布式锁等)。kubernetes 使用 etcd 存储所有运行数据。
[root@master01 ~]# cd /opt/k8s/work
[root@master01 work]# wget https://github.com/coreos/etcd/releases/download/v3.3.22/etcd-v3.3.10-linux-amd64.tar.gz
[root@master01 work]# ll
总用量 11116
-rw-r--r-- 1 root root 388 8月 6 10:12 ca-config.json
-rw-r--r-- 1 root root 1005 8月 6 10:15 ca.csr
-rw-r--r-- 1 root root 310 8月 6 10:13 ca-csr.json
-rw------- 1 root root 1679 8月 6 10:15 ca-key.pem
-rw-r--r-- 1 root root 1367 8月 6 10:15 ca.pem
-rw-r--r-- 1 root root 567 8月 6 10:12 config.json
-rw-r--r-- 1 root root 287 8月 6 10:12 csr.json
drwxr-xr-x 3 6810230 users 123 10月 11 2018 etcd-v3.3.10-linux-amd64
-rw-r--r-- 1 root root 11353259 3月 25 2020 etcd-v3.3.10-linux-amd64.tar.gz
[root@master01 work]# tar -xvf etcd-v3.3.10-linux-amd64.tar.gz
#提示:flanneld 版本 (v0.11.0/v0.12.0) 不支持 etcd v3.4.x,本方案部署etcd-v3.3.10版本。
#分发ETCD到master节点上
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp etcd-v3.3.10-linux-amd64/etcd* root@${master_ip}:/opt/k8s/bin
ssh root@${master_ip} "chmod +x /opt/k8s/bin/*"
done
#创建etcd证书和密钥,创建etcd的CA证书请求文件
[root@master01 work]# cat > etcd-csr.json <<EOF
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.100.202",
"192.168.100.203"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
#解释:
hosts:指定授权使用该证书的 etcd 节点 IP 或域名列表,需要将 etcd 集群的三个节点 IP 都列在其中。
##生成密钥和证书
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem -ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd
2021/08/06 10:23:29 [INFO] generate received request
2021/08/06 10:23:29 [INFO] received CSR
2021/08/06 10:23:29 [INFO] generating key: rsa-2048
2021/08/06 10:23:29 [INFO] encoded CSR
2021/08/06 10:23:29 [INFO] signed certificate with serial number 613228402925097686112501293991749855067805987177
2021/08/06 10:23:29 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
#分发证书和私钥
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}; do echo ">>> ${master_ip}"; ssh root@${master_ip} "mkdir -p /etc/etcd/cert"; scp etcd*.pem root@${master_ip}:/etc/etcd/cert/; done
#创建etcd的systemd
[root@master01 work]# source /root/environment.sh
[root@master01 work]# cat > etcd.service.template <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos
[Service]
Type=notify
WorkingDirectory=${ETCD_DATA_DIR}
ExecStart=/opt/k8s/bin/etcd \\
--enable-v2=true \\
--data-dir=${ETCD_DATA_DIR} \\
--wal-dir=${ETCD_WAL_DIR} \\
--name=##MASTER_NAME## \\
--cert-file=/etc/etcd/cert/etcd.pem \\
--key-file=/etc/etcd/cert/etcd-key.pem \\
--trusted-ca-file=/etc/kubernetes/cert/ca.pem \\
--peer-cert-file=/etc/etcd/cert/etcd.pem \\
--peer-key-file=/etc/etcd/cert/etcd-key.pem \\
--peer-trusted-ca-file=/etc/kubernetes/cert/ca.pem \\
--peer-client-cert-auth \\
--client-cert-auth \\
--listen-peer-urls=https://##MASTER_IP##:2380 \\
--initial-advertise-peer-urls=https://##MASTER_IP##:2380 \\
--listen-client-urls=https://##MASTER_IP##:2379,http://127.0.0.1:2379 \\
--advertise-client-urls=https://##MASTER_IP##:2379 \\
--initial-cluster-token=etcd-cluster-0 \\
--initial-cluster=${ETCD_NODES} \\
--initial-cluster-state=new \\
--auto-compaction-mode=periodic \\
--auto-compaction-retention=1 \\
--max-request-bytes=33554432 \\
--quota-backend-bytes=6442450944 \\
--heartbeat-interval=250 \\
--election-timeout=2000
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
#解释:
WorkingDirectory、--data-dir:指定工作目录和数据目录为 ${ETCD_DATA_DIR},需在启动服务前创建这个目录;
--wal-dir:指定 wal 目录,为了提高性能,一般使用 SSD 或者和 --data-dir 不同的磁盘;
--name:指定节点名称,当 --initial-cluster-state 值为 new 时,--name 的参数值必须位于 --initial-cluster 列表中;
--cert-file、--key-file:etcd server 与 client 通信时使用的证书和私钥;
--trusted-ca-file:签名 client 证书的 CA 证书,用于验证 client 证书;
--peer-cert-file、--peer-key-file:etcd 与 peer 通信使用的证书和私钥;
--peer-trusted-ca-file:签名 peer 证书的 CA 证书,用于验证 peer 证书。
#修改systemd相应地址
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for (( i=0; i < 2; i++ ))
do
sed -e "s/##MASTER_NAME##/${MASTER_NAMES[i]}/" -e "s/##MASTER_IP##/${MASTER_IPS[i]}/" etcd.service.template > etcd-${MASTER_IPS[i]}.service
done
[root@master01 work]# ll
总用量 11144
-rw-r--r-- 1 root root 388 8月 6 10:12 ca-config.json
-rw-r--r-- 1 root root 1005 8月 6 10:15 ca.csr
-rw-r--r-- 1 root root 310 8月 6 10:13 ca-csr.json
-rw------- 1 root root 1679 8月 6 10:15 ca-key.pem
-rw-r--r-- 1 root root 1367 8月 6 10:15 ca.pem
-rw-r--r-- 1 root root 567 8月 6 10:12 config.json
-rw-r--r-- 1 root root 287 8月 6 10:12 csr.json
-rw-r--r-- 1 root root 1383 8月 6 10:26 etcd-192.168.100.202.service #会有这两个master节点的service配置文件
-rw-r--r-- 1 root root 1383 8月 6 10:26 etcd-192.168.100.203.service
-rw-r--r-- 1 root root 1058 8月 6 10:23 etcd.csr
-rw-r--r-- 1 root root 354 8月 6 10:21 etcd-csr.json
-rw------- 1 root root 1679 8月 6 10:23 etcd-key.pem
-rw-r--r-- 1 root root 1436 8月 6 10:23 etcd.pem
-rw-r--r-- 1 root root 1382 8月 6 10:25 etcd.service.template
drwxr-xr-x 3 6810230 users 123 10月 11 2018 etcd-v3.3.10-linux-amd64
-rw-r--r-- 1 root root 11353259 3月 25 2020 etcd-v3.3.10-linux-amd64.tar.gz
#分发etcd systemd
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp etcd-${master_ip}.service root@${master_ip}:/etc/systemd/system/etcd.service
done
#启动ETCD
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p ${ETCD_DATA_DIR} ${ETCD_WAL_DIR}"
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable etcd && systemctl restart etcd " &
done
#检查ETCD启动
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl status etcd|grep Active"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 10:28:57 CST; 48s ago #提示两个都是running即可
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 10:28:57 CST; 48s ago
#验证服务状态
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ETCDCTL_API=3 /opt/k8s/bin/etcdctl \
--endpoints=https://${master_ip}:2379 \
--cacert=/etc/kubernetes/cert/ca.pem \
--cert=/etc/etcd/cert/etcd.pem \
--key=/etc/etcd/cert/etcd-key.pem endpoint health
done
>>> 192.168.100.202
https://192.168.100.202:2379 is healthy: successfully committed proposal: took = 2.190051ms #提示successfully即可
>>> 192.168.100.203
https://192.168.100.203:2379 is healthy: successfully committed proposal: took = 1.756794ms
#查看ETCD当前leader
[root@master01 work]# source /root/environment.sh
[root@master01 work]# ETCDCTL_API=3 /opt/k8s/bin/etcdctl \
-w table --cacert=/etc/kubernetes/cert/ca.pem \
--cert=/etc/etcd/cert/etcd.pem \
--key=/etc/etcd/cert/etcd-key.pem \
--endpoints=${ETCD_ENDPOINTS} endpoint status
+------------------------------+------------------+---------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+------------------------------+------------------+---------+---------+-----------+-----------+------------+
| https://192.168.100.202:2379 | 43bba1b27886ffbe | 3.3.10 | 20 kB | false | 2 | 6 |
| https://192.168.100.203:2379 | c98d893073b7487d | 3.3.10 | 20 kB | true | 2 | 6 |
+------------------------------+------------------+---------+---------+-----------+-----------+------------+
5、部署Docker
5步骤全部都在master01节点运行
Docker 运行和管理容器,kubelet 通过 Container Runtime Interface (CRI) 与它进行交互。
#下载Docker
[root@master01 ~]# cd /opt/k8s/work
[root@master01 work]# wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.12.tgz
[root@master01 work]# ll
总用量 70464
-rw-r--r-- 1 root root 388 8月 6 10:12 ca-config.json
-rw-r--r-- 1 root root 1005 8月 6 10:15 ca.csr
-rw-r--r-- 1 root root 310 8月 6 10:13 ca-csr.json
-rw------- 1 root root 1679 8月 6 10:15 ca-key.pem
-rw-r--r-- 1 root root 1367 8月 6 10:15 ca.pem
-rw-r--r-- 1 root root 567 8月 6 10:12 config.json
-rw-r--r-- 1 root root 287 8月 6 10:12 csr.json
-rw-r--r-- 1 root root 60741087 7月 1 2020 docker-19.03.12.tgz #这个
-rw-r--r-- 1 root root 1383 8月 6 10:26 etcd-192.168.100.202.service
-rw-r--r-- 1 root root 1383 8月 6 10:26 etcd-192.168.100.203.service
-rw-r--r-- 1 root root 1058 8月 6 10:23 etcd.csr
-rw-r--r-- 1 root root 354 8月 6 10:21 etcd-csr.json
-rw------- 1 root root 1679 8月 6 10:23 etcd-key.pem
-rw-r--r-- 1 root root 1436 8月 6 10:23 etcd.pem
-rw-r--r-- 1 root root 1382 8月 6 10:25 etcd.service.template
drwxr-xr-x 3 6810230 users 123 10月 11 2018 etcd-v3.3.10-linux-amd64
-rw-r--r-- 1 root root 11353259 3月 25 2020 etcd-v3.3.10-linux-amd64.tar.gz
[root@master01 work]# tar -xvf docker-19.03.12.tgz
#安装和部署Docker
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp docker/* root@${all_ip}:/opt/k8s/bin/
ssh root@${all_ip} "chmod +x /opt/k8s/bin/*"
done
#配置Docker system
[root@master01 work]# cat > docker.service <<"EOF"
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
[Service]
WorkingDirectory=##DOCKER_DIR##
Environment="PATH=/opt/k8s/bin:/bin:/sbin:/usr/bin:/usr/sbin"
EnvironmentFile=-/run/flannel/docker
ExecStart=/opt/k8s/bin/dockerd $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
#解释:
• EOF 前后有双引号,这样 bash 不会替换文档中的变量,如 $DOCKER_NETWORK_OPTIONS (这些环境变量是 systemd 负责替换的。);
• Dockerd 运行时会调用其它 Docker 命令,如 docker-proxy,所以需要将 Docker 命令所在的目录加到 PATH 环境变量中;
• flanneld 后续启动时将网络配置写入 /run/flannel/docker 文件中,dockerd 启动前读取该文件中的环境变量 DOCKER_NETWORK_OPTIONS ,然后设置 docker0 网桥网段;
• 如果指定了多个 EnvironmentFile 选项,则必须将 /run/flannel/docker 放在最后(确保 docker0 使用 flanneld 生成的 bip 参数);
• Docker 需要以 root 用于运行;
• Docker 从 1.13 版本开始,可能将 iptables FORWARD chain的默认策略设置为DROP,从而导致 ping 其它 Node 上的 Pod IP 失败,遇到这种情况时,需要手动设置策略为 ACCEPT,建议以下命令写入 /etc/rc.local 文件中,防止节点重启iptables FORWARD chain的默认策略又还原为DROP
[root@master01 work]# for all_ip in ${ALL_IPS[@]} ; do echo ">>> ${all_ip}"; ssh root@${all_ip} "echo '/sbin/iptables -P FORWARD ACCEPT' >> /etc/rc.local" ; done
#分发Docker systemd
[root@master01 work]# source /root/environment.sh
[root@master01 work]# sed -i -e "s|##DOCKER_DIR##|${DOCKER_DIR}|" docker.service
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp docker.service root@${all_ip}:/etc/systemd/system/
done
#配置Docker配置文件
[root@master01 work]# source /root/environment.sh
[root@master01 work]# cat > docker-daemon.json <<EOF
{
"registry-mirrors": ["https://dbzucv6w.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=cgroupfs"],
"data-root": "${DOCKER_DIR}/data",
"exec-root": "${DOCKER_DIR}/exec",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
#分发Docker配置文件
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "mkdir -p /etc/docker/ ${DOCKER_DIR}/{data,exec}"
scp docker-daemon.json root@${all_ip}:/etc/docker/daemon.json
done
#启动并验证
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "systemctl daemon-reload && systemctl enable docker && systemctl restart docker"
done
#检查状态
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "systemctl status docker|grep Active"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 10:39:59 CST; 36s ago #四台节点都是running即可
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 10:40:00 CST; 35s ago
>>> 192.168.100.205
Active: active (running) since 五 2021-08-06 10:40:02 CST; 33s ago
>>> 192.168.100.206
Active: active (running) since 五 2021-08-06 10:40:04 CST; 32s ago
#检查Docker 0网桥
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "/usr/sbin/ip addr show docker0"
done
>>> 192.168.100.202
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:1d:99:54:e1 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 #四个节点的docker0网卡都有ip地址即可
valid_lft forever preferred_lft forever
>>> 192.168.100.203
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:1c:98:5d:f3 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
>>> 192.168.100.205
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:dd:1f:ba:ba brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
>>> 192.168.100.206
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:44:74:0d:84 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
#查看Docker信息
[root@master01 ~]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "ps -elfH | grep docker | grep -v grep"
done
[root@master01 ~]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "docker info"
done
6、部署flannel
6步骤的操作全部都在master01上进行
kubernetes 要求集群内各节点(包括 master 节点)能通过 Pod 网段互联互通。flannel 使用 vxlan 技术为各节点创建一个可以互通的 Pod 网络,使用的端口为 UDP 8472。
flanneld 第一次启动时,从 etcd 获取配置的 Pod 网段信息,为本节点分配一个未使用的地址段,然后创建 flannedl.1 网络接口(也可能是其它名称,如 flannel1 等)。
flannel 将分配给自己的 Pod 网段信息写入 /run/flannel/docker 文件,docker 后续使用这个文件中的环境变量设置 docker0 网桥,从而从这个地址段为本节点的所有 Pod 容器分配 IP。
#下载flannel
root@master01 ~]# cd /opt/k8s/work/
[root@master01 work]# mkdir flannel
[root@master01 work]# wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
[root@master01 work]# ll
总用量 79816
-rw-r--r-- 1 root root 388 8月 6 10:12 ca-config.json
-rw-r--r-- 1 root root 1005 8月 6 10:15 ca.csr
-rw-r--r-- 1 root root 310 8月 6 10:13 ca-csr.json
-rw------- 1 root root 1679 8月 6 10:15 ca-key.pem
-rw-r--r-- 1 root root 1367 8月 6 10:15 ca.pem
-rw-r--r-- 1 root root 567 8月 6 10:12 config.json
-rw-r--r-- 1 root root 287 8月 6 10:12 csr.json
drwxrwxr-x 2 1000 1000 138 6月 22 2020 docker
-rw-r--r-- 1 root root 60741087 7月 1 2020 docker-19.03.12.tgz
-rw-r--r-- 1 root root 413 8月 6 10:38 docker-daemon.json
-rw-r--r-- 1 root root 487 8月 6 10:37 docker.service
-rw-r--r-- 1 root root 1383 8月 6 10:26 etcd-192.168.100.202.service
-rw-r--r-- 1 root root 1383 8月 6 10:26 etcd-192.168.100.203.service
-rw-r--r-- 1 root root 1058 8月 6 10:23 etcd.csr
-rw-r--r-- 1 root root 354 8月 6 10:21 etcd-csr.json
-rw------- 1 root root 1679 8月 6 10:23 etcd-key.pem
-rw-r--r-- 1 root root 1436 8月 6 10:23 etcd.pem
-rw-r--r-- 1 root root 1382 8月 6 10:25 etcd.service.template
drwxr-xr-x 3 6810230 users 123 10月 11 2018 etcd-v3.3.10-linux-amd64
-rw-r--r-- 1 root root 11353259 3月 25 2020 etcd-v3.3.10-linux-amd64.tar.gz
-rw-r--r-- 1 root root 9565743 3月 25 2020 flannel-v0.11.0-linux-amd64.tar.gz
[root@master01 work]# tar -xzvf flannel-v0.11.0-linux-amd64.tar.gz -C flannel
#分发flannel
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp flannel/{flanneld,mk-docker-opts.sh} root@${all_ip}:/opt/k8s/bin/
ssh root@${all_ip} "chmod +x /opt/k8s/bin/*"
done
#创建flannel证书和密钥,创建flanneld的CA证书请求文件
[root@master01 work]# cat > flanneld-csr.json <<EOF
{
"CN": "flanneld",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
#解释:
该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空。
#生成密钥和证书
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
> -ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
> -profile=kubernetes flanneld-csr.json | cfssljson -bare flanneld
#分发证书和私钥
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "mkdir -p /etc/flanneld/cert"
scp flanneld*.pem root@${all_ip}:/etc/flanneld/cert
done
#写入集群 Pod 网段信息
[root@master01 work]# etcdctl \
--endpoints=${ETCD_ENDPOINTS} \
--ca-file=/opt/k8s/work/ca.pem \
--cert-file=/opt/k8s/work/flanneld.pem \
--key-file=/opt/k8s/work/flanneld-key.pem \
mk ${FLANNEL_ETCD_PREFIX}/config '{"Network":"'${CLUSTER_CIDR}'", "SubnetLen": 21, "Backend": {"Type": "vxlan"}}'
#注意:本步骤只需执行一次。
写入的 Pod 网段 ${CLUSTER_CIDR} 地址段(如 /16)必须小于 SubnetLen,必须与 kube-controller-manager 的 --cluster-cidr 参数值一致。
# 创建flanneld的systemd
[root@master01 work]# source /root/environment.sh
[root@master01 work]# cat > flanneld.service << EOF
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service
[Service]
Type=notify
ExecStart=/opt/k8s/bin/flanneld \\
-etcd-cafile=/etc/kubernetes/cert/ca.pem \\
-etcd-certfile=/etc/flanneld/cert/flanneld.pem \\
-etcd-keyfile=/etc/flanneld/cert/flanneld-key.pem \\
-etcd-endpoints=${ETCD_ENDPOINTS} \\
-etcd-prefix=${FLANNEL_ETCD_PREFIX} \\
-iface=${IFACE} \\
-ip-masq
ExecStartPost=/opt/k8s/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
EOF
#解释:
mk-docker-opts.sh:该脚本将分配给 flanneld 的 Pod 子网段信息写入 /run/flannel/docker 文件,后续 docker 启动时使用这个文件中的环境变量配置 docker0 网桥;
flanneld:使用系统缺省路由所在的接口与其它节点通信,对于有多个网络接口(如内网和公网)的节点,可以用 -iface 参数指定通信接口;
flanneld:运行时需要 root 权限;
-ip-masq: flanneld 为访问 Pod 网络外的流量设置 SNAT 规则,同时将传递给 Docker 的变量 --ip-masq(/run/flannel/docker 文件中)设置为 false,这样 Docker 将不再创建 SNAT 规则; Docker 的 --ip-masq 为 true 时,创建的 SNAT 规则比较“暴力”:将所有本节点 Pod 发起的、访问非 docker0 接口的请求做 SNAT,这样访问其他节点 Pod 的请求来源 IP 会被设置为 flannel.1 接口的 IP,导致目的 Pod 看不到真实的来源 Pod IP。 flanneld 创建的 SNAT 规则比较温和,只对访问非 Pod 网段的请求做 SNAT。
#分发flannel systemd
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp flanneld.service root@${all_ip}:/etc/systemd/system/
done
#启动并验证
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld"
done
#检查flannel启动
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "systemctl status flanneld|grep Active"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 10:52:31 CST; 26s ago #同样四个running即可
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 10:52:32 CST; 24s ago
>>> 192.168.100.205
Active: active (running) since 五 2021-08-06 10:52:33 CST; 23s ago
>>> 192.168.100.206
Active: active (running) since 五 2021-08-06 10:52:35 CST; 22s ago
#检查pod网段信息,查看集群 Pod 网段(/16)
[root@master01 work]# etcdctl \
--endpoints=${ETCD_ENDPOINTS} \
--ca-file=/etc/kubernetes/cert/ca.pem \
--cert-file=/etc/flanneld/cert/flanneld.pem \
--key-file=/etc/flanneld/cert/flanneld-key.pem \
get ${FLANNEL_ETCD_PREFIX}/config
{"Network":"10.10.0.0/16", "SubnetLen": 21, "Backend": {"Type": "vxlan"}} #会输出这个网段信息
#查看已分配的 Pod 子网段列表(/24)
[root@master01 work]# etcdctl \
--endpoints=${ETCD_ENDPOINTS} \
--ca-file=/etc/kubernetes/cert/ca.pem \
--cert-file=/etc/flanneld/cert/flanneld.pem \
--key-file=/etc/flanneld/cert/flanneld-key.pem \
ls ${FLANNEL_ETCD_PREFIX}/subnets
/kubernetes/network/subnets/10.10.152.0-21
/kubernetes/network/subnets/10.10.136.0-21
/kubernetes/network/subnets/10.10.192.0-21
/kubernetes/network/subnets/10.10.168.0-21
#查看某一 Pod 网段对应的节点 IP 和 flannel 接口地址
[root@master01 work]# etcdctl \
--endpoints=${ETCD_ENDPOINTS} \
--ca-file=/etc/kubernetes/cert/ca.pem \
--cert-file=/etc/flanneld/cert/flanneld.pem \
--key-file=/etc/flanneld/cert/flanneld-key.pem \
get ${FLANNEL_ETCD_PREFIX}/subnets/10.10.168.0-21
{"PublicIP":"192.168.100.205","BackendType":"vxlan","BackendData":{"VtepMAC":"66:73:0e:a2:bc:4e"}} #接口信息
#解释输出信息:
10.10.168.0/21 被分配给节点 worker01(192.168.100.205);
VtepMAC 为 worker01 节点的 flannel.1 网卡 MAC 地址。
#检查flannel网络信息
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "/usr/sbin/ip addr show flannel.1 && /usr/sbin/ip addr show docker0"
done
>>> 192.168.100.202
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN
link/ether ea:7b:96:a4:6a:f5 brd ff:ff:ff:ff:ff:ff
inet 10.10.136.0/32 scope global flannel.1 #可以看到各节点的flannel网卡的网段和上面的pod子网段是相对应的
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:1d:99:54:e1 brd ff:ff:ff:ff:ff:ff
inet 10.10.136.1/21 brd 10.10.143.255 scope global docker0
valid_lft forever preferred_lft forever
>>> 192.168.100.203
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN
link/ether f2:74:0d:58:8e:48 brd ff:ff:ff:ff:ff:ff
inet 10.10.192.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:1c:98:5d:f3 brd ff:ff:ff:ff:ff:ff
inet 10.10.192.1/21 brd 10.10.199.255 scope global docker0
valid_lft forever preferred_lft forever
>>> 192.168.100.205
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN
link/ether 66:73:0e:a2:bc:4e brd ff:ff:ff:ff:ff:ff
inet 10.10.168.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:dd:1f:ba:ba brd ff:ff:ff:ff:ff:ff
inet 10.10.168.1/21 brd 10.10.175.255 scope global docker0
valid_lft forever preferred_lft forever
>>> 192.168.100.206
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN
link/ether 12:a4:53:8b:d3:4f brd ff:ff:ff:ff:ff:ff
inet 10.10.152.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:44:74:0d:84 brd ff:ff:ff:ff:ff:ff
inet 10.10.152.1/21 brd 10.10.159.255 scope global docker0
valid_lft forever preferred_lft forever
#解释:flannel.1 网卡的地址为分配的 Pod 子网段的第一个 IP(.0),且是 /32 的地址。
#查看网络信息
[root@master01 work]# ip route show |grep flannel.1
10.10.152.0/21 via 10.10.152.0 dev flannel.1 onlink
10.10.168.0/21 via 10.10.168.0 dev flannel.1 onlink
10.10.192.0/21 via 10.10.192.0 dev flannel.1 onlink
#解释:
到其它节点 Pod 网段请求都被转发到 flannel.1 网卡;
flanneld 根据 etcd 中子网段的信息,如 ${FLANNEL_ETCD_PREFIX}/subnets/172.30.32.0-21 ,来决定进请求发送给哪个节点的互联 IP。
#验证各节点flannel
在各节点上部署 flannel 后,检查是否创建了 flannel 接口(名称可能为 flannel0、flannel.0、flannel.1 等)
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "/usr/sbin/ip addr show flannel.1 | grep -w inet"
done
>>> 192.168.100.202
inet 10.10.136.0/32 scope global flannel.1
>>> 192.168.100.203
inet 10.10.192.0/32 scope global flannel.1
>>> 192.168.100.205
inet 10.10.168.0/32 scope global flannel.1
>>> 192.168.100.206
inet 10.10.152.0/32 scope global flannel.1
#在各节点上 ping 所有 flannel 接口 IP,确保能通,要注意ping的ip要和上面输出的网段信息相匹配
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh ${all_ip} "ping -c 1 10.10.136.0"
ssh ${all_ip} "ping -c 1 10.10.152.0"
ssh ${all_ip} "ping -c 1 10.10.192.0"
ssh ${all_ip} "ping -c 1 10.10.168.0"
done
#输出信息显示能通即可
7、部署master节点高可用
7步骤全部都在master01节点上进行,本次实验采用keepalived+nginx代理实现高可用
#Keepalived安装,创建keepalived的目录
[root@master01 work]# cd
[root@master01 ~]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh ${master_ip} "mkdir -p /opt/k8s/kube-keepalived/"
ssh ${master_ip} "mkdir -p /etc/keepalived/"
done
[root@master01 ~]# cd /opt/k8s/work
[root@master01 work]# wget http://down.linuxsb.com:8888/software/keepalived-2.0.20.tar.gz
[root@master01 work]# ll | grep keepalived
-rw-r--r-- 1 root root 1036063 7月 1 2020 keepalived-2.0.20.tar.gz
[root@master01 work]# tar -zxvf keepalived-2.0.20.tar.gz
[root@master01 work]# cd keepalived-2.0.20/ && ./configure --sysconf=/etc --prefix=/opt/k8s/kube-keepalived/ && make && make install
#分发Keepalived二进制文件
[root@master01 keepalived-2.0.20]# cd ..
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp -rp /opt/k8s/kube-keepalived/ root@${master_ip}:/opt/k8s/
scp -rp /usr/lib/systemd/system/keepalived.service root@${master_ip}:/usr/lib/systemd/system/
ssh ${master_ip} "systemctl daemon-reload && systemctl enable keepalived"
done
# Nginx安装
[root@master01 work]# wget http://nginx.org/download/nginx-1.19.0.tar.gz
[root@master01 work]# ll | grep nginx
-rw-r--r-- 1 root root 1043748 7月 1 2020 nginx-1.19.0.tar.gz
[root@master01 work]# tar -xzvf nginx-1.19.0.tar.gz
[root@master01 work]# cd /opt/k8s/work/nginx-1.19.0/
[root@master01 nginx-1.19.0]# mkdir nginx-prefix
[root@master01 nginx-1.19.0]# ./configure --with-stream --without-http --prefix=$(pwd)/nginx-prefix --without-http_uwsgi_module --without-http_scgi_module --without-http_fastcgi_module
[root@master01 nginx-1.19.0]# make && make install
#解释:
--with-stream:开启 4 层透明转发(TCP Proxy)功能;
--without-xxx:关闭所有其他功能,这样生成的动态链接二进制程序依赖最小。
[root@master01 nginx-1.19.0]# ./nginx-prefix/sbin/nginx -v
nginx version: nginx/1.19.0 #查看版本
#验证编译后的Nginx,查看 nginx 动态链接的库
[root@master01 nginx-1.19.0]# ldd ./nginx-prefix/sbin/nginx
linux-vdso.so.1 => (0x00007ffe23cdd000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f5c49436000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f5c4921a000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5c48e56000)
/lib64/ld-linux-x86-64.so.2 (0x0000559ddee42000)
#提示:
由于只开启了 4 层透明转发功能,所以除了依赖 libc 等操作系统核心 lib 库外,没有对其它 lib 的依赖(如 libz、libssl 等),以便达到精简编译的目的。
#分发Nginx二进制文件
[root@master01 nginx-1.19.0]# cd ..
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p /opt/k8s/kube-nginx/{conf,logs,sbin}"
scp /opt/k8s/work/nginx-1.19.0/nginx-prefix/sbin/nginx root@${master_ip}:/opt/k8s/kube-nginx/sbin/kube-nginx
ssh root@${master_ip} "chmod a+x /opt/k8s/kube-nginx/sbin/*"
done
#配置Nginx system
[root@master01 work]# cat > kube-nginx.service <<EOF
[Unit]
Description=kube-apiserver nginx proxy
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
ExecStartPre=/opt/k8s/kube-nginx/sbin/kube-nginx -c /opt/k8s/kube-nginx/conf/kube-nginx.conf -p /opt/k8s/kube-nginx -t
ExecStart=/opt/k8s/kube-nginx/sbin/kube-nginx -c /opt/k8s/kube-nginx/conf/kube-nginx.conf -p /opt/k8s/kube-nginx
ExecReload=/opt/k8s/kube-nginx/sbin/kube-nginx -c /opt/k8s/kube-nginx/conf/kube-nginx.conf -p /opt/k8s/kube-nginx -s reload
PrivateTmp=true
Restart=always
RestartSec=5
StartLimitInterval=0
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
#分发Nginx systemd
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-nginx.service root@${master_ip}:/etc/systemd/system/
ssh ${master_ip} "systemctl daemon-reload && systemctl enable kube-nginx.service"
done
#创建配置文件
[root@master01 work]# ll | grep config
-rw-r--r-- 1 root root 388 8月 6 10:12 ca-config.json
drwxr-xr-x 6 root root 92 8月 6 11:25 config #上传config目录
-rw-r--r-- 1 root root 567 8月 6 10:12 config.json
[root@master01 work]# vim binngkek8s.sh #需要修改master节点的ip和vip,以及master节点的网卡名称
#!/bin/sh
echo """
请记得一定要先上传,config目录
"""
if [ ! -d config ]
then
sleep 30
echo "请看上边输出..."
exit 1
fi
#######################################
# set variables below to create the config files, all files will create at ./config directory
#######################################
# master keepalived virtual ip address
export K8SHA_VIP=192.168.100.204
# master01 ip address
export K8SHA_IP1=192.168.100.202
# master02 ip address
export K8SHA_IP2=192.168.100.203
# master01 hostname
export K8SHA_HOST1=master01
# master02 hostname
export K8SHA_HOST2=master02
# master01 network interface name
export K8SHA_NETINF1=ens32
# master02 network interface name
export K8SHA_NETINF2=ens32
# keepalived auth_pass config
export K8SHA_KEEPALIVED_AUTH=412f7dc3bfed32194d1600c483e10ad1d
# kubernetes CIDR pod subnet
export K8SHA_PODCIDR=10.10.0.0
# kubernetes CIDR svc subnet
export K8SHA_SVCCIDR=10.20.0.0
##############################
# please do not modify anything below
##############################
mkdir -p config/$K8SHA_HOST1/{keepalived,nginx-lb}
mkdir -p config/$K8SHA_HOST2/{keepalived,nginx-lb}
mkdir -p config/keepalived
mkdir -p config/nginx-lb
# create all keepalived files
chmod u+x config/keepalived/check_apiserver.sh
cp config/keepalived/check_apiserver.sh config/$K8SHA_HOST1/keepalived
cp config/keepalived/check_apiserver.sh config/$K8SHA_HOST2/keepalived
sed \
-e "s/K8SHA_KA_STATE/BACKUP/g" \
-e "s/K8SHA_KA_INTF/${K8SHA_NETINF1}/g" \
-e "s/K8SHA_IPLOCAL/${K8SHA_IP1}/g" \
-e "s/K8SHA_KA_PRIO/102/g" \
-e "s/K8SHA_VIP/${K8SHA_VIP}/g" \
-e "s/K8SHA_KA_AUTH/${K8SHA_KEEPALIVED_AUTH}/g" \
config/keepalived/k8s-keepalived.conf.tpl > config/$K8SHA_HOST1/keepalived/keepalived.conf
sed \
-e "s/K8SHA_KA_STATE/BACKUP/g" \
-e "s/K8SHA_KA_INTF/${K8SHA_NETINF2}/g" \
-e "s/K8SHA_IPLOCAL/${K8SHA_IP2}/g" \
-e "s/K8SHA_KA_PRIO/101/g" \
-e "s/K8SHA_VIP/${K8SHA_VIP}/g" \
-e "s/K8SHA_KA_AUTH/${K8SHA_KEEPALIVED_AUTH}/g" \
config/keepalived/k8s-keepalived.conf.tpl > config/$K8SHA_HOST2/keepalived/keepalived.conf
echo "create keepalived files success. config/$K8SHA_HOST1/keepalived/"
echo "create keepalived files success. config/$K8SHA_HOST2/keepalived/"
# create all nginx-lb files
sed \
-e "s/K8SHA_IP1/$K8SHA_IP1/g" \
-e "s/K8SHA_IP2/$K8SHA_IP2/g" \
-e "s/K8SHA_IP3/$K8SHA_IP3/g" \
config/nginx-lb/bink8s-nginx-lb.conf.tpl > config/nginx-lb/nginx-lb.conf
echo "create nginx-lb files success. config/nginx-lb/nginx-lb.conf"
# cp all file to node
scp -rp config/nginx-lb/nginx-lb.conf root@$K8SHA_HOST1:/opt/k8s/kube-nginx/conf/kube-nginx.conf
scp -rp config/nginx-lb/nginx-lb.conf root@$K8SHA_HOST2:/opt/k8s/kube-nginx/conf/kube-nginx.conf
scp -rp config/$K8SHA_HOST1/keepalived/* root@$K8SHA_HOST1:/etc/keepalived/
scp -rp config/$K8SHA_HOST2/keepalived/* root@$K8SHA_HOST2:/etc/keepalived/
# chmod *.sh
chmod u+x config/*.sh
#保存退出
[root@master01 work]# chmod u+x *.sh
[root@master01 work]# ./binngkek8s.sh
#解释:
如上仅需Master01节点操作。执行binngkek8s.sh脚本后,会自动生成以下配置文件:
• keepalived:keepalived配置文件,位于各个master节点的/etc/keepalived目录
• nginx-lb:nginx-lb负载均衡配置文件,位于各个master节点的/opt/k8s/kube-nginx/conf/kube-nginx.conf目录
#确认高可用配置
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
echo ">>>> check check sh"
ssh root@${master_ip} "ls -l /etc/keepalived/check_apiserver.sh"
echo ">>> check Keepalived config"
ssh root@${master_ip} "cat /etc/keepalived/keepalived.conf"
echo ">>> check Nginx config"
ssh root@${master_ip} "cat /opt/k8s/kube-nginx/conf/kube-nginx.conf"
done
#检查一下高可用配置,会输出nginx和keepalived的配置文件,检查项包括:(要注意看是那个节点的输出信息不要搞混了)
mcast_src_ip #查看此节点的ip
virtual_ipaddress #查看vip地址
upstream apiserver #查看nginx的负载均衡
#启动服务
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl restart keepalived.service && systemctl enable keepalived.service"
ssh root@${master_ip} "systemctl restart kube-nginx.service && systemctl enable kube-nginx.service"
ssh root@${master_ip} "systemctl status keepalived.service | grep Active"
ssh root@${master_ip} "systemctl status kube-nginx.service | grep Active"
ssh root@${master_ip} "netstat -tlunp | grep 16443"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 11:31:55 CST; 292ms ago #都是running并且nginx处于启动状态即可
Active: active (running) since 五 2021-08-06 11:31:55 CST; 255ms ago
tcp 0 0 0.0.0.0:16443 0.0.0.0:* LISTEN 14274/nginx: master
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 11:31:55 CST; 342ms ago
Active: active (running) since 五 2021-08-06 11:31:55 CST; 309ms ago
tcp 0 0 0.0.0.0:16443 0.0.0.0:* LISTEN 8300/nginx: master
#确认验证,稍等一会再进行ping,下面ping的ip是vip,vip是多少就填多少
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "ping -c1 192.168.100.204"
done
#确认都可以ping通即可
8、部署master kubectl
8步骤的所有操作都在master01上进行
#获取kubectl
[root@master01 work]# wget https://storage.googleapis.com/kubernetes-release/release/v1.18.3/kubernetes-client-linux-amd64.tar.gz
[root@master01 work]# ll | grep kubernetes-client
-rw-r--r-- 1 root root 13233170 7月 1 2020 kubernetes-client-linux-amd64.tar.gz
[root@master01 work]# tar -xzvf kubernetes-client-linux-amd64.tar.gz
#分发kubectl
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kubernetes/client/bin/kubectl root@${master_ip}:/opt/k8s/bin/
ssh root@${master_ip} "chmod +x /opt/k8s/bin/*"
done
#创建admin证书和密钥,创建admin的CA证书请求文件
[root@master01 work]# cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
#解释:
O 为 system:masters:kube-apiserver 收到该证书后将请求的 Group 设置为 system:masters;
预定义的 ClusterRoleBinding cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,即该 Role 授予所有 API的权限;
该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空。
#生成密钥和证书
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
-profile=kubernetes admin-csr.json | cfssljson -bare admin
#创建kubeconfig文件
kubectl 默认从 ~/.kube/config 文件读取 kube-apiserver 地址和认证信息。只需在master节点部署一次,其生成的 kubeconfig 文件是通用的,可以拷贝到需要执行 kubectl 命令的机器,重命名为/.kube/config即可。
# 设置集群参数
[root@master01 work]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/work/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kubectl.kubeconfig
# 设置客户端认证参数
[root@master01 work]#kubectl config set-credentials admin \
--client-certificate=/opt/k8s/work/admin.pem \
--client-key=/opt/k8s/work/admin-key.pem \
--embed-certs=true \
--kubeconfig=kubectl.kubeconfig
#设置上下文参数
[root@master01 work]#kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=admin \
--kubeconfig=kubectl.kubeconfig
#设置默认上下文
[root@master01 work]# kubectl config use-context kubernetes --kubeconfig=kubectl.kubeconfig
#解释:
--certificate-authority:验证 kube-apiserver 证书的根证书;
--client-certificate、--client-key:刚生成的 admin 证书和私钥,连接 kube-apiserver 时使用;
--embed-certs=true:将 ca.pem 和 admin.pem 证书内容嵌入到生成的 kubectl.kubeconfig 文件中(默认写入的是证书文件路径,后续需要拷贝 kubeconfig 和该证书文件至到其它机器。)。
#分发kubeconfig
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p ~/.kube"
scp kubectl.kubeconfig root@${master_ip}:~/.kube/config
ssh root@${master_ip} "echo 'export KUBECONFIG=\$HOME/.kube/config' >> ~/.bashrc"
ssh root@${master_ip} "echo 'source <(kubectl completion bash)' >> ~/.bashrc"
done
9、部署kube-apiserver
9步骤全部都在master01上执行
#master节点服务
kubernetes master 节点运行如下组件:
• kube-apiserver
• kube-scheduler
• kube-controller-manager
• kube-nginx
kube-apiserver、kube-scheduler 和 kube-controller-manager 均以多实例模式运行:
kube-scheduler 和 kube-controller-manager 会自动选举产生一个 leader 实例,其它实例处于阻塞模式,当 leader 挂了后,重新选举产生新的 leader,从而保证服务可用性。
kube-apiserver 是无状态的,需要通过 kube-nginx 进行代理访问,从而保证服务可用性。
#安装Kubernetes
[root@master01 work]# wget https://storage.googleapis.com/kubernetes-release/release/v1.18.3/kubernetes-server-linux-amd64.tar.gz
[root@master01 work]# ll | grep kubernetes-server
-rw-r--r-- 1 root root 363654483 7月 1 2020 kubernetes-server-linux-amd64.tar.gz
[root@master01 work]# tar -xzvf kubernetes-server-linux-amd64.tar.gz
[root@master01 work]# cd kubernetes
[root@master01 kubernetes]# tar -xzvf kubernetes-src.tar.gz
#分发Kubernetes
[root@master01 kubernetes]# cd ..
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp -rp kubernetes/server/bin/{apiextensions-apiserver,kube-apiserver,kube-controller-manager,kube-proxy,kube-scheduler,kubeadm,kubectl,kubelet,mounter} root@${master_ip}:/opt/k8s/bin/
ssh root@${master_ip} "chmod +x /opt/k8s/bin/*"
done
高可用apiserver介绍
本实验部署一个三实例 kube-apiserver 集群的步骤,它们通过 kube-nginx 进行代理访问,从而保证服务可用性
#创建kube-apiserver证书,创建Kubernetes证书和私钥,要注意看hosts项中的ip对不对,分别是master01、02和vip地址
[root@master01 work]# cat > kubernetes-csr.json <<EOF
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"192.168.100.202",
"192.168.100.203",
"192.168.100.204",
"${CLUSTER_KUBERNETES_SVC_IP}",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local."
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
#解释:
hosts 字段指定授权使用该证书的 IP 和域名列表,这里列出了 master 节点 IP、kubernetes 服务的 IP 和域名;
kubernetes 服务 IP 是 apiserver 自动创建的,一般是 --service-cluster-ip-range 参数指定的网段的第一个IP,后续可以通过下面命令获取:
kubectl get svc kubernetes
#生成密钥和证书
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
-profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
#分发证书和私钥
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p /etc/kubernetes/cert"
scp kubernetes*.pem root@${master_ip}:/etc/kubernetes/cert/
done
#配置kube-apiserver审计
#创建加密配置文件
[root@master01 work]# cat > encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: ${ENCRYPTION_KEY}
- identity: {}
EOF
#分发加密配置文件
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp encryption-config.yaml root@${master_ip}:/etc/kubernetes/
done
#创建审计策略文件
cat > audit-policy.yaml <<EOF
apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules:
# The following requests were manually identified as high-volume and low-risk, so drop them.
- level: None
resources:
- group: ""
resources:
- endpoints
- services
- services/status
users:
- 'system:kube-proxy'
verbs:
- watch
- level: None
resources:
- group: ""
resources:
- nodes
- nodes/status
userGroups:
- 'system:nodes'
verbs:
- get
- level: None
namespaces:
- kube-system
resources:
- group: ""
resources:
- endpoints
users:
- 'system:kube-controller-manager'
- 'system:kube-scheduler'
- 'system:serviceaccount:kube-system:endpoint-controller'
verbs:
- get
- update
- level: None
resources:
- group: ""
resources:
- namespaces
- namespaces/status
- namespaces/finalize
users:
- 'system:apiserver'
verbs:
- get
# Don't log HPA fetching metrics.
- level: None
resources:
- group: metrics.k8s.io
users:
- 'system:kube-controller-manager'
verbs:
- get
- list
# Don't log these read-only URLs.
- level: None
nonResourceURLs:
- '/healthz*'
- /version
- '/swagger*'
# Don't log events requests.
- level: None
resources:
- group: ""
resources:
- events
# node and pod status calls from nodes are high-volume and can be large, don't log responses for expected updates from nodes
- level: Request
omitStages:
- RequestReceived
resources:
- group: ""
resources:
- nodes/status
- pods/status
users:
- kubelet
- 'system:node-problem-detector'
- 'system:serviceaccount:kube-system:node-problem-detector'
verbs:
- update
- patch
- level: Request
omitStages:
- RequestReceived
resources:
- group: ""
resources:
- nodes/status
- pods/status
userGroups:
- 'system:nodes'
verbs:
- update
- patch
# deletecollection calls can be large, don't log responses for expected namespace deletions
- level: Request
omitStages:
- RequestReceived
users:
- 'system:serviceaccount:kube-system:namespace-controller'
verbs:
- deletecollection
# Secrets, ConfigMaps, and TokenReviews can contain sensitive & binary data,
# so only log at the Metadata level.
- level: Metadata
omitStages:
- RequestReceived
resources:
- group: ""
resources:
- secrets
- configmaps
- group: authentication.k8s.io
resources:
- tokenreviews
# Get repsonses can be large; skip them.
- level: Request
omitStages:
- RequestReceived
resources:
- group: ""
- group: admissionregistration.k8s.io
- group: apiextensions.k8s.io
- group: apiregistration.k8s.io
- group: apps
- group: authentication.k8s.io
- group: authorization.k8s.io
- group: autoscaling
- group: batch
- group: certificates.k8s.io
- group: extensions
- group: metrics.k8s.io
- group: networking.k8s.io
- group: policy
- group: rbac.authorization.k8s.io
- group: scheduling.k8s.io
- group: settings.k8s.io
- group: storage.k8s.io
verbs:
- get
- list
- watch
# Default level for known APIs
- level: RequestResponse
omitStages:
- RequestReceived
resources:
- group: ""
- group: admissionregistration.k8s.io
- group: apiextensions.k8s.io
- group: apiregistration.k8s.io
- group: apps
- group: authentication.k8s.io
- group: authorization.k8s.io
- group: autoscaling
- group: batch
- group: certificates.k8s.io
- group: extensions
- group: metrics.k8s.io
- group: networking.k8s.io
- group: policy
- group: rbac.authorization.k8s.io
- group: scheduling.k8s.io
- group: settings.k8s.io
- group: storage.k8s.io
# Default level for all other requests.
- level: Metadata
omitStages:
- RequestReceived
EOF
#分发策略文件
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp audit-policy.yaml root@${master_ip}:/etc/kubernetes/audit-policy.yaml
done
#配置metrics-server,创建metrics-server的CA证书请求文件
[root@master01 work]# cat > proxy-client-csr.json <<EOF
{
"CN": "system:metrics-server",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
#解释:
CN 名称需要位于 kube-apiserver 的 --requestheader-allowed-names 参数中,否则后续访问 metrics 时会提示权限不足。
#生成密钥和证书
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
-profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client
#分发证书和私钥
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp proxy-client*.pem root@${master_ip}:/etc/kubernetes/cert/
done
#创建kube-apiserver的systemd
[root@master01 work]# cat > kube-apiserver.service.template <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
WorkingDirectory=${K8S_DIR}/kube-apiserver
ExecStart=/opt/k8s/bin/kube-apiserver \\
--insecure-port=0 \\
--secure-port=6443 \\
--bind-address=##MASTER_IP## \\
--advertise-address=##MASTER_IP## \\
--default-not-ready-toleration-seconds=360 \\
--default-unreachable-toleration-seconds=360 \\
--feature-gates=DynamicAuditing=true \\
--max-mutating-requests-inflight=2000 \\
--max-requests-inflight=4000 \\
--default-watch-cache-size=200 \\
--delete-collection-workers=2 \\
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml \\
--etcd-cafile=/etc/kubernetes/cert/ca.pem \\
--etcd-certfile=/etc/kubernetes/cert/kubernetes.pem \\
--etcd-keyfile=/etc/kubernetes/cert/kubernetes-key.pem \\
--etcd-servers=${ETCD_ENDPOINTS} \\
--tls-cert-file=/etc/kubernetes/cert/kubernetes.pem \\
--tls-private-key-file=/etc/kubernetes/cert/kubernetes-key.pem \\
--audit-dynamic-configuration \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-truncate-enabled=true \\
--audit-log-path=${K8S_DIR}/kube-apiserver/audit.log \\
--audit-policy-file=/etc/kubernetes/audit-policy.yaml \\
--profiling \\
--anonymous-auth=false \\
--client-ca-file=/etc/kubernetes/cert/ca.pem \\
--enable-bootstrap-token-auth=true \\
--requestheader-allowed-names="system:metrics-server" \\
--requestheader-client-ca-file=/etc/kubernetes/cert/ca.pem \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--service-account-key-file=/etc/kubernetes/cert/ca.pem \\
--authorization-mode=Node,RBAC \\
--runtime-config=api/all=true \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction \\
--allow-privileged=true \\
--apiserver-count=3 \\
--event-ttl=168h \\
--kubelet-certificate-authority=/etc/kubernetes/cert/ca.pem \\
--kubelet-client-certificate=/etc/kubernetes/cert/kubernetes.pem \\
--kubelet-client-key=/etc/kubernetes/cert/kubernetes-key.pem \\
--kubelet-https=true \\
--kubelet-timeout=10s \\
--proxy-client-cert-file=/etc/kubernetes/cert/proxy-client.pem \\
--proxy-client-key-file=/etc/kubernetes/cert/proxy-client-key.pem \\
--service-cluster-ip-range=${SERVICE_CIDR} \\
--service-node-port-range=${NODE_PORT_RANGE} \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=10
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#使用 --audit-policy-file 标志将包含策略的文件传递给 kube-apiserver。如果不设置该标志,则不记录事件。
#解释:
• --advertise-address:apiserver 对外通告的 IP(kubernetes 服务后端节点 IP);
• --default-*-toleration-seconds:设置节点异常相关的阈值;
• --max-*-requests-inflight:请求相关的最大阈值;
• --etcd-*:访问 etcd 的证书和 etcd 服务器地址;
• --experimental-encryption-provider-config:指定用于加密 etcd 中 secret 的配置;
• --bind-address: https 监听的 IP,不能为 127.0.0.1,否则外界不能访问它的安全端口 6443;
• --secret-port:https 监听端口;
• --insecure-port=0:关闭监听 http 非安全端口(8080);
• --tls-*-file:指定 apiserver 使用的证书、私钥和 CA 文件;
• --audit-*:配置审计策略和审计日志文件相关的参数;
• --client-ca-file:验证 client (kue-controller-manager、kube-scheduler、kubelet、kube-proxy 等)请求所带的证书;
• --enable-bootstrap-token-auth:启用 kubelet bootstrap 的 token 认证;
• --requestheader-*:kube-apiserver 的 aggregator layer 相关的配置参数,proxy-client & HPA 需要使用;
• --requestheader-client-ca-file:用于签名 --proxy-client-cert-file 和 --proxy-client-key-file 指定的证书;在启用了 metric aggregator 时使用;
• --requestheader-allowed-names:不能为空,值为逗号分割的 --proxy-client-cert-file 证书的 CN 名称,这里设置为 "aggregator";
• --service-account-key-file:签名 ServiceAccount Token 的公钥文件,kube-controller-manager 的 --service-account-private-key-file 指定私钥文件,两者配对使用;
• --runtime-config=api/all=true: 启用所有版本的 APIs,如 autoscaling/v2alpha1;
• --authorization-mode=Node,RBAC、--anonymous-auth=false: 开启 Node 和 RBAC 授权模式,拒绝未授权的请求;
• --enable-admission-plugins:启用一些默认关闭的 plugins;
• --allow-privileged:运行执行 privileged 权限的容器;
• --apiserver-count=3:指定 apiserver 实例的数量;
• --event-ttl:指定 events 的保存时间;
• --kubelet-*:如果指定,则使用 https 访问 kubelet APIs;需要为证书对应的用户(上面 kubernetes*.pem 证书的用户为 kubernetes) 用户定义 RBAC 规则,否则访问 kubelet API 时提示未授权;
• --proxy-client-*:apiserver 访问 metrics-server 使用的证书;
• --service-cluster-ip-range: 指定 Service Cluster IP 地址段;
• --service-node-port-range: 指定 NodePort 的端口范围。
#提示:如果 kube-apiserver 机器没有运行 kube-proxy,则还需要添加 --enable-aggregator-routing=true 参数。
#注意:requestheader-client-ca-file 指定的 CA 证书,必须具有 client auth and server auth;
如果 --requestheader-allowed-names 为空,或者 --proxy-client-cert-file 证书的 CN 名称不在 allowed-names 中,则后续查看 node 或 pods 的 metrics 失败,会提示:
[root@master01 ~]# kubectl top nodes #不用进行操作,这里只是演示报错信息
Error from server (Forbidden): nodes.metrics.k8s.io is forbidden: User "aggregator" cannot list resource "nodes" in API group "metrics.k8s.io" at the cluster scope
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#分发systemd
[root@master01 work]# for (( i=0; i < 2; i++ ))
do
sed -e "s/##MASTER_NAME##/${MASTER_NAMES[i]}/" -e "s/##MASTER_IP##/${MASTER_IPS[i]}/" kube-apiserver.service.template > kube-apiserver-${MASTER_IPS[i]}.service
done
[root@master01 work]# ls kube-apiserver*.service #查看,会发现都替换了两个master节点的相应的ip地址
kube-apiserver-192.168.100.202.service kube-apiserver-192.168.100.203.service
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-apiserver-${master_ip}.service root@${master_ip}:/etc/systemd/system/kube-apiserver.service
done
#启动kube-apiserver服务
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p ${K8S_DIR}/kube-apiserver"
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver"
done
#检查kube-apiserver服务
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl status kube-apiserver |grep 'Active:'"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 12:05:06 CST; 31s ago #两个都是running即可
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 12:05:18 CST; 20s ago
#查看kube-apiserver写入etcd的数据
[root@master01 work]# ETCDCTL_API=3 etcdctl \
--endpoints=${ETCD_ENDPOINTS} \
--cacert=/opt/k8s/work/ca.pem \
--cert=/opt/k8s/work/etcd.pem \
--key=/opt/k8s/work/etcd-key.pem \
get /registry/ --prefix --keys-only
#检查集群信息
[root@master01 work]# kubectl cluster-info #集群ip
Kubernetes master is running at https://192.168.100.204:16443
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
[root@master01 work]# kubectl get all --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.20.0.1 <none> 443/TCP 107s
[root@master01 work]# kubectl get componentstatuses
NAME STATUS MESSAGE ERROR
controller-manager Unhealthy Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: connect: connection refused
scheduler Unhealthy Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: connect: connection refused
etcd-0 Healthy {"health":"true"}
etcd-1 Healthy {"health":"true"}
[root@master01 work]# netstat -lnpt|grep 6443
tcp 0 0 192.168.100.202:6443 0.0.0.0:* LISTEN 17172/kube-apiserve
tcp 0 0 0.0.0.0:16443 0.0.0.0:* LISTEN 14274/nginx: master
#提示
执行 kubectl get componentstatuses 命令时,apiserver 默认向 127.0.0.1 发送请求。目前controller-manager和scheduler还未部署,因此显示Unhealthy;
6443: 接收 https 请求的安全端口,对所有请求做认证和授权;
16443:Nginx反向代理监听端口;
由于关闭了非安全端口,故没有监听 8080。
#授权
授予 kube-apiserver 访问 kubelet API 的权限。
在执行 kubectl exec、run、logs 等命令时,apiserver 会将请求转发到 kubelet 的 https 端口。本实验定义 RBAC 规则,授权 apiserver 使用的证书(kubernetes.pem)用户名(CN:kuberntes)访问 kubelet API 的权限:
[root@master01 ~]# kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes
clusterrolebinding.rbac.authorization.k8s.io/kube-apiserver:kubelet-apis created #会提示已创建
10、部署kube-controller-manager
10步骤全部都在master01上执行
高可用kube-controller-manager介绍
本实验部署一个三实例 kube-controller-manager 的集群,启动后将通过竞争选举机制产生一个 leader 节点,其它节点为阻塞状态。当 leader 节点不可用时,阻塞的节点将再次进行选举产生新的 leader 节点,从而保证服务的可用性。
为保证通信安全,本文档先生成 x509 证书和私钥,kube-controller-manager 在如下两种情况下使用该证书:
• 与 kube-apiserver 的安全端口通信;
• 在安全端口(https,10252) 输出 prometheus 格式的 metrics。
#创建kube-controller-manager证书和私钥,创建kube-controller-manager的CA证书请求文件,注意修改ip
[root@master01 work]# source /root/environment.sh
[root@master01 work]# cat > kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"hosts": [
"127.0.0.1",
"192.168.100.202",
"192.168.100.203",
"192.168.100.204"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "system:kube-controller-manager",
"OU": "System"
}
]
}
EOF
#解释:
hosts 列表包含所有 kube-controller-manager 节点 IP;
CN 和 O 均为 system:kube-controller-manager,kubernetes 内置的 ClusterRoleBindings system:kube-controller-manager 赋予 kube-controller-manager 工作所需的权限。
#生成
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
-profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
#分发证书和私钥
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-controller-manager*.pem root@${master_ip}:/etc/kubernetes/cert/
done
#创建和分发kubeconfig
kube-controller-manager 使用 kubeconfig 文件访问 apiserver,该文件提供了 apiserver 地址、嵌入的 CA 证书和 kube-controller-manager 证书:
[root@master01 work]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/work/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-controller-manager.kubeconfig
[root@master01 work]# kubectl config set-credentials system:kube-controller-manager \
--client-certificate=kube-controller-manager.pem \
--client-key=kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=kube-controller-manager.kubeconfig
[root@master01 work]# kubectl config set-context system:kube-controller-manager \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=kube-controller-manager.kubeconfig
[root@master01 work]# kubectl config use-context system:kube-controller-manager --kubeconfig=kube-controller-manager.kubeconfig
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-controller-manager.kubeconfig root@${master_ip}:/etc/kubernetes/
done
#创建kube-controller-manager的systemd
[root@master01 work]# cat > kube-controller-manager.service.template <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
WorkingDirectory=${K8S_DIR}/kube-controller-manager
ExecStart=/opt/k8s/bin/kube-controller-manager \\
--secure-port=10257 \\
--bind-address=127.0.0.1 \\
--profiling \\
--cluster-name=kubernetes \\
--controllers=*,bootstrapsigner,tokencleaner \\
--kube-api-qps=1000 \\
--kube-api-burst=2000 \\
--leader-elect \\
--use-service-account-credentials\\
--concurrent-service-syncs=2 \\
--tls-cert-file=/etc/kubernetes/cert/kube-controller-manager.pem \\
--tls-private-key-file=/etc/kubernetes/cert/kube-controller-manager-key.pem \\
--authentication-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
--client-ca-file=/etc/kubernetes/cert/ca.pem \\
--requestheader-allowed-names="system:metrics-server" \\
--requestheader-client-ca-file=/etc/kubernetes/cert/ca.pem \\
--requestheader-extra-headers-prefix="X-Remote-Extra-" \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--cluster-signing-cert-file=/etc/kubernetes/cert/ca.pem \\
--cluster-signing-key-file=/etc/kubernetes/cert/ca-key.pem \\
--experimental-cluster-signing-duration=87600h \\
--horizontal-pod-autoscaler-sync-period=10s \\
--concurrent-deployment-syncs=10 \\
--concurrent-gc-syncs=30 \\
--node-cidr-mask-size=24 \\
--service-cluster-ip-range=${SERVICE_CIDR} \\
--cluster-cidr=${CLUSTER_CIDR} \\
--pod-eviction-timeout=6m \\
--terminated-pod-gc-threshold=10000 \\
--root-ca-file=/etc/kubernetes/cert/ca.pem \\
--service-account-private-key-file=/etc/kubernetes/cert/ca-key.pem \\
--kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
#分发systemd
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-controller-manager.service.template root@${master_ip}:/etc/systemd/system/kube-controller-manager.service
done
#启动kube-controller-manager 服务
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p ${K8S_DIR}/kube-controller-manager"
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable kube-controller-manager && systemctl restart kube-controller-manager"
done
#检查kube-controller-manager 服务
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl status kube-controller-manager|grep Active"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 12:17:44 CST; 25s ago #全是running即可
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 12:17:45 CST; 25s ago
#查看输出的 metrics
[root@master01 work]# curl -s --cacert /opt/k8s/work/ca.pem --cert /opt/k8s/work/admin.pem --key /opt/k8s/work/admin-key.pem https://127.0.0.1:10257/metrics | head
#查看权限
[root@master01 work]# kubectl describe clusterrole system:kube-controller-manager
#提示
ClusteRole system:kube-controller-manager 的权限很小,只能创建 secret、serviceaccount 等资源对象,各 controller 的权限分散到 ClusterRole system:controller:XXX 中。
当在 kube-controller-manager 的启动参数中添加 --use-service-account-credentials=true 参数,这样 main controller 会为各 controller 创建对应的 ServiceAccount XXX-controller。内置的 ClusterRoleBinding system:controller:XXX 将赋予各 XXX-controller ServiceAccount 对应的 ClusterRole system:controller:XXX 权限。
[root@master01 ~]# kubectl get clusterrole | grep controller
#查看当前leader
[root@master01 work]# kubectl get endpoints kube-controller-manager --namespace=kube-system -o yaml
11、部署kube-scheduler
11步骤全部都在master01上执行
高可用kube-scheduler介绍
本实验部署一个三实例 kube-scheduler 的集群,启动后将通过竞争选举机制产生一个 leader 节点,其它节点为阻塞状态。当 leader 节点不可用时,阻塞的节点将再次进行选举产生新的 leader 节点,从而保证服务的可用性。
为保证通信安全,本文档先生成 x509 证书和私钥,kube-controller-manager 在如下两种情况下使用该证书:
• 与 kube-apiserver 的安全端口通信;
• 在安全端口(https,10251) 输出 prometheus 格式的 metrics。
#创建kube-scheduler证书和私钥,注意修改ip
[root@master01 work]# source /root/environment.sh
[root@master01 work]# cat > kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"hosts": [
"127.0.0.1",
"192.168.100.202",
"192.168.100.203",
"192.168.100.204"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "system:kube-scheduler",
"OU": "System"
}
]
}
EOF
#解释:
hosts 列表包含所有 kube-scheduler 节点 IP;
CN 和 O 均为 system:kube-scheduler,kubernetes 内置的 ClusterRoleBindings system:kube-scheduler 将赋予 kube-scheduler 工作所需的权限。
#生成
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
-profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
#分发证书和私钥
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-scheduler*.pem root@${master_ip}:/etc/kubernetes/cert/
done
#创建和分发kubeconfig
kube-scheduler 使用 kubeconfig 文件访问 apiserver,该文件提供了 apiserver 地址、嵌入的 CA 证书和 kube-scheduler 证书
[root@master01 work]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/work/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-scheduler.kubeconfig
[root@master01 work]# kubectl config set-credentials system:kube-scheduler \
--client-certificate=kube-scheduler.pem \
--client-key=kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=kube-scheduler.kubeconfig
[root@master01 work]# kubectl config set-context system:kube-scheduler \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=kube-scheduler.kubeconfig
[root@master01 work]# kubectl config use-context system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-scheduler.kubeconfig root@${master_ip}:/etc/kubernetes/
done
#创建kube-scheduler 配置文件
[root@master01 work]# cat > kube-scheduler.yaml.template <<EOF
apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
bindTimeoutSeconds: 600
clientConnection:
burst: 200
kubeconfig: "/etc/kubernetes/kube-scheduler.kubeconfig"
qps: 100
enableContentionProfiling: false
enableProfiling: true
hardPodAffinitySymmetricWeight: 1
healthzBindAddress: 127.0.0.1:10251
leaderElection:
leaderElect: true
metricsBindAddress: 127.0.0.1:10251
EOF
#解释:
--kubeconfig:指定 kubeconfig 文件路径,kube-scheduler 使用它连接和验证 kube-apiserver;
--leader-elect=true:集群运行模式,启用选举功能;被选为 leader 的节点负责处理工作,其它节点为阻塞状态。
#分发配置文件
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-scheduler.yaml.template root@${master_ip}:/etc/kubernetes/kube-scheduler.yaml
done
# 创建kube-scheduler的systemd
[root@master01 work]# cat > kube-scheduler.service.template <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
WorkingDirectory=${K8S_DIR}/kube-scheduler
ExecStart=/opt/k8s/bin/kube-scheduler \\
--port=0 \\
--secure-port=10259 \\
--bind-address=127.0.0.1 \\
--config=/etc/kubernetes/kube-scheduler.yaml \\
--tls-cert-file=/etc/kubernetes/cert/kube-scheduler.pem \\
--tls-private-key-file=/etc/kubernetes/cert/kube-scheduler-key.pem \\
--authentication-kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \\
--client-ca-file=/etc/kubernetes/cert/ca.pem \\
--requestheader-allowed-names="system:metrics-server" \\
--requestheader-client-ca-file=/etc/kubernetes/cert/ca.pem \\
--requestheader-extra-headers-prefix="X-Remote-Extra-" \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--authorization-kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \\
--logtostderr=true \\
--v=2
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOF
#分发systemd
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
scp kube-scheduler.service.template root@${master_ip}:/etc/systemd/system/kube-scheduler.service
done
# 启动kube-scheduler 服务,启动服务前必须先创建工作目录
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "mkdir -p ${K8S_DIR}/kube-scheduler"
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable kube-scheduler && systemctl restart kube-scheduler"
done
# 检查kube-scheduler 服务
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl status kube-scheduler | grep Active"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 12:30:52 CST; 22s ago
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 12:30:53 CST; 22s ago
# 查看输出的 metrics
kube-scheduler 监听 10251 和 10251 端口:
• 10251:接收 http 请求,非安全端口,不需要认证授权;
• 10259:接收 https 请求,安全端口,需要认证授权。
• 两个接口都对外提供 /metrics 和 /healthz 的访问。
[root@master01 work]# for master_ip in ${MASTER_IPS[@]}
do
echo ">>> ${master_ip}"
ssh root@${master_ip} "netstat -lnpt | grep kube-sch"
done
#测试非安全端口
[root@master01 work]# curl -s http://127.0.0.1:10251/metrics | head
#测试安全端口
[root@master01 work]# curl -s --cacert /opt/k8s/work/ca.pem --cert /opt/k8s/work/admin.pem --key /opt/k8s/work/admin-key.pem https://127.0.0.1:10259/metrics | head
#查看当前leader
[root@master01 work]# kubectl get endpoints kube-scheduler --namespace=kube-system -o yaml
12、部署worker kubelet
12步骤全部都在master01上执行
kubelet 运行在每个 worker 节点上,接收 kube-apiserver 发送的请求,管理 Pod 容器,执行交互式命令,如 exec、run、logs 等。
kubelet 启动时自动向 kube-apiserver 注册节点信息,内置的 cadvisor 统计和监控节点的资源使用情况。
为确保安全,部署时关闭了 kubelet 的非安全 http 端口,对请求进行认证和授权,拒绝未授权的访问(如 apiserver、heapster 的请求)。
#提示:master01节点已下载相应二进制,可直接分发至worker节点。
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp kubernetes/server/bin/kubelet root@${all_ip}:/opt/k8s/bin/
ssh root@${all_ip} "chmod +x /opt/k8s/bin/*"
done
#分发kubeconfig
[root@master01 work]# for all_name in ${ALL_NAMES[@]}
do
echo ">>> ${all_name}"
export BOOTSTRAP_TOKEN=$(kubeadm token create \
--description kubelet-bootstrap-token \
--groups system:bootstrappers:${all_name} \
--kubeconfig ~/.kube/config)
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/cert/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kubelet-bootstrap-${all_name}.kubeconfig
kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=kubelet-bootstrap-${all_name}.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=kubelet-bootstrap-${all_name}.kubeconfig
kubectl config use-context default --kubeconfig=kubelet-bootstrap-${all_name}.kubeconfig
done
#解释:
向 kubeconfig 写入的是 token,bootstrap 结束后 kube-controller-manager 为 kubelet 创建 client 和 server 证书。
token 有效期为 1 天,超期后将不能再被用来 boostrap kubelet,且会被 kube-controller-manager 的 tokencleaner 清理;
kube-apiserver 接收 kubelet 的 bootstrap token 后,将请求的 user 设置为 system:bootstrap:<Token ID>,group 设置为 system:bootstrappers,后续将为这个 group 设置 ClusterRoleBinding。
#查看 kubeadm 为各节点创建的 token
[root@master01 work]# kubeadm token list --kubeconfig ~/.kube/config
##查看各 token 关联的 Secret
[root@master01 work]# kubectl get secrets -n kube-system|grep bootstrap-token
#分发bootstrap kubeconfig
[root@master01 work]# for all_name in ${ALL_NAMES[@]}
do
echo ">>> ${all_name}"
scp kubelet-bootstrap-${all_name}.kubeconfig root@${all_name}:/etc/kubernetes/kubelet-bootstrap.kubeconfig
done
# 创建kubelet 参数配置文件
[root@master01 work]# cat > kubelet-config.yaml.template <<EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: "##ALL_IP##"
staticPodPath: ""
syncFrequency: 1m
fileCheckFrequency: 20s
httpCheckFrequency: 20s
staticPodURL: ""
port: 10250
readOnlyPort: 0
rotateCertificates: true
serverTLSBootstrap: true
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: "/etc/kubernetes/cert/ca.pem"
authorization:
mode: Webhook
registryPullQPS: 0
registryBurst: 20
eventRecordQPS: 0
eventBurst: 20
enableDebuggingHandlers: true
enableContentionProfiling: true
healthzPort: 10248
healthzBindAddress: "##ALL_IP##"
clusterDomain: "${CLUSTER_DNS_DOMAIN}"
clusterDNS:
- "${CLUSTER_DNS_SVC_IP}"
nodeStatusUpdateFrequency: 10s
nodeStatusReportFrequency: 1m
imageMinimumGCAge: 2m
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
volumeStatsAggPeriod: 1m
kubeletCgroups: ""
systemCgroups: ""
cgroupRoot: ""
cgroupsPerQOS: true
cgroupDriver: cgroupfs
runtimeRequestTimeout: 10m
hairpinMode: promiscuous-bridge
maxPods: 220
podCIDR: "${CLUSTER_CIDR}"
podPidsLimit: -1
resolvConf: /etc/resolv.conf
maxOpenFiles: 1000000
kubeAPIQPS: 1000
kubeAPIBurst: 2000
serializeImagePulls: false
evictionHard:
memory.available: "100Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "15%"
evictionSoft: {}
enableControllerAttachDetach: true
failSwapOn: true
containerLogMaxSize: 20Mi
containerLogMaxFiles: 10
systemReserved: {}
kubeReserved: {}
systemReservedCgroup: ""
kubeReservedCgroup: ""
enforceNodeAllocatable: ["pods"]
EOF
#分发kubelet 参数配置文件
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
sed -e "s/##ALL_IP##/${all_ip}/" kubelet-config.yaml.template > kubelet-config-${all_ip}.yaml.template
scp kubelet-config-${all_ip}.yaml.template root@${all_ip}:/etc/kubernetes/kubelet-config.yaml
done
#创建kubelet systemd
[root@master01 work]# cat > kubelet.service.template <<EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=${K8S_DIR}/kubelet
ExecStart=/opt/k8s/bin/kubelet \\
--bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \\
--cert-dir=/etc/kubernetes/cert \\
--cgroup-driver=cgroupfs \\
--cni-conf-dir=/etc/cni/net.d \\
--container-runtime=docker \\
--container-runtime-endpoint=unix:///var/run/dockershim.sock \\
--root-dir=${K8S_DIR}/kubelet \\
--kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
--config=/etc/kubernetes/kubelet-config.yaml \\
--hostname-override=##ALL_NAME## \\
--pod-infra-container-image=k8s.gcr.io/pause-amd64:3.2 \\
--image-pull-progress-deadline=15m \\
--volume-plugin-dir=${K8S_DIR}/kubelet/kubelet-plugins/volume/exec/ \\
--logtostderr=true \\
--v=2
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOF
#解释:
• 如果设置了 --hostname-override 选项,则 kube-proxy 也需要设置该选项,否则会出现找不到 Node 的情况;
• --bootstrap-kubeconfig:指向 bootstrap kubeconfig 文件,kubelet 使用该文件中的用户名和 token 向 kube-apiserver 发送 TLS Bootstrapping 请求;
• K8S approve kubelet 的 csr 请求后,在 --cert-dir 目录创建证书和私钥文件,然后写入 --kubeconfig 文件;
• --pod-infra-container-image 不使用 redhat 的 pod-infrastructure:latest 镜像,它不能回收容器的僵尸。
#分发kubelet systemd
[root@master01 work]# for all_name in ${ALL_NAMES[@]}
do
echo ">>> ${all_name}"
sed -e "s/##ALL_NAME##/${all_name}/" kubelet.service.template > kubelet-${all_name}.service
scp kubelet-${all_name}.service root@${all_name}:/etc/systemd/system/kubelet.service
done
#授权
kubelet 启动时查找 --kubeletconfig 参数对应的文件是否存在,如果不存在则使用 --bootstrap-kubeconfig 指定的 kubeconfig 文件向 kube-apiserver 发送证书签名请求 (CSR)。
kube-apiserver 收到 CSR 请求后,对其中的 Token 进行认证,认证通过后将请求的 user 设置为 system:bootstrap:<Token ID>,group 设置为 system:bootstrappers,这一过程称为 Bootstrap Token Auth。
默认情况下,这个 user 和 group 没有创建 CSR 的权限,因此kubelet 会启动失败,可通过如下方式创建一个 clusterrolebinding,将 group system:bootstrappers 和 clusterrole system:node-bootstrapper 绑定。
[root@master01 work]# kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers
#启动kubelet
[root@master01 work]# for all_name in ${ALL_NAMES[@]}
do
echo ">>> ${all_name}"
ssh root@${all_name} "mkdir -p ${K8S_DIR}/kubelet/kubelet-plugins/volume/exec/"
ssh root@${all_name} "/usr/sbin/swapoff -a"
ssh root@${all_name} "systemctl daemon-reload && systemctl enable kubelet && systemctl restart kubelet"
done
kubelet 启动后使用 --bootstrap-kubeconfig 向 kube-apiserver 发送 CSR 请求,当这个 CSR 被 approve 后,kube-controller-manager 为 kubelet 创建 TLS 客户端证书、私钥和 --kubeletconfig 文件。
#注意:kube-controller-manager 需要配置 --cluster-signing-cert-file 和 --cluster-signing-key-file 参数,才会为 TLS Bootstrap 创建证书和私钥。
#提示:启动服务前必须先创建工作目录;
#关闭 swap 分区,否则 kubelet 会启动失败。
#提示:本步骤操作仅需要在master01节点操作。
#查看kubelet服务
[root@master01 work]# for all_name in ${ALL_NAMES[@]}
do
echo ">>> ${all_name}"
ssh root@${all_name} "systemctl status kubelet|grep active"
done
>>> master01
Active: active (running) since 五 2021-08-06 12:41:14 CST; 1min 9s ago #全是running即可
>>> master02
Active: active (running) since 五 2021-08-06 12:41:14 CST; 1min 8s ago
>>> worker01
Active: active (running) since 五 2021-08-06 12:41:15 CST; 1min 8s ago
>>> worker02
Active: active (running) since 五 2021-08-06 12:41:16 CST; 1min 7s ago
[root@master01 work]# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
csr-mkkcx 92s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:hrdvi4 Pending
csr-pgx7g 94s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:32syq8 Pending
csr-v6cws 93s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:0top7h Pending
csr-vhq62 93s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:bf9va5 Pending
[root@master01 work]# kubectl get nodes
No resources found in default namespace.
#自动 approve CSR 请求
创建三个 ClusterRoleBinding,分别用于自动 approve client、renew client、renew server 证书。
[root@master01 work]# cat > csr-crb.yaml <<EOF
# Approve all CSRs for the group "system:bootstrappers"
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: auto-approve-csrs-for-group
subjects:
- kind: Group
name: system:bootstrappers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
apiGroup: rbac.authorization.k8s.io
---
# To let a node of the group "system:nodes" renew its own credentials
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: node-client-cert-renewal
subjects:
- kind: Group
name: system:nodes
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
apiGroup: rbac.authorization.k8s.io
---
# A ClusterRole which instructs the CSR approver to approve a node requesting a
# serving cert matching its client cert.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: approve-node-server-renewal-csr
rules:
- apiGroups: ["certificates.k8s.io"]
resources: ["certificatesigningrequests/selfnodeserver"]
verbs: ["create"]
---
# To let a node of the group "system:nodes" renew its own server credentials
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: node-server-cert-renewal
subjects:
- kind: Group
name: system:nodes
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: approve-node-server-renewal-csr
apiGroup: rbac.authorization.k8s.io
EOF
[root@master01 work]# kubectl apply -f csr-crb.yaml
#解释:
auto-approve-csrs-for-group:自动 approve node 的第一次 CSR; 注意第一次 CSR 时,请求的 Group 为 system:bootstrappers;
node-client-cert-renewal:自动 approve node 后续过期的 client 证书,自动生成的证书 Group 为 system:nodes;
node-server-cert-renewal:自动 approve node 后续过期的 server 证书,自动生成的证书 Group 为 system:nodes。
#查看 kubelet 的情况
[root@master01 work]# kubectl get csr | grep boot
csr-mkkcx 4m8s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:hrdvi4 Pending
csr-pgx7g 4m10s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:32syq8 Pending
csr-v6cws 4m9s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:0top7h Pending
csr-vhq62 4m9s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:bf9va5 Pending
#等待一段时间(1-10 分钟),三个节点的 CSR 都被自动 approved
[root@master01 work]# ls -l /etc/kubernetes/kubelet.kubeconfig
-rw------- 1 root root 2313 8月 6 12:41 /etc/kubernetes/kubelet.kubeconfig
[root@master01 work]# ls -l /etc/kubernetes/cert/ | grep kubelet
-rw------- 1 root root 1224 8月 6 12:48 kubelet-client-2021-08-06-12-48-03.pem
lrwxrwxrwx 1 root root 59 8月 6 12:48 kubelet-client-current.pem -> /etc/kubernetes/cert/kubelet-client-2021-08-06-12-48-03.pem
#手动 approve server cert csr
基于安全性考虑,CSR approving controllers 不会自动 approve kubelet server 证书签名请求,需要手动 approve。
[root@master01 work]# kubectl get csr | grep node #现在还是pending
csr-874vr 23s kubernetes.io/kubelet-serving system:node:master01 Pending
csr-dsc6z 22s kubernetes.io/kubelet-serving system:node:master02 Pending
csr-t6wvz 22s kubernetes.io/kubelet-serving system:node:worker02 Pending
csr-wc84r 22s kubernetes.io/kubelet-serving system:node:worker01 Pending
[root@master01 work]# kubectl get csr | grep Pending | awk '{print $1}' | xargs kubectl certificate approve
certificatesigningrequest.certificates.k8s.io/csr-874vr approved
certificatesigningrequest.certificates.k8s.io/csr-dsc6z approved
certificatesigningrequest.certificates.k8s.io/csr-t6wvz approved
certificatesigningrequest.certificates.k8s.io/csr-wc84r approved
[root@master01 work]# ls -l /etc/kubernetes/cert/kubelet-*
-rw------- 1 root root 1224 8月 6 12:48 /etc/kubernetes/cert/kubelet-client-2021-08-06-12-48-03.pem
lrwxrwxrwx 1 root root 59 8月 6 12:48 /etc/kubernetes/cert/kubelet-client-current.pem -> /etc/kubernetes/cert/kubelet-client-2021-08-06-12-48-03.pem
-rw------- 1 root root 1261 8月 6 12:48 /etc/kubernetes/cert/kubelet-server-2021-08-06-12-48-53.pem
lrwxrwxrwx 1 root root 59 8月 6 12:48 /etc/kubernetes/cert/kubelet-server-current.pem -> /etc/kubernetes/cert/kubelet-server-2021-08-06-12-48-53.pem
[root@master01 work]# kubectl get csr | grep node
csr-874vr 64s kubernetes.io/kubelet-serving system:node:master01 Approved,Issued
csr-dsc6z 63s kubernetes.io/kubelet-serving system:node:master02 Approved,Issued
csr-t6wvz 63s kubernetes.io/kubelet-serving system:node:worker02 Approved,Issued
csr-wc84r 63s kubernetes.io/kubelet-serving system:node:worker01 Approved,Issued
[root@master01 work]# kubectl get nodes #查看集群节点状态,都是ready就对了
NAME STATUS ROLES AGE VERSION
master01 Ready <none> 103s v1.18.3
master02 Ready <none> 102s v1.18.3
worker01 Ready <none> 101s v1.18.3
worker02 Ready <none> 101s v1.18.3
#kubelet 提供的 API 接口
[root@master01 work]# netstat -lnpt | grep kubelet #查看监听的端口
tcp 0 0 127.0.0.1:35257 0.0.0.0:* LISTEN 20914/kubelet
tcp 0 0 192.168.100.202:10248 0.0.0.0:* LISTEN 20914/kubelet
tcp 0 0 192.168.100.202:10250 0.0.0.0:* LISTEN 20914/kubelet
#解释:
• 10248: healthz http 服务;
• 10250: https 服务,访问该端口时需要认证和授权(即使访问 /healthz 也需要);
• 未开启只读端口 10255;
• 从 K8S v1.10 开始,去除了 --cadvisor-port 参数(默认 4194 端口),不支持访问 cAdvisor UI & API。
#kubelet api 认证和授权
kubelet 配置了如下认证参数:
• authentication.anonymous.enabled:设置为 false,不允许匿名访问 10250 端口;
• authentication.x509.clientCAFile:指定签名客户端证书的 CA 证书,开启 HTTPs 证书认证;
• authentication.webhook.enabled=true:开启 HTTPs bearer token 认证。
同时配置了如下授权参数:
authroization.mode=Webhook:开启 RBAC 授权。
kubelet 收到请求后,使用 clientCAFile 对证书签名进行认证,或者查询 bearer token 是否有效。如果两者都没通过,则拒绝请求,提示 Unauthorized,这里就是都没有通过
[root@master01 work]# curl -s --cacert /etc/kubernetes/cert/ca.pem https://192.168.100.202:10250/metrics
Unauthorized
[root@master01 work]# curl -s --cacert /etc/kubernetes/cert/ca.pem -H "Authorization: Bearer 123456" https://192.168.100.202cs0250/metri
Unauthorized
若通过认证后,kubelet 使用 SubjectAccessReview API 向 kube-apiserver 发送请求,查询证书或 token 对应的 user、group 是否有操作资源的权限(RBAC)。
#证书认证和授权,默认权限不足
[root@master01 work]# curl -s --cacert /etc/kubernetes/cert/ca.pem --cert /etc/kubernetes/cert/kube-controller-manager.pem --key /etc/kubernetes/cert/kube-controller-manager-key.pem https://192.168.100.202:10250/metrics
Forbidden (user=system:kube-controller-manager, verb=get, resource=nodes, subresource=metrics)
##使用最高权限的admin
[root@master01 work]# curl -s --cacert /etc/kubernetes/cert/ca.pem --cert /opt/k8s/work/admin.pem --key /opt/k8s/work/admin-key.pem https://192.168.100.202:10250/metrics | head
#解释:
--cacert、--cert、--key 的参数值必须是文件路径,如上面的 ./admin.pem 不能省略 ./,否则返回 401 Unauthorized。
#创建bear token 认证和授权
[root@master01 work]# kubectl create sa kubelet-api-test
serviceaccount/kubelet-api-test created
[root@master01 work]# kubectl create clusterrolebinding kubelet-api-test --clusterrole=system:kubelet-api-admin --serviceaccount=default:kubelet-api-test
clusterrolebinding.rbac.authorization.k8s.io/kubelet-api-test created
[root@master01 work]# SECRET=$(kubectl get secrets | grep kubelet-api-test | awk '{print $1}')
[root@master01 work]# TOKEN=$(kubectl describe secret ${SECRET} | grep -E '^token' | awk '{print $2}')
[root@master01 work]# echo ${TOKEN} #查看token值
eyJhbGciOiJSUzI1NiIsImtpZCI6IjBMT1lOUFgycEpIOWpQajFoQUpNNHlWMkRxZDNmdUttcVBNVHpyajdTN2sifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Imt1YmVsZXQtYXBpLXRlc3QtdG9rZW4tNGI4Y3YiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3ViZWxldC1hcGktdGVzdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQ2NDhkNzQ5LTg1NWUtNDI4YS1iZGE1LTJiMmQ5NmQwYjNjOSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Omt1YmVsZXQtYXBpLXRlc3QifQ.t_h8MprNlDiSKXBUN_oTCm9KNXxxKbiqHBwBsrx4q7KvyPS10QCZ03nkNhbsjmrboXxSgkj7Ll7yBY_-DaXGI0-bULLA4v8fjK_c0UCWEC3jKHLpsCBIYIS9WKJliZNZb3NgXXGY33n8MEQpZccVz1IyTih0kFPgV4JgQxwYeqIH60mq4KieZv1gAEnnXg9rhU_AXm1bqB7QQEQafWMFO3XHfOo7HYvoVlFa0BzlfJgN8SAExdF6-V6BC6AqY6oRC6BIt7rPlnGIS9iHLEqH8rCm-lDgXlW3LQbn7sbSGZa-kGMnBwI10v7xOdxd18g_FfoNFO-Rcnpb6KbGQsPVbw
[root@master01 work]# curl -s --cacert /etc/kubernetes/cert/ca.pem -H "Authorization: Bearer ${TOKEN}" https://192.168.100.202:10250/metrics | head
13、部署所有节点的kube-proxy
13步骤所有操作都在master01上执行
#kube-proxy 运行在所有节点上,它监听 apiserver 中 service 和 endpoint 的变化情况,创建路由规则以提供服务 IP 和负载均衡功能。
安装kube-proxy
#提示:master01 节点已下载相应二进制,可直接分发至worker节点。
#分发kube-proxy
[root@master01 work]# source /root/environment.sh
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp kubernetes/server/bin/kube-proxy root@${all_ip}:/opt/k8s/bin/
ssh root@${all_ip} "chmod +x /opt/k8s/bin/*"
done
#创建kube-proxy证书和私钥
[root@master01 work]# cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
#解释:
• CN:指定该证书的 User 为 system:kube-proxy;
• 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限;
• 该证书只会被 kube-proxy 当做 client 证书使用,所以 hosts 字段为空。
#生成
[root@master01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
# 创建和分发kubeconfig
kube-proxy 使用 kubeconfig 文件访问 apiserver,该文件提供了 apiserver 地址、嵌入的 CA 证书和 kube-proxy 证书:
[root@master01 work]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/work/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-proxy.kubeconfig
[root@master01 work]# kubectl config set-credentials kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
[root@master01 work]# kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
[root@master01 work]# kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
scp kube-proxy.kubeconfig root@${all_ip}:/etc/kubernetes/
done
#创建kube-proxy 配置文件
从 v1.10 开始,kube-proxy 部分参数可以配置文件中配置。可以使用 --write-config-to 选项生成该配置文件。
[root@master01 work]# cat > kube-proxy-config.yaml.template <<EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
burst: 200
kubeconfig: "/etc/kubernetes/kube-proxy.kubeconfig"
qps: 100
bindAddress: ##ALL_IP##
healthzBindAddress: ##ALL_IP##:10256
metricsBindAddress: ##ALL_IP##:10249
enableProfiling: true
clusterCIDR: ${CLUSTER_CIDR}
hostnameOverride: ##ALL_NAME##
mode: "ipvs"
portRange: ""
kubeProxyIPTablesConfiguration:
masqueradeAll: false
kubeProxyIPVSConfiguration:
scheduler: rr
excludeCIDRs: []
EOF
#解释:
• bindAddress: 监听地址;
• clientConnection.kubeconfig: 连接 apiserver 的 kubeconfig 文件;
• clusterCIDR: kube-proxy 根据 --cluster-cidr 判断集群内部和外部流量,指定 --cluster-cidr 或 --masquerade-all 选项后 kube-proxy 才会对访问 Service IP 的请求做 SNAT;
• hostnameOverride: 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 ipvs 规则;
• mode: 使用 ipvs 模式。
#分发配置文件
[root@master01 work]# for (( i=0; i < 4; i++ ))
do
echo ">>> ${ALL_NAMES[i]}"
sed -e "s/##ALL_NAME##/${ALL_NAMES[i]}/" -e "s/##ALL_IP##/${ALL_IPS[i]}/" kube-proxy-config.yaml.template > kube-proxy-config-${ALL_NAMES[i]}.yaml.template
scp kube-proxy-config-${ALL_NAMES[i]}.yaml.template root@${ALL_NAMES[i]}:/etc/kubernetes/kube-proxy-config.yaml
done
#创建kube-proxy的systemd
[root@master01 work]# cat > kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
WorkingDirectory=${K8S_DIR}/kube-proxy
ExecStart=/opt/k8s/bin/kube-proxy \\
--config=/etc/kubernetes/kube-proxy-config.yaml \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
#分发kube-proxy systemd
[root@master01 work]# for all_name in ${ALL_NAMES[@]}
do
echo ">>> ${all_name}"
scp kube-proxy.service root@${all_name}:/etc/systemd/system/
done
# 启动kube-proxy 服务,启动服务前必须先创建工作目录
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "mkdir -p ${K8S_DIR}/kube-proxy"
ssh root@${all_ip} "modprobe ip_vs_rr"
ssh root@${all_ip} "systemctl daemon-reload && systemctl enable kube-proxy && systemctl restart kube-proxy"
done
#检查kube-proxy 服务
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "systemctl status kube-proxy | grep Active"
done
>>> 192.168.100.202
Active: active (running) since 五 2021-08-06 13:03:59 CST; 42s ago #都是running即可
>>> 192.168.100.203
Active: active (running) since 五 2021-08-06 13:04:00 CST; 42s ago
>>> 192.168.100.205
Active: active (running) since 五 2021-08-06 13:04:00 CST; 41s ago
>>> 192.168.100.206
Active: active (running) since 五 2021-08-06 13:04:01 CST; 41s ago
#查看监听端口
kube-proxy 监听 10249 和 10256 端口:
• 10249:对外提供 /metrics;
• 10256:对外提供 /healthz 的访问。
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "sudo netstat -lnpt | grep kube-prox"
done
#查看ipvs 路由规则
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh root@${all_ip} "/usr/sbin/ipvsadm -ln"
done
#可见所有通过 https 访问 K8S SVC kubernetes 的请求都转发到 kube-apiserver 节点的 6443 端口。
14、验证集群功能
#检查节点状态
[root@master01 work]# kubectl get cs
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health":"true"}
etcd-1 Healthy {"health":"true"}
[root@master01 work]# kubectl cluster-info
Kubernetes master is running at https://192.168.100.204:16443
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
[root@master01 work]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready <none> 20m v1.18.3
master02 Ready <none> 19m v1.18.3
worker01 Ready <none> 19m v1.18.3
worker02 Ready <none> 19m v1.18.3
#创建测试文件
————————————————————————————————————————————————————————————————————————
运行config下的脚本可以自己下载镜像,但是需要联网
[root@master01 work]# bash config/baseimage.sh #提前pull镜像
————————————————————————————————————————————————————————————————————————
[root@master01 work]# source /root/environment.sh
#上传镜像,上传镜像四个节点全部都需要操作
[root@master01 work]# ll | grep nginx
-rw-r--r-- 1 root root 624 8月 6 11:19 kube-nginx.service
drwxr-xr-x 10 1001 1001 206 8月 6 11:16 nginx-1.19.0
-rw-r--r-- 1 root root 1043748 7月 1 2020 nginx-1.19.0.tar.gz
-rw-r--r-- 1 root root 586 8月 6 13:08 nginx-ds.yml
-rw-r--r-- 1 root root 136325120 7月 1 2020 nginx.tar.gz #上传nginx1.19.0的镜像文件
[root@master01 work]# ll | grep pau
-rw-r--r-- 1 root root 692736 7月 1 2020 pause-amd64_3.2.tar #上传pause-amd64_3.2镜像文件
[root@master01 work]# docker load -i nginx.tar.gz #上传
13cb14c2acd3: Loading layer [==================================================>] 72.49MB/72.49MB
d4cf327d8ef5: Loading layer [==================================================>] 63.8MB/63.8MB
7c7d7f446182: Loading layer [==================================================>] 3.072kB/3.072kB
9040af41bb66: Loading layer [==================================================>] 4.096kB/4.096kB
f978b9ed3f26: Loading layer [==================================================>] 3.584kB/3.584kB
Loaded image: nginx:1.19.0
[root@master01 work]# docker load -i pause-amd64_3.2.tar
ba0dae6243cc: Loading layer [==================================================>] 684.5kB/684.5kB
Loaded image: k8s.gcr.io/pause-amd64:3.2
[root@master01 work]# docker images #查看
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
[root@master01 work]# scp nginx.tar.gz root@192.168.100.203:/root
[root@master01 work]# scp nginx.tar.gz root@192.168.100.205:/root
[root@master01 work]# scp nginx.tar.gz root@192.168.100.206:/root
[root@master01 work]# scp pause-amd64_3.2.tar root@192.168.100.203:/root
[root@master01 work]# scp pause-amd64_3.2.tar root@192.168.100.205:/root
[root@master01 work]# scp pause-amd64_3.2.tar root@192.168.100.206:/root
#在另外三台节点使用docker load进行导入
[root@master02 ~]# docker load -i nginx.tar.gz
[root@master02 ~]# docker load -i pause-amd64_3.2.tar
[root@worker01 ~]# docker load -i nginx.tar.gz
[root@worker01 ~]# docker load -i pause-amd64_3.2.tar
[root@worker02 ~]# docker load -i nginx.tar.gz
[root@worker02 ~]# docker load -i pause-amd64_3.2.tar
#在master01编写测试文件
[root@master01 work]# cat > nginx-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx-svc
spec:
type: NodePort
selector:
app: nginx-ds
ports:
- name: http
port: 80
targetPort: 80
nodePort: 8888
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
labels:
app: nginx-ds
spec:
selector:
matchLabels:
app: nginx-ds
template:
metadata:
labels:
app: nginx-ds
spec:
containers:
- name: my-nginx
image: nginx:1.19.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
EOF
[root@master01 work]# kubectl create -f nginx-ds.yml
service/nginx-svc created
daemonset.apps/nginx-ds created
#检查各节点的 Pod IP 连通性
[root@master01 work]# kubectl get pods -o wide | grep nginx-ds
nginx-ds-8znb9 1/1 Running 0 17s 10.10.136.2 master01 <none> <none>
nginx-ds-h2ssb 1/1 Running 0 17s 10.10.152.2 worker02 <none> <none>
nginx-ds-pnjbf 1/1 Running 0 17s 10.10.192.2 master02 <none> <none>
nginx-ds-wjx2z 1/1 Running 0 17s 10.10.168.2 worker01 <none> <none>
[root@master01 work]# for all_ip in ${ALL_IPS[@]}
do
echo ">>> ${all_ip}"
ssh ${all_ip} "ping -c 1 10.10.136.2"
ssh ${all_ip} "ping -c 1 10.10.152.2"
ssh ${all_ip} "ping -c 1 10.10.192.2"
ssh ${all_ip} "ping -c 1 10.10.168.2"
done
#能通即可
#检查服务 IP 和端口可达性
[root@master01 work]# kubectl get svc |grep nginx-svc
nginx-svc NodePort 10.20.0.12 <none> 80:8888/TCP 88s
[root@master01 work]# for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh ${node_ip} "curl -s 10.20.0.12"
done
#注意这个循环的ip要和上面查询到的ip相同,执行后会输出信息,可以看到nginx的页面,例如:
>>> 192.168.100.206
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1> #这样就是成功了
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
#解释:
Service Cluster IP:10.20.0.12
服务端口:80
NodePort 端口:8888
#检查服务的 NodePort 可达性
[root@master01 work]# for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh ${node_ip} "curl -s ${node_ip}:8888"
done
#这个和上面的一样,可以看到nginx页面内容即可
15、部署集群插件coredns
#下载解压
[root@master01 work]# cd /opt/k8s/work/kubernetes/
[root@master01 kubernetes]# tar -xzvf kubernetes-src.tar.gz
# 修改配置
[root@master01 ~]# cd /opt/k8s/work/kubernetes/cluster/addons/dns/coredns
[root@master01 coredns]# cp coredns.yaml.base coredns.yaml
[root@master01 coredns]# source /root/environment.sh
[root@master01 coredns]# sed -i -e "s/__PILLAR__DNS__DOMAIN__/${CLUSTER_DNS_DOMAIN}/" -e "s/__PILLAR__DNS__SERVER__/${CLUSTER_DNS_SVC_IP}/" -e "s/__PILLAR__DNS__MEMORY__LIMIT__/200Mi/" coredns.yaml
#在两台master上上传镜像
[root@master01 work]# docker load -i coredns_1.6.5.tar
225df95e717c: Loading layer [==================================================>] 336.4kB/336.4kB
7c9b0f448297: Loading layer [==================================================>] 41.37MB/41.37MB
Loaded image: k8s.gcr.io/coredns:1.6.5
[root@master01 work]# docker load -i tutum-dnsutils.tar.gz
5f70bf18a086: Loading layer [==================================================>] 1.024kB/1.024kB
3c9ca2b4b72a: Loading layer [==================================================>] 197.2MB/197.2MB
b83a6cb01503: Loading layer [==================================================>] 208.9kB/208.9kB
f5c259e37fdd: Loading layer [==================================================>] 4.608kB/4.608kB
47995420132c: Loading layer [==================================================>] 11.86MB/11.86MB
Loaded image: tutum/dnsutils:latest
[root@master01 work]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
k8s.gcr.io/coredns 1.6.5 70f311871ae1 21 months ago 41.6MB
tutum/dnsutils latest 6cd78a6d3256 6 years ago 200MB
[root@master02 ~]# docker load -i coredns_1.6.5.tar
225df95e717c: Loading layer [==================================================>] 336.4kB/336.4kB
7c9b0f448297: Loading layer [==================================================>] 41.37MB/41.37MB
Loaded image: k8s.gcr.io/coredns:1.6.5
[root@master01 work]# docker load -i tutum-dnsutils.tar.gz
5f70bf18a086: Loading layer [==================================================>] 1.024kB/1.024kB
3c9ca2b4b72a: Loading layer [==================================================>] 197.2MB/197.2MB
b83a6cb01503: Loading layer [==================================================>] 208.9kB/208.9kB
f5c259e37fdd: Loading layer [==================================================>] 4.608kB/4.608kB
47995420132c: Loading layer [==================================================>] 11.86MB/11.86MB
Loaded image: tutum/dnsutils:latest
[root@master02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
k8s.gcr.io/coredns 1.6.5 70f311871ae1 21 months ago 41.6MB
#创建 coredns
设置调度策略
提示:对于非业务应用(即集群内部应用)建议仅部署在master节点,如coredns及dashboard。
[root@master01 coredns]# kubectl label nodes master01 node-role.kubernetes.io/master=true
node/master01 labeled
[root@master01 coredns]# kubectl label nodes master02 node-role.kubernetes.io/master=true
node/master02 labeled
[root@master01 coredns]# vi coredns.yaml
#找到下面这个项里面修改:
apiVersion: apps/v1
kind: Deployment
。。。。。。
97 # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
98 replicas: 2
99 strategy:
。。。。。。
118 nodeSelector: #从这行添加,直接复制119到124行,把119行原来那一行删除
119 node-role.kubernetes.io/master: "true"
120 tolerations:
121 - key: node-role.kubernetes.io/master
122 operator: "Equal"
123 value: ""
124 effect: NoSchedule
#保存退出
#创建coredns并检查
[root@master01 coredns]# kubectl create -f coredns.yaml #都是created即可
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created
#检查 coredns 功能
[root@master01 coredns]# kubectl get all -n kube-system
NAME READY STATUS RESTARTS AGE
pod/coredns-7966bcdf9-hqx7t 1/1 Running 0 5s
pod/coredns-7966bcdf9-nvjk8 1/1 Running 0 5s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-dns ClusterIP 10.20.0.254 <none> 53/UDP,53/TCP,9153/TCP 5s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/coredns 2/2 2 2 5s
NAME DESIRED CURRENT READY AGE
replicaset.apps/coredns-7966bcdf9 2 2 2 5s
#新建Deployment,查看应用
[root@master01 coredns]# cd /opt/k8s/work/
[root@master01 work]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ds-8znb9 1/1 Running 0 106m 10.10.136.2 master01 <none> <none>
nginx-ds-h2ssb 1/1 Running 0 106m 10.10.152.2 worker02 <none> <none>
nginx-ds-pnjbf 1/1 Running 0 106m 10.10.192.2 master02 <none> <none>
nginx-ds-wjx2z 1/1 Running 0 106m 10.10.168.2 worker01 <none> <none>
[root@master01 work]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.20.0.1 <none> 443/TCP 3h14m <none>
nginx-svc NodePort 10.20.0.12 <none> 80:8888/TCP 106m app=nginx-ds
#创建测试pod
[root@master01 work]# source /root/environment.sh
[root@master01 work]# cat > dnsutils-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: dnsutils-ds
labels:
app: dnsutils-ds
spec:
type: NodePort
selector:
app: dnsutils-ds
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: dnsutils-ds
labels:
addonmanager.kubernetes.io/mode: Reconcile
spec:
selector:
matchLabels:
app: dnsutils-ds
template:
metadata:
labels:
app: dnsutils-ds
spec:
containers:
- name: my-dnsutils
image: tutum/dnsutils:latest
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
ports:
- containerPort: 80
EOF
[root@master01 work]# kubectl create -f dnsutils-ds.yml
service/dnsutils-ds created
daemonset.apps/dnsutils-ds created
[root@master01 work]# kubectl get pods -lapp=dnsutils-ds
NAME READY STATUS RESTARTS AGE
dnsutils-ds-hcsw2 1/1 Running 0 6s
dnsutils-ds-msmnd 1/1 Running 0 6s
dnsutils-ds-qvcwp 1/1 Running 0 6s
dnsutils-ds-vrczl 1/1 Running 0 6s
#检查解析
[root@master01 work]# kubectl -it exec dnsutils-ds-hcsw2 -- /bin/sh #这里的pod填上面输出的podname
# cat /etc/resolv.conf
nameserver 10.20.0.254 #可以成功解析
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
# exit
16、部署metrics、dashboard
Metrics介绍
Kubernetes的早期版本依靠Heapster来实现完整的性能数据采集和监控功能,Kubernetes从1.8版本开始,性能数据开始以Metrics API的方式提供标准化接口,并且从1.10版本开始将Heapster替换为Metrics Server。在Kubernetes新的监控体系中,Metrics Server用于提供核心指标(Core Metrics),包括Node、Pod的CPU和内存使用指标。
对其他自定义指标(Custom Metrics)的监控则由Prometheus等组件来完成。
#获取部署文件
[root@master01 work]# mkdir metrics
[root@master01 work]# cd metrics/
[root@master01 metrics]# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml
[root@master01 metrics]# ll
总用量 4
-rw-r--r-- 1 root root 3509 1月 6 2021 components.yaml
[root@master01 metrics]# vi components.yaml
找到这个,在这个项里面修改配置
62 apiVersion: apps/v1
63 kind: Deployment
。。。。。。
69 spec:
70 replicas: 2 #添加这行
71 selector:
。。。。。。
79 spec:
80 serviceAccountName: metrics-server
81 hostNetwork: true #添加这行
。。。。。。
87 - name: metrics-server #添加下面到94行
88 image: k8s.gcr.io/metrics-server-amd64:v0.3.6
89 imagePullPolicy: IfNotPresent
90 args:
91 - --cert-dir=/tmp
92 - --secure-port=4443
93 - --kubelet-insecure-tls
94 - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
95 ports:
#保存退出
#在两台master上上传镜像
[root@master01 metrics]# docker load -i metrics-server-amd64_v0.3.6.tar #上传这个
932da5156413: Loading layer [==================================================>] 3.062MB/3.062MB
7bf3709d22bb: Loading layer [==================================================>] 38.13MB/38.13MB
Loaded image: k8s.gcr.io/metrics-server-amd64:v0.3.6
[root@master01 metrics]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
k8s.gcr.io/coredns 1.6.5 70f311871ae1 21 months ago 41.6MB
k8s.gcr.io/metrics-server-amd64 v0.3.6 9dd718864ce6 22 months ago 39.9MB
tutum/dnsutils latest 6cd78a6d3256 6 years ago 200MB
[root@master02 ~]# docker load -i metrics-server-amd64_v0.3.6.tar
932da5156413: Loading layer [==================================================>] 3.062MB/3.062MB
7bf3709d22bb: Loading layer [==================================================>] 38.13MB/38.13MB
Loaded image: k8s.gcr.io/metrics-server-amd64:v0.3.6
[root@master02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
k8s.gcr.io/coredns 1.6.5 70f311871ae1 21 months ago 41.6MB
k8s.gcr.io/metrics-server-amd64 v0.3.6 9dd718864ce6 22 months ago 39.9MB
tutum/dnsutils latest 6cd78a6d3256 6 years ago 200MB
#正式部署
[root@master01 metrics]# kubectl apply -f components.yaml
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
serviceaccount/metrics-server created
deployment.apps/metrics-server created
service/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
[root@master01 metrics]# kubectl -n kube-system get pods -l k8s-app=metrics-server #都是running即可
NAME READY STATUS RESTARTS AGE
metrics-server-7b97647899-5tnn7 1/1 Running 0 2m44s
metrics-server-7b97647899-tr6qt 1/1 Running 0 2m45s
#查看资源监控
[root@master02 ~]# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master01 111m 5% 2038Mi 53%
master02 101m 5% 1725Mi 44%
worker01 12m 1% 441Mi 23%
worker02 14m 1% 439Mi 23%
[root@master02 ~]# kubectl top pods --all-namespaces
NAMESPACE NAME CPU(cores) MEMORY(bytes)
default dnsutils-ds-hcsw2 0m 0Mi
default dnsutils-ds-msmnd 0m 1Mi
default dnsutils-ds-qvcwp 0m 1Mi
default dnsutils-ds-vrczl 0m 1Mi
default nginx-ds-8znb9 0m 3Mi
default nginx-ds-h2ssb 0m 2Mi
default nginx-ds-pnjbf 0m 3Mi
default nginx-ds-wjx2z 0m 2Mi
kube-system coredns-7966bcdf9-hqx7t 3m 9Mi
kube-system coredns-7966bcdf9-nvjk8 3m 14Mi
kube-system metrics-server-7b97647899-5tnn7 1m 13Mi
kube-system metrics-server-7b97647899-tr6qt 1m 11Mi
#dashboard部署
#设置标签
[root@master01 ~]# kubectl label nodes master01 dashboard=yes
node/master01 labeled
[root@master01 ~]# kubectl label nodes master02 dashboard=yes
node/master02 labeled
#创建证书
[root@master01 metrics]# mkdir -p /opt/k8s/work/dashboard/certs
[root@master01 metrics]# cd /opt/k8s/work/dashboard/certs
[root@master01 certs]# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=ZheJiang/L=HangZhou/O=Xianghy/OU=Xianghy/CN=k8s.odocker.com"
[root@master01 certs]# ls
tls.crt tls.key
[root@master01 certs]# pwd
/opt/k8s/work/dashboard/certs
[root@master01 certs]# scp tls.* root@192.168.100.203:$pwd #要记得在master02上创建目录
tls.crt 100% 1346 1.2MB/s 00:00
tls.key 100% 1704 1.5MB/s 00:00
#手动创建secret
#v2版本dashboard独立ns
[root@master01 certs]# kubectl create ns kubernetes-dashboard
namespace/kubernetes-dashboard created
[root@master01 certs]# kubectl create secret generic kubernetes-dashboard-certs --from-file=/opt/k8s/work/dashboard/certs -n kubernetes-dashboard
secret/kubernetes-dashboard-certs created
#查看新证书
[root@master01 certs]# kubectl get secret kubernetes-dashboard-certs -n kubernetes-dashboard -o yaml
# 下载yaml文件
[root@master01 certs]# cd /opt/k8s/work/dashboard/
[root@master01 dashboard]# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.1/aio/deploy/recommended.yaml
[root@master01 dashboard]# ll
总用量 8
drwxr-xr-x 2 root root 36 8月 6 18:29 certs
-rw-r--r-- 1 root root 7767 7月 2 2020 recommended.yaml
#修改yaml文件
[root@master01 dashboard]# vi recommended.yaml
。。。。。。
30 ---
31
32 kind: Service
33 apiVersion: v1
34 metadata:
35 labels:
36 k8s-app: kubernetes-dashboard
37 name: kubernetes-dashboard
38 namespace: kubernetes-dashboard
39 spec:
40 type: NodePort #增加
41 ports:
42 - port: 443
43 targetPort: 8443
44 nodePort: 30001 #增加
45 selector:
46 k8s-app: kubernetes-dashboard
47
48 ---
。。。。。。
#因为自动生成的证书很多浏览器无法使用,所以我们自己创建,注释掉kubernetes-dashboard-certs对象声明
48 ---
49
50 #apiVersion: v1 #注释掉
51 #kind: Secret
52 #metadata:
53 # labels:
54 # k8s-app: kubernetes-dashboard
55 # name: kubernetes-dashboard-certs
56 # namespace: kubernetes-dashboard
57 #type: Opaque
58
59 ---
。。。。。。
189 spec: #从189开始
190 containers:
191 - name: kubernetes-dashboard
192 image: kubernetesui/dashboard:v2.0.0-beta8
193 imagePullPolicy: IfNotPresent
194 ports:
195 - containerPort: 8443
196 protocol: TCP
197 args:
198 - --auto-generate-certificates
199 - --namespace=kubernetes-dashboard
200 - --tls-key-file=tls.key
201 - --tls-cert-file=tls.crt
202 - --token-ttl=3600
#保存退出
#正式部署
[root@master01 dashboard]# kubectl apply -f recommended.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
namespace/kubernetes-dashboard configured
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
#在master1和master2上都下载一下镜像
[root@master02 ~]# docker pull kubernetesui/metrics-scraper:v1.0.1
[root@master02 ~]# docker pull kubernetesui/dashboard:v2.0.0-beta8
[root@master02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
kubernetesui/dashboard v2.0.0-beta8 eb51a3597525 20 months ago 90.8MB #这个
k8s.gcr.io/coredns 1.6.5 70f311871ae1 21 months ago 41.6MB
k8s.gcr.io/metrics-server-amd64 v0.3.6 9dd718864ce6 22 months ago 39.9MB
kubernetesui/metrics-scraper v1.0.1 709901356c11 2 years ago 40.1MB #这个
tutum/dnsutils latest 6cd78a6d3256 6 years ago 200MB
[root@master01 ~]# docker pull kubernetesui/metrics-scraper:v1.0.1
[root@master01 ~]# docker pull kubernetesui/dashboard:v2.0.0-beta8
[root@master01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.19.0 2622e6cca7eb 14 months ago 132MB
k8s.gcr.io/pause-amd64 3.2 80d28bedfe5d 17 months ago 683kB
kubernetesui/dashboard v2.0.0-beta8 eb51a3597525 20 months ago 90.8MB #这个
k8s.gcr.io/coredns 1.6.5 70f311871ae1 21 months ago 41.6MB
k8s.gcr.io/metrics-server-amd64 v0.3.6 9dd718864ce6 22 months ago 39.9MB
kubernetesui/metrics-scraper v1.0.1 709901356c11 2 years ago 40.1MB #这个
tutum/dnsutils latest 6cd78a6d3256 6 years ago 200MB
#查看状态
[root@master01 dashboard]# kubectl get deployment kubernetes-dashboard -n kubernetes-dashboard
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-dashboard 1/1 1 1 18m
[root@master01 dashboard]# kubectl get services -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.20.55.23 <none> 8000/TCP 18m
kubernetes-dashboard NodePort 10.20.46.179 <none> 443:30001/TCP 18m
[root@master01 dashboard]# kubectl get pods -o wide -n kubernetes-dashboard
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dashboard-metrics-scraper-694557449d-l2cpn 1/1 Running 0 19m 10.10.192.5 master02 <none> <none>
kubernetes-dashboard-df75cc4c7-xz8nt 1/1 Running 0 19m 10.10.136.5 master01 <none> <none>
#提示:master01 NodePort 30001/TCP映射到 dashboard pod 443 端口。
#创建管理员账户
提示:dashboard v2版本默认没有创建具有管理员权限的账户,可如下操作创建。
[root@master01 dashboard]# vi dashboard-admin.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
#保存退出
[root@master01 dashboard]# kubectl apply -f dashboard-admin.yaml
serviceaccount/admin-user created
clusterrolebinding.rbac.authorization.k8s.io/admin-user created
#访问Dashboard
[root@master01 dashboard]# kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') #查看token值
Name: admin-user-token-87x8n
Namespace: kubernetes-dashboard
Labels: <none>
Annotations: kubernetes.io/service-account.name: admin-user
kubernetes.io/service-account.uid: e7006035-fdda-4c70-b5bd-c5342cf9a9e8
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1367 bytes
namespace: 20 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjBMT1lOUFgycEpIOWpQajFoQUpNNHlWMkRxZDNmdUttcVBNVHpyajdTN2sifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLTg3eDhuIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJlNzAwNjAzNS1mZGRhLTRjNzAtYjViZC1jNTM0MmNmOWE5ZTgiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.Rrhwup0uhoIYQAzXhz7VylRYk-cJR1oyAyi4HZc4mJGE6rFcpA6CsfcHtJJvdGticX9hS7TErPlN9nP-yK0dA2T-oxB5mG2RA2H6mMEqa9wU_X4JcQv0Aw7JwEPXzO62I3ue6iThnT8PpsxAN6PQM3fSG1qJqKL8hneyenNzS8J-S09isdZSCChYSk_DsJLf1ICuUMIJvcTAbIELKcmhsf2ixY6k1FAvttmzfB8-EV6I6Brua63pY-5wc3i6Ptrg1FofH5tyOAV5mYDGBZzl9Y1B9N5QM9oJDAffgHP5oAKLnflVeuMeU8miba5phrLh7DTdXT8nKSo34dhUA6CEKw
使用浏览器访问https://192.168.100.204:30001/
成功访问,至此二进制成功安装k8s!!!