Kubernetes二进制搭建

服务器规划

角色IP地址主机名资源配置组件关键要求
Master192.168.56.101k8smaster4CPU/4GB/20GB+kube-apiserver、kube-controller-manager、kube-scheduler、etcd确保与Worker节点网络互通,时间同步,Swap关闭
Node1192.168.56.102k8snode14CPU/8GB/40GB+kubelet、kube-proxy、docker、etcd容器运行时(Docker)版本与K8s兼容,Cgroup驱动配置为systemd
Node2192.168.56.103k8snode24CPU/8GB/40GB+kubelet、kube-proxy、docker、etcd同上

目录结构

所有节点执行以下命令创建统一目录:

mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs,templates}

目录结构如下:

1
2
3
4
5
6
/opt/kubernetes/
├── bin/ # 存放二进制文件(kube-apiserver, kube-scheduler 等)
├── cfg/ # 存放配置文件(*.conf, token.csv 等)
├── logs/ # 存放日志文件
├── ssl/ # 存放证书文件(ca.pem, etcd.pem 等)
└── templates/ # 存放模板文件(如 etcd.service 模板)

系统初始化配置(所有节点执行)

初始化脚本sudo ./setup_k8s.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/bin/bash
# ------------------------- 初始化配置 -------------------------
# 定义执行命令并处理结果的函数
run_cmd() {
local cmd="$1"
local success_msg="$2"
local failure_msg="${3:-命令执行失败,请检查。}"

echo "正在执行:$cmd"
eval "$cmd" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "\e[32m成功: $success_msg\e[0m" # 绿色表示成功
else
echo -e "\e[31m失败: $failure_msg\e[0m" # 红色表示失败
exit 1
fi
}

# ------------------------- 基础配置 -------------------------
# 规划统一路径
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs,templates}

# 关闭防火墙
run_cmd "systemctl stop firewalld && systemctl disable firewalld" \
"防火墙已成功关闭并禁用。"

# 禁用 SELinux
run_cmd "setenforce 0" "SELinux 已临时禁用。" "临时禁用 SELinux 失败,请检查权限。"
run_cmd "sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config" \
"SELinux 已永久禁用,重启后生效。" "永久禁用 SELinux 失败,请检查权限或配置文件。"

# 关闭 Swap
run_cmd "swapoff -a" "Swap 已临时关闭。" "临时关闭 Swap 失败,请检查权限。"
run_cmd "sed -ri '/swap/s/^/#/' /etc/fstab" \
"Swap 已永久关闭,重启后生效。" "永久关闭 Swap 失败,请检查权限或配置文件。"

# 设置主机名
IP=$(hostname -I | awk '{print $1}')
case $IP in
192.168.56.101) hostname="k8smaster";;
192.168.56.102) hostname="k8snode1";;
192.168.56.103) hostname="k8snode2";;
*) echo "Unknown IP: $IP"; exit 1;;
esac
hostnamectl set-hostname "$hostname"

# 添加主机解析
cat >> /etc/hosts <<EOF
192.168.56.101 k8smaster
192.168.56.102 k8snode1
192.168.56.103 k8snode2
EOF
echo -e "\e[32m成功: 主机解析已添加到 /etc/hosts 文件。\e[0m"

# 加载内核模块
run_cmd "cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF" "内核模块配置文件已创建。" "创建内核模块配置文件失败,请检查权限。"
run_cmd "sysctl --system" "内核参数已生效。" "应用内核参数失败,请检查配置。"

# 配置阿里云YUM源
run_cmd "curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo" \
"配置 阿里云 YUM源成功。" "配置 阿里云 YUM源失败。"

# 时间同步
run_cmd "yum install -y chrony" "Chrony 已安装。" "安装 Chrony 失败,请检查网络或 yum 配置。"
run_cmd "systemctl enable chronyd && systemctl start chronyd" "Chrony服务启动成功。"
run_cmd "chronyc sources" "时间同步状态验证成功。"

# ------------------------- 安装 Docker 19.03.15 -------------------------
echo -e "\n\e[34m开始安装 Docker...\e[0m" # 蓝色提示阶段

# 配置阿里云 Docker 源
run_cmd "yum install -y yum-utils wget vim" "已安装 yum-utils wget。" "安装 yum-utils wget 失败。"
run_cmd "yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo" \
"Docker 源已配置成功。" "配置 Docker 源失败。"

#清理旧版本
run_cmd "yum remove -y docker* containerd.io" "旧版本Docker清理完成。"

# 安装指定版本的 Docker
run_cmd "yum install -y docker-ce-19.03.15 docker-ce-cli-19.03.15" \
"Docker 已安装成功。" "安装 Docker 失败,请检查版本是否存在。"

