kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具。

这个工具能通过两条指令完成一个kubernetes集群的部署:

1
2
3
4
5
# 创建一个 Master 节点
$ kubeadm init

# 将一个 Node 节点加入到当前集群中
$ kubeadm join <Master节点的IP和端口 >

1. 安装要求

在开始之前,部署Kubernetes集群机器需要满足以下几个条件:

  • 一台或多台机器,操作系统 CentOS7.x-86_x64
  • 硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多
  • 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
  • 禁止swap分区

2. 准备环境

角色 IP
master 192.168.1.11
node1 192.168.1.12
node2 192.168.1.13

使用kubeadm方式搭建K8s集群主要分为以下几步

  • 准备三台虚拟机,同时安装操作系统CentOS 7.x
  • 对三个安装之后的操作系统进行初始化操作
  • 在三个节点安装 docker kubelet kubeadm kubectl
  • 在master节点执行kubeadm init命令初始化
  • 在node节点上执行 kubeadm join命令,把node节点添加到当前集群
  • 配置CNI网络插件,用于节点之间的连通【失败了可以多试几次】
  • 通过拉取一个nginx进行测试,能否进行外网测试
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
# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld


# 关闭selinux # 永久 # 临时
sed -i 's/enforcing/disabled/' /etc/selinux/config && setenforce 0


## 关闭swap 临时 # 永久
swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab

# 根据规划设置主机名
hostnamectl set-hostname <hostname>

# 在master添加hosts
cat >> /etc/hosts << EOF
172.17.156.95 master
172.17.156.96 node1
172.17.156.97 node2
EOF

# 将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system # 生效

# 时间同步
yum install ntpdate -y
ntpdate time.windows.com

3. 所有节点安装Docker/kubeadm/kubelet

Kubernetes默认CRI(容器运行时)为Docker,因此先安装Docker。

3.1 安装Docker

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
# 1.1 切换镜像源
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

# 1.23 更新并安装Docker-CE
sudo yum makecache fast

# 2 查看当前镜像源中支持的docker版本
$ yum list docker-ce --showduplicates
$ yum search docker-ce --showduplicates


# 3 安装特定版本的docker-ce # 如果想安装最新版本sudo yum -y install docker-ce

$ yum -y install --setopt=obsoletes=0 docker-ce-cli-20.10.18-3.el7.x86_64

# 4 添加一个配置文件
# Docker在默认情况下使用的Cgroup Driver为cgroupfs,而kubernetes推荐使用systemd来代替cgroupfs
# 4.1 查看docker 的 cgroup-driver
$ docker info |grep Cgroup
Cgroup Driver: cgroupfs

# 4.2 修改为 cgroupfs 添加一个配置文件
$ cat > /etc/docker/daemon.json << EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://kn0t2bca.mirror.aliyuncs.com"]
}
EOF

# 5 启动docker
$ systemctl enable docker && systemctl start docker


# 6 检查docker状态和版本
$ docker --version
Docker version 20.10.18, build b40c2f6

3.2 安装kubernetes组件

添加阿里云YUM软件源

1
2
3
4
5
6
7
8
9
$ cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

安装kubeadm,kubelet和kubectl

由于版本更新频繁,这里指定版本号部署:

1
2
3
4
5
6
7
8
9
10
11
# 卸载旧版本
yum remove -y kubelet kubeadm kubectl

# 查看可以安装的版本
yum list kubelet --showduplicates | sort -r

# 安装kubelet、kubeadm、kubectl 指定版本
yum install -y kubelet-1.23.0 kubeadm-1.23.0 kubectl-1.23.0

# 开机启动kubelet
systemctl enable kubelet && systemctl start kubelet

4. 部署Kubernetes Master

在192.168.31.61(Master)执行。

  • -apiserver-advertise-address写master节点IP
1
2
3
4
5
6
$ kubeadm init \
--apiserver-advertise-address=192.168.16.4 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.23.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16

由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址。

当我们出现下面的情况时,表示kubernetes的镜像已经安装成功

image-20201214120124624

使用kubectl工具:

1
2
3
4
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
$ kubectl get nodes

执行完成后,我们使用下面命令,查看我们正在运行的节点

kubectl get nodes

image-20201214120058150

能够看到,目前有一个master节点已经运行了,但是还处于未准备状态

下面我们还需要在Node节点执行其它的命令,将node1和node2加入到我们的master节点上

5. 加入Kubernetes Node

在192.168.1.12/13(Node)执行。

向集群添加新节点,执行在kubeadm init输出的kubeadm join命令:

1
2
$ kubeadm join 192.168.1.11:6443 --token esce21.q6hetwm8si29qxwn \
--discovery-token-ca-cert-hash sha256:00603a05805807501d7181c3d60b478788408cfe6cedefedb1f97569708be9c5

默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,操作如下:

1
kubeadm token create --print-join-command

当我们把两个节点都加入进来后,我们就可以去Master节点 执行下面命令查看情况

kubectl get node

image-20201214120204167

6. 部署CNI网络插件

1
2
# 下载网络插件配置
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