# 配置 Docker 镜像加速
run_cmd "mkdir -p /etc/docker" "Docker 配置目录已创建。" "创建目录失败。"
run_cmd "cat > /etc/docker/daemon.json <<EOF
{
\"log-driver\": \"json-file\",
\"log-opts\": {
\"max-size\": \"100m\",
\"max-file\": \"1\"
},
\"exec-opts\": [\"native.cgroupdriver=systemd\"],
\"registry-mirrors\": [
\"https://x9r52uz5.mirror.aliyuncs.com\",
\"https://dockerhub.icu\",
\"https://docker.chenby.cn\",
\"https://docker.1panel.live\",
\"https://docker.awsl9527.cn\",
\"https://docker.anyhub.us.kg\",
\"https://dhub.kubesre.xyz\"
]
}
EOF" "Docker 镜像加速配置完成。" "配置镜像加速失败。"

# 启动 Docker 服务
run_cmd "systemctl enable docker && systemctl start docker" \
"Docker 服务已启用并启动。" "Docker 服务启动失败。"
run_cmd "docker info | grep 'Cgroup Driver'" "验证Cgroup驱动为systemd。"

echo -e "\n\e[32m所有配置已完成,建议重启系统以确保更改生效!\e[0m"

证书生成与权限设置

准备cfssl证书生成工具

cfssl是一个开源的证书管理工具,使用json文件生成证书,相比openssl更方便使用。 找任意一台服务器操作,这里用Master节点

仅 Master 节点执行此脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/bin/bash
# 生成证书脚本:generate_certs.sh

# 定义节点IP
ETCD_NODES=("192.168.56.101" "192.168.56.102" "192.168.56.103")
CERT_DIR="/opt/kubernetes/ssl"
mkdir -p $CERT_DIR && cd $CERT_DIR

# 定义执行命令并处理结果的函数
run_cmd() {
local cmd="$1"
local success_msg="$2"
local failure_msg="${3:-命令执行失败,请检查。}"

echo "正在执行:$cmd"
eval "$cmd" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "\e[32m成功: $success_msg\e[0m" # 绿色表示成功
else
echo -e "\e[31m失败: $failure_msg\e[0m" # 红色表示失败
exit 1
fi
}

# 安装CFSSL工具
run_cmd "curl -s -L https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_1.6.3_linux_amd64 -o /usr/local/bin/cfssl && chmod +x /usr/local/bin/cfssl" "CFSSL安装成功。" "CFSSL安装失败。"
run_cmd "curl -s -L https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_1.6.3_linux_amd64 -o /usr/local/bin/cfssljson && chmod +x /usr/local/bin/cfssljson" "CFSSLJSON安装成功。" "CFSSLJSON安装失败。"

# 生成CA证书
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": ["signing", "key encipherment", "server auth", "client auth"]
}
}
}
}
EOF

cat > ca-csr.json <<EOF
{
"CN": "Kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"O": "Kubernetes",
"OU": "CA"
}
]
}
EOF
run_cmd "cfssl gencert -initca ca-csr.json | cfssljson -bare ca" "CA证书生成成功。" "CA证书生成失败。"

# 生成etcd证书
cat > etcd-csr.json <<EOF
{
"CN": "etcd",
"hosts": [
"localhost",
"${ETCD_NODES[0]}",
"${ETCD_NODES[1]}",
"${ETCD_NODES[2]}"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"O": "etcd",
"OU": "etcd-cluster"
}
]
}
EOF
run_cmd "cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd" "etcd证书生成成功。" "etcd证书生成失败。"

# 生成apiserver证书
cat > apiserver-csr.json <<EOF
{
"CN": "kube-apiserver",
"hosts": [
"localhost",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local",
"10.96.0.1",
"${ETCD_NODES[0]}",
"${ETCD_NODES[1]}",
"${ETCD_NODES[2]}"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"O": "Kubernetes",
"OU": "API Server"
}
]
}
EOF
run_cmd "cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes apiserver-csr.json | cfssljson -bare apiserver" "API Server证书生成成功。" "API Server证书生成失败。"

# 生成admin证书(用于kubectl)
cat > admin-csr.json <<EOF
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "Kubernetes The Hard Way"
}
]
}
EOF
run_cmd "cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin" "admin证书生成成功。" "admin证书生成失败。"

# 生成kube-proxy证书
cat > kube-proxy-csr.json << EOF
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

run_cmd "cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy" "kube-proxy证书生成成功。" "kube-proxy证书生成失败。"


# 设置私钥权限
run_cmd "find . -maxdepth 1 -name '*-key.pem' -exec chmod 600 {} \;" "私钥权限设置成功。" "私钥权限设置失败。"

# 设置非私钥证书权限
run_cmd "find . -maxdepth 1 -name '*.pem' \! -name '*-*' -exec chmod 644 {} \;" "证书权限设置成功。" "证书权限设置失败。"

echo -e "\e[32m[SUCCESS] 所有证书已生成到 $CERT_DIR,有效期:87600小时(约10年)\e[0m"

部署etcd集群(所有节点执行)

Etcd是一个分布式键值存储系统,Kubernetes使用Etcd进行数据存储,所以先准备 一个Etcd数据库,为解决Etcd单点故障,应采用集群方式部署,这里使用3台组建集 群,可容忍1台机器故障,当然,你也可以使用5台组建集群,可容忍2台机器故障。