如果下载不了可以直接在任意目录下创建kube-flannel.yml文件

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp.flannel.unprivileged
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
spec:
privileged: false
volumes:
- configMap
- secret
- emptyDir
- hostPath
allowedHostPaths:
- pathPrefix: "/etc/cni/net.d"
- pathPrefix: "/etc/kube-flannel"
- pathPrefix: "/run/flannel"
readOnlyRootFilesystem: false
# Users and groups
runAsUser:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
fsGroup:
rule: RunAsAny
# Privilege Escalation
allowPrivilegeEscalation: false
defaultAllowPrivilegeEscalation: false
# Capabilities
allowedCapabilities: ['NET_ADMIN', 'NET_RAW']
defaultAddCapabilities: []
requiredDropCapabilities: []
# Host namespaces
hostPID: false
hostIPC: false
hostNetwork: true
hostPorts:
- min: 0
max: 65535
# SELinux
seLinux:
# SELinux is unused in CaaSP
rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
rules:
- apiGroups: ['extensions']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['psp.flannel.unprivileged']
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flannel
namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-system
labels:
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-system
labels:
tier: node
app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.mirrors.ustc.edu.cn/coreos/flannel/flannel:v0.14.0
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
image: quay.mirrors.ustc.edu.cn/coreos/flannel/flannel:v0.14.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: run
mountPath: /run/flannel
- name: flannel-cfg
mountPath: /etc/kube-flannel/
volumes:
- name: run
hostPath:
path: /run/flannel
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg

默认镜像地址无法访问,sed命令修改为docker hub镜像仓库。

1
2
3
4
5
6
7
8
9
10
# 修改文件中quay.io仓库为quay-mirror.qiniu.com 或者quay.mirrors.ustc.edu.cn 随便一个

sed -i 's#quay.io/coreos/flannel#quay.mirrors.ustc.edu.cn/coreos/flannel#' kube-flannel.yml
sed -i 's#quay.io/coreos/flannel#quay-mirror.qiniu.com/coreos/flannel#' kube-flannel.yml

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-amd64-2pc95 1/1 Running 0 72s

运行后的结果

image-20201214120243333

运行完成后,我们查看状态可以发现,已经变成了Ready状态了

image-20201214120258685

如果上述操作完成后,还存在某个节点处于NotReady状态,可以在Master将该节点删除

1
2
3
4
5
6
7
# master节点将该节点删除
kubectl delete node k8snode1

# 然后到k8snode1节点进行重置
kubeadm reset
# 重置完后在加入
kubeadm join 192.168.177.130:6443 --token 8j6ui9.gyr4i156u30y80xf --discovery-token-ca-cert-hash sha256:eda1380256a62d8733f4bddf926f148e57cf9d1a3a58fb45dd6e80768af5a500
1
2
3
4
5
6
7
8
9
10
# 看出pod状态都是running
kubectl get pod --all-namespaces


#查看集群状态都是Healthy ok
kubectl get cs
如果出现unhealthy,分别修改下面两个文件,注释 - --port=0,然后重启kubelet
vim /etc/kubernetes/manifests/kube-controller-manager.yaml
vim /etc/kubernetes/manifests/kube-scheduler.yaml
systemctl restart kubelet.service

7. 测试kubernetes集群

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

1
2
3
4
5
6
$ kubectl create deployment nginx --image=nginx
# 暴露端口
$ kubectl expose deployment nginx --port=80 --type=NodePort

# 查看一下对外的端口
$ kubectl get pod,svc

能够看到,我们已经成功暴露了 80端口 到 30529上

image-20201214120440677

访问地址:http://NodeIP:Port

拓展

journalctl -f -u kubelet.service

systemctl status kubelet -l

image-20220925221645090

1
2
3
4
5
6
sudo mkdir -p /opt/cni/bin
cd /opt/cni/bin
然后接下来去下载相应的压缩包
https://github.com/containernetworking/plugins/releases/tag/v0.8.6
下载一个cni-plugins-linux-amd64-v0.8.6.tgz
然后将其解压在/opt/cni/bin下就可以了。

允许Mater上调度

1
2
3
4
5
6
7
8
9
10
# 查看node
kubectl get nodes

# 查看污点
kubectl describe node k8s-master |grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule

# 删除污点
kubectl taint nodes --all node-role.kubernetes.io/master-
kubectl taint nodes --all node.kubernetes.io/not-ready-

卸载k8s集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
一、清空K8S集群设置
#在卸载K8s组件前,先执行kubeadm reset命令,清空K8s集群设置
kubeadm reset

二、卸载管理组件
#把之前通过yum安装的管理组件卸载
yum erase -y kubelet kubectl kubeadm kubernetes-cni

三、删除基础组件镜像
#基础组件通过Docker镜像部署,因此只需要强制删除对应镜像即可卸载
docker rmi -f k8s.gcr.io/kube-apiserver:v1.20.1

docker rmi -f k8s.gcr.io/kube-controller-manager:v1.20.1

docker rmi -f k8s.gcr.io/kube-scheduler:v1.20.1m

docker rmi -f k8s.gcr.io/kube-proxy:v1.20.1

docker rmi -f k8s.gcr.io/pause:3.2

docker rmi -f k8s.gcr.io/etcd:3.4.13

docker rmi -f k8s.gcr.io/coredns:1.8.1