节点名称IP
etcd-1192.168.56.101
etcd-2192.168.56.102
etcd-3192.168.56.103

注:为了节省机器,这里与K8s节点机器复用。也可以独立于k8s集群之外部署,只要 apiserver能连接到就行。

安装etcd二进制文件

从Github下载二进制文件

1
2
3
4
ETCD_VERSION="v3.4.9"
wget https://github.com/etcd-io/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-linux-amd64.tar.gz
tar -zxvf etcd-${ETCD_VERSION}-linux-amd64.tar.gz
mv etcd-${ETCD_VERSION}-linux-amd64/{etcd,etcdctl} /usr/local/bin/

将上面Master节点生成的证书文件拷贝到其他etcd节点

1
2
# 192.168.56.102/103 ctd在其他节点执行:
scp -r 192.168.56.101:/opt/kubernetes/ssl/* /opt/kubernetes/ssl/

创建systemd服务文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# /etc/systemd/system/etcd.service 
[Unit]
Description=etcd server
Documentation=https://github.com/etcd-io/etcd
After=network.target

[Service]
Type=notify
EnvironmentFile=/opt/kubernetes/cfg/etcd.conf
ExecStart=/usr/local/bin/etcd \
--cert-file=/opt/kubernetes/ssl/etcd.pem \
--key-file=/opt/kubernetes/ssl/etcd-key.pem \
--peer-cert-file=/opt/kubernetes/ssl/etcd.pem \
--peer-key-file=/opt/kubernetes/ssl/etcd-key.pem \
--trusted-ca-file=/opt/kubernetes/ssl/ca.pem \
--peer-trusted-ca-file=/opt/kubernetes/ssl/ca.pem \
--logger=zap

Restart=always
RestartSec=10s
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target


# /opt/kubernetes/cfg/etcd.conf
# etcd-1 示例
ETCD_NAME="etcd-1"
ETCD_DATA_DIR=/var/lib/etcd
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_LISTEN_PEER_URLS=https://192.168.56.101:2380
ETCD_LISTEN_CLIENT_URLS=https://192.168.56.101:2379,https://localhost:2379
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.56.101:2380,etcd-2=https://192.168.56.102:2380,etcd-3=https://192.168.56.103:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.56.101:2380
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.56.101:2379

# etcd-2 示例
ETCD_NAME="etcd-2"
ETCD_DATA_DIR=/var/lib/etcd
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_LISTEN_PEER_URLS=https://192.168.56.102:2380
ETCD_LISTEN_CLIENT_URLS=https://192.168.56.102:2379,https://localhost:2379
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.56.101:2380,etcd-2=https://192.168.56.102:2380,etcd-3=https://192.168.56.103:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.56.102:2380
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.56.102:2379

# etcd-3 示例
ETCD_NAME="etcd-3"
ETCD_DATA_DIR=/var/lib/etcd
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_LISTEN_PEER_URLS=https://192.168.56.103:2380
ETCD_LISTEN_CLIENT_URLS=https://192.168.56.103:2379,https://localhost:2379
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.56.101:2380,etcd-2=https://192.168.56.102:2380,etcd-3=https://192.168.56.103:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.56.103:2380
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.56.103:2379
  • ETCD_NAME:节点名称,集群中唯一
  • ETCD_DATA_DIR:数据目录
  • ETCD_LISTEN_PEER_URLS:集群通信监听地址
  • ETCD_LISTEN_CLIENT_URLS:客户端访问监听地址
  • ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
  • ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址
  • ETCD_INITIAL_CLUSTER:集群节点地址
  • ETCD_INITIAL_CLUSTER_TOKEN:集群Token
  • ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态,new是新集群,existing表示加入已有集群

其他节点参考

1
2
3
4
5
6
7
8
9
10
11
#[Member]
ETCD_NAME="etcd-1" #自定义改此处,节点2改为etcd-2,节点3改为etcd-3
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.56.101:2380" #修改此处为当前服务器IP
ETCD_LISTEN_CLIENT_URLS="https://192.168.56.101:2379" #修改此处为当前服务器IP
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.56.101:2380" #修改此处为当前服务器IP
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.56.101:2379" #修改此处为当前服务器IP
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.56.101:2380,etcd-2=https://192.168.56.102:2380,etcd-3=https://192.168.56.103:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"

启动etcd集群

1
2
3
systemctl daemon-reload
systemctl enable etcd
systemctl start etcd

验证集群状态

1
2
3
4
5
6
ETCDCTL_API=3 etcdctl \
--endpoints="https://192.168.56.101:2379,https://192.168.56.102:2379,https://192.168.56.103:2379" \
--cacert=/opt/kubernetes/ssl/ca.pem \
--cert=/opt/kubernetes/ssl/etcd.pem \
--key=/opt/kubernetes/ssl/etcd-key.pem \
endpoint health
1
2
3
https://192.168.56.101:2379 is healthy: successfully committed proposal: took = 10.524037ms
https://192.168.56.102:2379 is healthy: successfully committed proposal: took = 11.004703ms
https://192.168.56.103:2379 is healthy: successfully committed proposal: took = 11.154245ms

如果输出上面信息,就说明集群部署成功。如果有问题第一步先看日志: /var/log/messagejournalctl -u etcd

启用 TLS Bootstrapping 机制

背景

在 Kubernetes 集群中,当 kube-apiserver 启用 TLS 认证后,Node 节点上的 kubeletkube-proxy 必须使用 CA 签发的有效证书才能与 kube-apiserver 进行通信。如果手动为每个 Node 节点签发证书,工作量会非常大,并且会增加集群扩展的复杂度。

为了解决这个问题,Kubernetes 引入了 TLS Bootstrapping 机制。通过该机制,kubelet 可以以一个低权限用户(Bootstrap Token)向 kube-apiserver 申请证书,动态签署并生成客户端证书,从而简化了证书管理流程。

目前,TLS Bootstrapping 主要用于 kubelet,而 kube-proxy 仍然需要手动颁发统一的证书。

![TLS Bootstrapping](TLS Bootstrapping.jpg)

TLS Bootstrapping 工作流程

先行了解,后续才会步步操作

  1. 创建 Bootstrap Token 文件
  • 在 Master 节点上创建一个 token.csv 文件,用于存储 Bootstrap Token。
  • 该文件格式如下:
1
<token>,<username>,<user-id>,<group>
  • <token>:用于身份验证的随机字符串(通常为 32 个字符)。
  • <username>:用户名,建议命名为 kubelet-bootstrap
  • <user-id>:用户 ID,可以是一个数字。
  • <group>:用户所属的组,建议设置为 system:node-bootstrapper
  1. 配置 kube-apiserver 支持 TLS Bootstrapping

kube-apiserver 的配置文件中添加以下参数:

1
2
--enable-bootstrap-token-auth=true
--token-auth-file=/opt/kubernetes/cfg/token.csv
  1. 创建 RBAC 角色绑定
  • 为了让 kubelet 使用 Bootstrap Token 申请证书,需要为其绑定适当的 RBAC 权限。
  • 创建一个 ClusterRoleBinding,将 system:node-bootstrapper 组与 system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 角色绑定:
1
2
3
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
  1. 启动 kubelet 并自动申请证书

    • 在 Node 节点上配置 kubelet,使其能够使用 Bootstrap Token 向 kube-apiserver 申请证书。
    • 配置 kubelet 的启动参数,例如:
    1
    2
    --bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig
    --kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig
    • bootstrap.kubeconfig 是一个初始配置文件,包含 Bootstrap Token 和 API Server 地址。
    • kubelet 启动时,它会使用 bootstrap.kubeconfig 中的 Token 向 kube-apiserver 申请证书,并将签发的证书保存到 kubelet.kubeconfig 文件中。
  2. 批准 CertificateSigningRequest (CSR)

    • kubelet 申请证书后,会在 Kubernetes 中生成一个 CSR 对象。
    • 使用以下命令查看未批准的 CSR:
    1
    kubectl get csr
    • 手动批准 CSR:
    1
    kubectl certificate approve <csr-name>
    • 或者,可以通过自动化工具(如控制器)自动批准所有来自 system:bootstrappers 组的 CSR。
  3. 完成证书签发

    • 一旦 CSR 被批准,kube-apiserver 会为 kubelet 签发证书,并将其返回给 kubelet
    • kubelet 将签发的证书保存到指定的 kubeconfig 文件中,后续通信将使用该证书进行认证。

部署Master组件

仅 Master 节点执行

1
2
3
4
5
6
7
8
# 下载Kubernetes Server二进制文件(v1.18.20)
wget https://dl.k8s.io/v1.18.20/kubernetes-server-linux-amd64.tar.gz
tar zxf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin

# 复制执行文件
cp kube-apiserver kube-scheduler kube-controller-manager /opt/kubernetes/bin/
cp kubectl /usr/bin/

配置 kubeconfig 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 设置集群信息
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.56.101:6443

# 指定 CA 证书文件路径,用于验证 API Server 的身份
# 将证书嵌入到 kubeconfig 文件中(避免外部依赖)
# 指定 Kubernetes API Server 的地址和端口
# 解释:
# 这个命令定义了一个名为 "kubernetes" 的集群,包含了 API Server 的地址、CA 证书等信息。
# 它的作用是告诉 kubectl 如何连接到 Kubernetes 集群。


# 设置用户凭据
kubectl config set-credentials admin \
--client-certificate=/opt/kubernetes/ssl/admin.pem \
--client-key=/opt/kubernetes/ssl/admin-key.pem

# 指定客户端证书文件路径,用于向 API Server 证明用户身份
# 指定客户端私钥文件路径,与证书配合使用进行身份验证
# 解释:
# 这个命令定义了一个名为 "admin" 的用户,包含了客户端证书和私钥。
# 它的作用是告诉 kubectl 使用这些凭据来代表 "admin" 用户与 API Server 进行交互。


# 设置上下文
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=admin

# 指定要使用的集群名称(之前通过 set-cluster 定义的)
# 指定要使用的用户名称(之前通过 set-credentials 定义的)
# 解释:
# 这个命令定义了一个名为 "kubernetes" 的上下文,将集群和用户绑定在一起。
# 上下文的作用是将一个特定的集群、用户和命名空间组合起来,方便切换不同的环境。


# 切换当前上下文
kubectl config use-context kubernetes # 切换到名为 "kubernetes" 的上下文

# 解释:
# 这个命令告诉 kubectl 当前应该使用哪个上下文。
# 在这里,我们切换到刚刚定义的 "kubernetes" 上下文,这样后续的 kubectl 命令都会基于这个上下文进行操作。

授权kubelet-bootstrap用户允许请求证书

1
2
3
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap

部署kube-apiserver

  1. 创建 Bootstrap Token 文件

创建配置文件中Bootstrap Token文件

1
2
3
4
5
6
7
8
9
10
11
# 生成随机Token(32位)
BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')

# 写入token.csv文件
cat > /opt/kubernetes/cfg/token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF

# 验证文件内容
cat /opt/kubernetes/cfg/token.csv
80dfa93db74de1e423d1506e48ecfaa1,kubelet-bootstrap,10001,"system:node-bootstrapper"

字段说明

  • BOOTSTRAP_TOKEN:随机生成的 Bootstrap Token(32 个字符)。
  • kubelet-bootstrap:用户名。
  • 10001:用户 ID。
  • "system:node-bootstrapper":用户所属的组。
  1. 创建配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cat > /opt/kubernetes/cfg/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--etcd-servers=https://192.168.56.101:2379,https://192.168.56.102:2379,https://192.168.56.103:2379 \\
--bind-address=192.168.56.101 \\
--secure-port=6443 \\
--advertise-address=192.168.56.101 \\
--allow-privileged=true \\
--service-cluster-ip-range=10.96.0.0/12 \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--authorization-mode=RBAC,Node \\
--enable-bootstrap-token-auth=true \\
--token-auth-file=/opt/kubernetes/cfg/token.csv \\
--service-node-port-range=30000-32767 \\
--kubelet-client-certificate=/opt/kubernetes/ssl/apiserver.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/apiserver-key.pem \\
--tls-cert-file=/opt/kubernetes/ssl/apiserver.pem \\
--tls-private-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--etcd-cafile=/opt/kubernetes/ssl/ca.pem \\
--etcd-certfile=/opt/kubernetes/ssl/etcd.pem \\
--etcd-keyfile=/opt/kubernetes/ssl/etcd-key.pem \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
EOF

注:上面两个\第一个是转义符,第二个是换行符,使用转义符是为了使用EOF保留换行符。

  1. 创建 systemd 服务文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat > /etc/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=etcd.service
Wants=etcd.service

[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-apiserver.conf
ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
  1. 启动服务
1
2
3
systemctl daemon-reload
systemctl enable kube-apiserver
systemctl start kube-apiserver

参数解释

--logtostderr
控制是否将日志输出到标准错误(stderr)。

  • 默认值为 true,即日志默认输出到 stderr。
  • 设置为 false 时,日志会写入文件(通过 --log-dir 指定目录)。

--v
设置日志的详细级别(verbosity level)。

  • 数值越高,日志越详细。例如:
    • 0:仅记录关键信息。
    • 2:记录大多数信息,适合调试。
    • 4 或更高:记录非常详细的调试信息。

--log-dir
指定日志文件存储的目录路径。

  • 如果未设置,日志不会写入文件,而是输出到标准错误(除非 --logtostderr=true)。

--etcd-servers
指定 etcd 集群的地址列表(逗号分隔)。

  • 例如:https://192.168.56.101:2379,https://192.168.56.102:2379
  • Kubernetes 使用 etcd 存储集群的所有数据。

--bind-address
指定 kube-apiserver 监听的 IP 地址。

  • 通常设置为节点的本地 IP 地址(如 192.168.56.101),或者 0.0.0.0 表示监听所有地址。

--secure-port
指定 kube-apiserver 的 HTTPS 安全端口号。

  • 默认值为 6443,这是 Kubernetes 的标准安全端口。

--advertise-address
指定 kube-apiserver 向其他组件(如 kubelet、controller-manager 等)通告的 IP 地址。

  • 通常与 --bind-address 一致,用于集群内部通信。

--allow-privileged
允许在容器中运行特权模式(privileged mode)。

  • 设置为 true 时,允许 Pod 使用特权模式(例如访问主机设备)。

--service-cluster-ip-range
指定 Kubernetes Service 的虚拟 IP 地址范围。

  • 例如:10.0.0.0/24 表示 Service 的 ClusterIP 将从该范围内分配。
  • 这个范围不能与节点网络或 Pod 网络冲突。

--enable-admission-plugins
启用一组准入控制插件(Admission Controllers)。

  • 这些插件在请求到达 API Server 时执行额外的验证或修改操作。
  • 常见插件包括:
    • NamespaceLifecycle
    • LimitRanger
    • ServiceAccount
    • NodeRestriction

--authorization-mode
指定 API Server 的授权模式。

  • 常见模式包括:
    • RBAC
    • Node
  • 多个模式用逗号分隔,例如:RBAC,Node

--enable-bootstrap-token-auth
启用 TLS Bootstrap 机制,允许节点使用临时 Token 自动注册并获取证书。

--token-auth-file
指定包含 Bootstrap Token 的文件路径,用于节点认证。

--service-node-port-range
指定 Service NodePort 类型的端口范围。

  • 例如:30000-32767 是默认范围。

--kubelet-client-certificate, --kubelet-client-key
指定 API Server 访问 kubelet 时使用的客户端证书和密钥文件路径。

--tls-cert-file, --tls-private-key-file
指定 API Server 的 HTTPS 证书和密钥文件路径。

--client-ca-file
指定客户端 CA 证书文件路径,用于验证客户端证书。

--service-account-key-file
指定 Service Account 的私钥文件路径,用于签发 Service Account Token。

--etcd-cafile, --etcd-certfile, --etcd-keyfile
指定连接 etcd 集群时使用的 CA 证书、客户端证书和密钥文件路径。

--audit-log-path, --audit-log-maxage, --audit-log-maxbackup, --audit-log-maxsize
配置审计日志相关参数。

  • 包括:
    • --audit-log-path:审计日志文件路径。
    • --audit-log-maxage:保留审计日志的最大天数。
    • --audit-log-maxbackup:保留的最大审计日志文件数量。
    • --audit-log-maxsize:单个审计日志文件的最大大小(以 MB 为单位)。

部署kube-controller-manager

  1. 创建配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat > /opt/kubernetes/cfg/kube-controller-manager.conf <<EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--master=127.0.0.1:8080 \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.96.0.0/12 \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--experimental-cluster-signing-duration=87600h0m0s"
EOF

–master:通过本地非安全本地端口8080连接apiserver。

–leader-elect:当该组件启动多个时,自动选举(HA)

–cluster-signing-cert-file/–cluster-signing-key-file:自动为kubelet颁发证书 的CA,与apiserver保持一致

  1. systemd管理controller-manager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat > /etc/systemd/system/kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://kubernetes.io/docs/concepts/overview/components/
After=kube-apiserver.service
Requires=kube-apiserver.service

[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-controller-manager.conf
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=always
RestartSec=10s
LimitNOFILE=65536
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=kube-controller-manager

[Install]
WantedBy=multi-user.target
EOF
  1. 启动并设置开机启动
1
2
3
4
5
6
7
systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl start kube-controller-manager

# 检查服务状态
systemctl status kube-controller-manager -l
journalctl -u kube-controller-manager | grep -i error

部署kube-scheduler

1.创建配置文件

1
2
3
4
5
6
7
8
cat > /opt/kubernetes/cfg/kube-scheduler.conf <<EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect \\
--master=127.0.0.1:8080 \\
--bind-address=127.0.0.1"
EOF

–master:通过本地非安全本地端口8080连接apiserver。

–leader-elect:当该组件启动多个时,自动选举(HA)

  1. systemd管理scheduler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat > /etc/systemd/system/kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://kubernetes.io/docs/concepts/overview/components/

[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-scheduler.conf
ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=always
RestartSec=10s
LimitNOFILE=65536
MemoryLimit=512M
CPUQuota=100%
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=kube-scheduler

[Install]
WantedBy=multi-user.target
EOF
  1. 启动并设置开机启动
1
2
3
4
5
6
7
systemctl daemon-reload
systemctl enable kube-scheduler
systemctl start kube-scheduler

# 检查服务状态
systemctl status kube-scheduler -l
journalctl -u kube-scheduler | grep -i error
  1. 查看集群状态

所有组件都已经启动成功,通过kubectl工具查看当前集群组件状态:

1
2
3
kubectl get componentstatus
# 简写
kubectl get cs

预期输出:

1
2
3
4
5
6
NAME                 STATUS    MESSAGE             ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-2 Healthy {"health":"true"}
etcd-0 Healthy {"health":"true"}
etcd-1 Healthy {"health":"true"}

部署node组件

下载并拷贝二进制文件

1
2
3
4
wget https://dl.k8s.io/v1.18.20/kubernetes-server-linux-amd64.tar.gz
tar zxf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
cp kubectl kubelet kube-proxy /opt/kubernetes/bin/

添加环境变量

1
2
echo 'export PATH=$PATH:/opt/kubernetes/bin' | sudo tee -a /etc/profile
source /etc/profile

部署kubelet

创建kubelet配置文件

1
2
3
4
5
6
7
8
9
10
11
12
cat >/opt/kubernetes/cfg/kubelet.conf <<EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=k8snode1 \\
--network-plugin=cni \\
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \\
--config=/opt/kubernetes/cfg/kubelet-config.yml \\
--cert-dir=/opt/kubernetes/ssl \\
--pod-infra-container-image=lizhenliang/pause-amd64:3.0"
EOF

记得修改 -hostname-override=k8snode1

–hostname-override:显示名称,集群中唯一

–network-plugin:启用CNI

–kubeconfig:空路径,会自动生成,后面用于连接apiserver

–bootstrap-kubeconfig:首次启动向apiserver申请证书

–config:配置参数文件

–cert-dir:kubelet证书生成目录

–pod-infra-container-image:管理Pod网络容器的镜像

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cat >/opt/kubernetes/cfg/kubelet-config.yml <<EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
cgroupDriver: systemd # 根据Docker配置调整(如systemd/cgroupfs)
clusterDNS:
- 10.96.0.10 # 默认ClusterDNS为kube-dns服务IP
clusterDomain: cluster.local
failSwapOn: false
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /opt/kubernetes/ssl/ca.pem
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
maxOpenFiles: 100000
maxPods: 110
EOF

执行以下命令会生成bootstrap.kubeconfig文件,移动至/opt/kubernetes/cfg/bootstrap.kubeconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
KUBE_APISERVER="https://192.168.56.101:6443"  # apiserver IP:PORT
TOKEN="80dfa93db74de1e423d1506e48ecfaa1" # 与 token.csv 里保持一致

# 生成 kubelet bootstrap kubeconfig 配置文件(注意命令空格分隔)
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=bootstrap.kubeconfig

kubectl config set-credentials "kubelet-bootstrap" \
--token=${TOKEN} \
--kubeconfig=bootstrap.kubeconfig

kubectl config set-context default \
--cluster=kubernetes \
--user="kubelet-bootstrap" \
--kubeconfig=bootstrap.kubeconfig

kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

# 将生成的文件移动到配置目录
mv bootstrap.kubeconfig /opt/kubernetes/cfg/

systemd管理kubelet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat > /etc/systemd/system//kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service

[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet.conf
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
EOF

启动并设置开机启动

1
2
3
4
5
6
7
8
9
# 重新加载systemd配置
systemctl daemon-reload

# 启动并设置开机启动
systemctl start kubelet
systemctl enable kubelet

# 验证状态
systemctl status kubelet

Master批准kubelet证书申请并加入集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看kubelet证书请求
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
node-csr-RCpKZeogM1MIxtouElJ1WDXPNDe-raOBpkv5gyHt8h0 30m kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending

# 批准申请
$ kubectl certificate approve node-csr-RCpKZeogM1MIxtouElJ1WDXPNDe-raOBpkv5gyHt8h0
certificatesigningrequest.certificates.k8s.io/node-csr-RCpKZeogM1MIxtouElJ1WDXPNDe-raOBpkv5gyHt8h0

# 查看节点
$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8snode1 NotReady <none> 16s v1.18.20
k8snode2 NotReady <none> 11s v1.18.20

注:由于网络插件还没有部署,节点会没有准备就绪 NotReady

部署kube-proxy

1.1 kube-proxy.conf 配置文件

1
2
3
4
5
6
cat > /opt/kubernetes/cfg/kube-proxy.conf << EOF
KUBE_PROXY_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/kubernetes/logs \
--config=/opt/kubernetes/cfg/kube-proxy-config.yml"
EOF

1.2 kube-proxy-config.yml 参数文件

1
2
3
4
5
6
7
8
9
10
cat > /opt/kubernetes/cfg/kube-proxy-config.yml << EOF
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
bindAddress: 0.0.0.0
metricsBindAddress: 0.0.0.0:10249
clientConnection:
kubeconfig: /opt/kubernetes/cfg/kube-proxy.kubeconfig
hostnameOverride: "k8snode1" # 替换为当前节点的主机名
clusterCIDR: 10.0.0.0/24
EOF

说明

  • apiVersion:使用最新版本 v1(原 v1alpha1 已弃用)。
  • bindAddress:监听所有网络接口。
  • metricsBindAddress:监控端口。
  • hostnameOverride:节点名称(需与 kubelet 配置一致)。
  • clusterCIDR:Pod 网络 CIDR。
  1. 生成证书和 kubeconfig 文件

2.1 生成 kube-proxy.kubeconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# API Server 地址
KUBE_APISERVER="https://192.168.56.101:6443"

# 创建 kubeconfig 文件
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-proxy.kubeconfig

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

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

kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

2.2 拷贝文件到指定路径

1
cp kube-proxy.kubeconfig /opt/kubernetes/cfg/
  1. 配置 systemd 服务

3.1 创建 kube-proxy.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat > /usr/lib/systemd/system/kube-proxy.service << EOF
[Unit]
Description=Kubernetes Proxy
After=network.target

[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-proxy.conf
ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

3.2 启动并设置开机启动

1
2
3
systemctl daemon-reload
systemctl start kube-proxy
systemctl enable kube-proxy
  1. 验证部署
1
2
3
4
5
# 查看服务状态
systemctl status kube-proxy

# 查看日志(如有问题)
journalctl -u kube-proxy -f --since "5 minutes ago"

部署集群网络

Node节点操作(所有Worker Node执行)

安装CNI插件(容器网络接口)

1
2
3
4
5
6
# 下载CNI二进制文件
wget https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz

# 解压到CNI插件目录
mkdir -p /opt/cni/bin
tar zxf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
  • 作用
    • CNI插件是Kubernetes容器网络的基础组件,负责为Pod分配IP、配置网络路由和连通性。
    • 常见的插件如bridgeflannelhost-local等会在此目录中提供二进制工具。
  • 预期结果
    • /opt/cni/bin目录下会包含一系列CNI插件二进制文件(如flanneldbridge等)。
    • 若无此步骤,Pod将无法获得IP地址,节点状态会持续为NotReady

Master节点操作

部署Flannel网络插件

1
2
3
4
5
# 下载Flannel的Kubernetes配置文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 应用配置文件
kubectl apply -f kube-flannel.yml
  • 作用
    • Flannel是一个Overlay网络解决方案,负责为集群中的Pod分配子网并实现跨节点通信。
    • kube-flannel.yml定义了Flannel的DaemonSet、ServiceAccount、RBAC规则等资源。

预期结果

  • 每个Node节点会自动启动一个kube-flannel Pod(通过DaemonSet部署)。
  • 执行以下命令验证
1
kubectl get pods -n kube-flannel

输出示例:

1
2
3
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-lc985 1/1 Running 0 2m28s
kube-flannel-ds-vbv67 1/1 Running 0 2m28s
  • 所有节点的STATUS应从NotReady变为Ready(需等待1-2分钟)。

授权API Server访问kubelet

  1. 创建 RBAC 配置文件

创建 apiserver-to-kubelet-rbac.yaml 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups: [""]
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
- pods/log
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kube-apiserver
  1. 应用 RBAC 配置文件
1
kubectl apply -f apiserver-to-kubelet-rbac.yaml
  • 作用
    • 允许API Server通过kubelet的API访问Pod日志、监控指标等。
    • 若无此授权,执行kubectl logskubectl exec时会报权限错误。

测试kubernetes集群

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

步骤 1:创建 Deployment

1
kubectl create deployment nginx --image=nginx
  • 作用
    创建了一个名为 nginx 的 Deployment,使用官方的 nginx 镜像。
  • 结果
    Kubernetes 会自动创建一个 ReplicaSet,并调度一个 Pod 运行 Nginx 容器。

步骤 2:暴露服务

1
kubectl expose deployment nginx --port=80 --type=NodePort
  • 作用
    创建了一个 Service,将 nginx Deployment 的 80 端口暴露为 NodePort 类型的服务。
  • 结果
    Kubernetes 会分配一个随机的高范围端口(默认范围是 30000-32767),并将流量转发到 Nginx Pod 的 80 端口。

步骤 3:查看 Pods

确认 nginx Pod 是否正常运行:

1
2
3
4
5
6
7
# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-f89759699-496vr 1/1 Running 0 3m26s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19h
service/nginx NodePort 10.97.173.113 <none> 80:31366/TCP 28s
  • 解释:
    • nginx Service 的类型为 NodePort
    • 内部 ClusterIP 是 10.100.123.45
    • 外部访问端口是 31366(随机分配的)。

通过 NodePort 访问: 假设节点 IP 地址是 192.168.56.102/103,可以通过以下命令任意node节点IP访问:

1
curl http://192.168.56.102:30001

新增 Worker Node

  1. 拷贝已部署好的 Node 相关文件到新节点

在 Master 节点上,将以下文件拷贝到新节点(例如:192.168.56.102192.168.56.103):

1
2
3
4
scp -r /opt/kubernetes root@192.168.56.102:/opt/
scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service root@192.168.56.102:/usr/lib/systemd/system/
scp -r /opt/cni/ root@192.168.56.102:/opt/
scp /opt/kubernetes/ssl/ca.pem root@192.168.56.102:/opt/kubernetes/ssl/
  1. 删除 kubelet 证书和 kubeconfig 文件

在新节点上删除旧的 kubelet 证书和 kubeconfig 文件:

1
2
rm /opt/kubernetes/cfg/kubelet.kubeconfig
rm -f /opt/kubernetes/ssl/kubelet*

注:这几个文件是证书申请审批后自动生成的,每个Node不同,必须删除重新生成。

  1. 修改主机名

在新节点上修改 kubelet 和 kube-proxy 的配置文件中的主机名:

编辑文件:

1
2
3
4
5
6
7
vi /opt/kubernetes/cfg/kubelet.conf
# 修改以下行:
--hostname-override=k8s-node3

vi /opt/kubernetes/cfg/kube-proxy-config.yml
# 修改以下行:
hostnameOverride: k8s-node3
  1. 启动服务并设置开机启动
1
2
3
4
5
systemctl daemon-reload
systemctl start kubelet
systemctl enable kubelet
systemctl start kube-proxy
systemctl enable kube-proxy
  1. 在 Master 上批准新 Node 的 kubelet 证书申请

在 Master 节点上查看证书签名请求(CSR):

1
2
3
4
kubectl get csr

# 批准证书申请:
kubectl certificate approve <CSR_NAME>
  1. 查看Node状态
1
kubectl get nodes