0%

Kubernetes入门 -- 一使用kubeadm部署Kubernetes集群v1.14.1

上一次通过kubeadm来配置Kubernetes的环境使用的还是 v1.13 的版本,最近看到Kubernetes的稳定版本已经更新到了 v1.14.1 ,所以决定重新安装一次,并把配置过程和遇到的问题同时整理一下。

kubeadm是Kubernetes官方提供的用于快速安装Kubernetes集群的工具,伴随Kubernetes每个版本的发布都会同步更新,kubeadm会对集群配置方面的一些实践做调整,通过实验kubeadm可以学习到Kubernetes官方在集群配置上一些新的最佳实践。

系统信息

  • master ip : 192.168.5.28
  • node1 ip : 192.168.5.29
  • 配置均为:2核2G

系统环境配置

注意:在 Master 和 Node 节点均操作

切换到 root 权限
1
$ su - root
更改hostname
master
1
2
3
# hostname
# hostnamectl set-hostname master
# hostname
node1
1
2
3
# hostname
# hostnamectl set-hostname node1
# hostname
修改 hosts
master

编辑 /etc/hosts 文件,在底部新增下面两行,然后重启系统:

1
2
3
4
5
6
# vim /etc/hosts

192.168.5.28 master
192.168.5.29 node1

reboot
禁用防火墙
1
2
# systemctl disable firewalld && systemctl stop firewalld
# systemctl status firewalld
禁用SELinux
1
2
3
4
5
# setenforce 0

# vim /etc/selinux/config
#SELINUX=enforcing
SELINUX=disabled
禁用swap

查看当前swap状态:

1
2
3
4
# free -m
total used free shared buff/cache available
Mem: 1466 142 1063 8 260 1151
Swap: 3071 0 3071

禁用swap:

1
# swapoff -a

编辑 /etc/fstab 文件,注释掉带有 swap 的那一行:

1
2
3
# vim /etc/fstab

#/dev/mapper/centos-swap swap swap defaults 0 0

查看:

1
2
3
4
# free -m
total used free shared buff/cache available
Mem: 1466 142 1063 8 260 1152
Swap: 0 0 0

修改iptables配置

创建 /etc/sysctl.d/k8s.conf 文件,加入如下内容:

1
2
3
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1

执行命令使修改生效:

1
2
# modprobe br_netfilter
# sysctl -p /etc/sysctl.d/k8s.conf
kube-proxy开启ipvs的前置条件

由于ipvs已经加入到了内核的主干,所以为kube-proxy开启ipvs的前提需要加载以下的内核模块:

1
2
3
4
5
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack_ipv4

执行以下脚本来配置:

1
2
3
4
5
6
7
8
9
10
11
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF


chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4

保证 ipset 已安装,同时要管理ipvs,需要安装ipvsadm:

1
# yum install ipset ipvsadm

安装docker

省略。

修改docker cgroup driver为systemd

根据文档CRI installation中的内容,对于使用systemd作为init system的Linux的发行版,使用systemd作为docker的cgroup driver可以确保服务器节点在资源紧张的情况更加稳定,因此这里修改各个节点上docker的cgroup driver为systemd。

查看docer的cgroup:

1
2
# docker info |grep -i cgroup
Cgroup Driver: cgroupfs

创建或修改 /etc/docker/daemon.json

1
2
3
{
"exec-opts":["native.cgroupdriver=systemd"]
}

重启docker:

1
# systemctl restart docker

再次查看cgroup:

1
2
# docker info |grep -i cgroup
Cgroup Driver: systemd

使用kubeadm部署Kubernetes

安装kubeadm和kubelet
需要在各个节点分别配置地址源
1
2
3
4
5
6
7
8
9
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

更新缓存:

1
# yum makecache fast
Master节点安装

在 Master 节点上安装 kubelet kubeadm kubectl:

1
2
3
4
5
6
# yum install -y kubelet kubeadm kubectl

Installing:
kubeadm 1.14.1-0
kubectl 1.14.1-0
kubelet 1.14.1-0
Node节点安装

在 Node1 节点上安装 kubelet kubeadm:

1
# yum install -y kubelet kubeadm

kubectl 在 node 节点上是非必需的。

设置 kubelet 开机启动
1
# systemctl enable kubelet && systemctl start kubelet

此时如果查看 kubelet 的状态,会发现 处于 loaded 状态,错误码是 255:

1
2
3
4
5
6
7
8
9
# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Thu 2019-05-16 23:51:36 CST; 808ms ago
Docs: https://kubernetes.io/docs/
Process: 4317 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=255)
Main PID: 4317 (code=exited, status=255)
提前获取镜像

可以通过命令 kubeadm config images list 查看当前可用的最新镜像版本信息。

Kubernetes启动时默认会从 k8s.gcr.io 去拉取所需的镜像,但该地址在国内无法访问,需要更换为国内可用的地址。

Azure 中国 提供了 gcr.iok8s.gcr.io 容器仓库的镜像代理服务。

镜像地址:docker pull gcr.azk8s.cn/google_containers/<imagename>:<version>

默认情况下无法访问获取最新的版本,会根据使用的 kubeadm 的版本给出相应版本:

1
2
3
4
5
6
7
8
9
10
# kubeadm config images list
I0517 00:03:01.427109 4857 version.go:96] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.txt": Get https://dl.k8s.io/release/stable-1.txt: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
I0517 00:03:01.427382 4857 version.go:97] falling back to the local client version: v1.14.1
k8s.gcr.io/kube-apiserver:v1.14.1
k8s.gcr.io/kube-controller-manager:v1.14.1
k8s.gcr.io/kube-scheduler:v1.14.1
k8s.gcr.io/kube-proxy:v1.14.1
k8s.gcr.io/pause:3.1
k8s.gcr.io/etcd:3.3.10
k8s.gcr.io/coredns:1.3.1

也可以直接指定版本:

1
kubeadm config images list --kubernetes-version=v1.14.1

下载镜像

在 Master 和 Node 节点均执行

创建一个名为 kubeadm_pull.sh 脚本文件:

1
2
3
4
5
6
7
8
# kubeadm_pull.sh

for i in `kubeadm config images list`; do
imageName=${i#k8s.gcr.io/}
docker pull gcr.azk8s.cn/google_containers/$imageName
docker tag gcr.azk8s.cn/google_containers/$imageName k8s.gcr.io/$imageName
docker rmi gcr.azk8s.cn/google_containers/$imageName
done;

在网上也找到一个阿里云的地址源 registry.aliyuncs.com/google_containers,替换脚本中的 gcr.azk8s.cn/google_containers 部分即可。

另外,如果想下载指定版本,可以将第一行改为 kubeadm config images list --kubernetes-version=v1.14.1 即加上版本的限制:

1
--kubernetes-version=v1.14.1

然后执行,等待下载:

1
2
3
4
# vim ./kubeadm_pull.sh

# chmod +x ./kubeadm_pull.sh
# ./kubeadm_pull.sh

使用kubeadm init初始化集群

kubeadm init

在 Master 节点执行

1
# kubeadm init --kubernetes-version=v1.14.1 --apiserver-advertise-address=192.168.5.28 --pod-network-cidr=10.244.0.0/16

其中,–apiserver-advertise-address
这是 API server 用来告知集群中其它成员的地址,这也是在 init 流程的时候用来构建 kubeadm join 命令行的地址。

更多的配置参数说明可见:kubeadm 设置工具参考指南 | Kubernetes

当看到输出信息中的 Your Kubernetes control-plane has initialized successfully! 说明Kubernetes初始化成功了。

后面的几段输出比较重要。

要管理集群,我们需要执行如下命令:

1
2
3
4
5
To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

安装支持的Pod网站组件:

1
2
3
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

要将其他Node节点加入到当前Master节点的集群中,需要执行如下命令:

1
2
3
4
Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.5.28:6443 --token runell.pdp1y28g1dsayy1o \
--discovery-token-ca-cert-hash sha256:349ee7b8a8f8a255065ebdbd1de2a98127f45fd190716af6a7a780e025f8cdfd

上面的三步,也就是我们初始化集群要做的。

授权管理集群

如果需要使用Kubernetes集群,则首先要执行上面的授权操作,否则你看到的就是下面这样:

1
2
# kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?

在 Master 节点上操作

因为我常用的是非root用户,所以这里我退出root用户权限来操作。当然,你也可以在其他的系统上来管理集群,只需要将 /etc/kubernetes/admin.conf 拷贝到 $HOME/.kube/config 目录中即可。

1
2
3
4
5
6
7
8
9
[root@master ~]# exit
logout
➜ ~ pwd
/home/tiger

➜ ~ mkdir -p $HOME/.kube
➜ ~ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[sudo] tiger 的密码:
➜ ~ sudo chown $(id -u):$(id -g) $HOME/.kube/config

我们可以通过 kubectl get nodes 查看节点的状态:

1
2
3
➜  ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 14m v1.14.1

master 节点 处于 NotReady 状态,还需要配置网络。

安装网络组件

Kubernetes系统上Pod网络的实现依赖于第三方插件进行,简单易用的实现是为CoreOS提供的flannel项目。

安装文档 Creating a single master cluster with kubeadm - Kubernetes 中的介绍,直接执行如下命令:

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

由于上面我是在 tiger 用户下设置了授权,所以这里安装 flannel 就需要在 tiger 用户下来操作(不需要sudo),执行结果:

1
2
3
4
5
6
7
8
9
10
➜  ~ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.extensions/kube-flannel-ds-amd64 created
daemonset.extensions/kube-flannel-ds-arm64 created
daemonset.extensions/kube-flannel-ds-arm created
daemonset.extensions/kube-flannel-ds-ppc64le created
daemonset.extensions/kube-flannel-ds-s390x created

之后,再次查看节点状态:

1
2
3
➜  ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 35m v1.14.1

现在是 Ready 状态了。

如果是用root权限操作,由于上面没有为root账户授权,会报如下错误:

1
2
unable to recognize "https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml": Get http://localhost:8080/api?timeout=32s: dial tcp [::1]:8080: connect: connection refused
unable to recognize "https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml": Get http://localhost:8080/api?timeout=32s: dial tcp [::1]:8080: connect: connection refused

检查 Flannel 的pod状态:

1
2
3
➜  ~ kubectl get pods -n kube-system -l app=flannel
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-amd64-2rzqc 1/1 Running 0 6m51s
验证Master节点上相关Pod是否正常

通过命令 kubectl get pods --all-namespaces 验证master节点上kubernetes集群的相关Pod是否都正常创建并运行:

1
2
3
4
5
6
7
8
9
10
➜  ~ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-fb8b8dccf-cm28l 1/1 Running 0 40m
kube-system coredns-fb8b8dccf-lqh8n 1/1 Running 0 40m
kube-system etcd-master 1/1 Running 0 39m
kube-system kube-apiserver-master 1/1 Running 0 39m
kube-system kube-controller-manager-master 1/1 Running 0 39m
kube-system kube-flannel-ds-amd64-2rzqc 1/1 Running 0 8m10s
kube-system kube-proxy-mb87m 1/1 Running 0 40m
kube-system kube-scheduler-master 1/1 Running 0 40m

如果发现有状态错误的Pod,可以通过命令 kubectl --namespace=kube-system describe pod <pod_name> 来查看具体错误原因。

查看集群中各个组件的状态:

1
2
3
4
5
➜  ~ kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true"}
设置Master节点调度Pod

Kubeadm 在 master节点上也安装了 kubelet,出于安全考虑Pod不会被调度到Master Node上,也就是说Master Node不参与工作负载。这是因为master节点被打上了 node-role.kubernetes.io/master:NoSchedule 的标记:

查看Master节点的 Taint kubectl describe node <host_name> | grep Taint:

1
2
➜  ~ kubectl describe node master | grep Taint
Taints: node-role.kubernetes.io/master:NoSchedule

如果希望在 Master 节点上也可以运行 Pod,可以执行如下命令(删除 Node 的 Label “node-role.kubernetes.io/master”,让Master节点成为Node节点):

1
2
3
4
# 当前只有一个master节点,可以使用 --all 来执行
kubectl taint nodes --all node-role.kubernetes.io/master-
# 或者指定节点名称
kubectl taint nodes <host_name> node-role.kubernetes.io/master-

结果:

1
2
➜  ~ kubectl taint nodes --all node-role.kubernetes.io/master-
node/master untainted

另外,如果要恢复禁止master部署Pod,可以执行:

1
kubectl taint nodes <host_name> node-role.kubernetes.io/master:NoSchedule

向Kubernetes集群中添加Node节点

注意:在 Node 节点上操作

按照上面的第三步操作,直接在 Node 节点上执行,这里需要注意的是必须以root权限来执行:

1
2
kubeadm join 192.168.5.28:6443 --token runell.pdp1y28g1dsayy1o \
--discovery-token-ca-cert-hash sha256:349ee7b8a8f8a255065ebdbd1de2a98127f45fd190716af6a7a780e025f8cdfd

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@node1 ~]# kubeadm join 192.168.5.28:6443 --token runell.pdp1y28g1dsayy1o \
> --discovery-token-ca-cert-hash sha256:349ee7b8a8f8a255065ebdbd1de2a98127f45fd190716af6a7a780e025f8cdfd
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.14" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Activating the kubelet service
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
查看集群节点状态

回到主节点master上,查看集群节点状态:

1
2
3
4
➜  ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 65m v1.14.1
node1 Ready <none> 77s v1.14.1

至此,node1 节点顺利添加到了集群中。


kube-proxy开启ipvs

注意:在 Master 节点下操作

通过命令 ipvsadm -L -n 查看当前ipvs状态:

1
2
3
4
➜  ~ sudo ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn

发现并没有使用ipvs。

修改 ConfigMap的kube-system/kube-proxy 中的 config.conf,执行命令:

1
➜  ~ kubectl edit cm kube-proxy -n kube-system

找到其中的如下部分:

1
2
3
4
5
...
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: ""
...

mode: "" 改为 mode: "ipvs"

之后重启各个节点上的kube-proxy Pod:

1
kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'

上面的命令是将原有 kube-proxy 的 Pod 删除,然后重新创建的。执行结果:

1
2
3
4
5
6
7
8
9
10
➜  ~ kubectl get pod -n kube-system | grep kube-proxy
kube-proxy-d78m2 1/1 Running 0 55m
kube-proxy-mb87m 1/1 Running 0 119m
➜ ~ kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
pod "kube-proxy-d78m2" deleted
pod "kube-proxy-mb87m" deleted
➜ ~ kubectl get pod -n kube-system | grep kube-proxy
kube-proxy-8x8f6 1/1 Running 0 10s
kube-proxy-k54d5 1/1 Running 0 3s
➜ ~

查看其中一个 kube-proxy Pod 的日志输出:

1
2
3
4
5
6
7
8
9
10
11
12
➜  ~ kubectl logs kube-proxy-k54d5 -n kube-system
I0517 02:04:00.609209 1 server_others.go:177] Using ipvs Proxier.
W0517 02:04:00.609514 1 proxier.go:381] IPVS scheduler not specified, use rr by default
I0517 02:04:00.609660 1 server.go:555] Version: v1.14.1
I0517 02:04:00.619582 1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 02:04:00.620296 1 config.go:202] Starting service config controller
I0517 02:04:00.620318 1 controller_utils.go:1027] Waiting for caches to sync for service config controller
I0517 02:04:00.620338 1 config.go:102] Starting endpoints config controller
I0517 02:04:00.621083 1 controller_utils.go:1027] Waiting for caches to sync for endpoints config controller
I0517 02:04:00.720469 1 controller_utils.go:1034] Caches are synced for service config controller
I0517 02:04:00.721541 1 controller_utils.go:1034] Caches are synced for endpoints config controller
➜ ~

日志中打印出了 Using ipvs Proxier ,说明ipvs模式已经开启。

再次通过 ipvsadm -L -n 命令查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜  ~ sudo ipvsadm -L -n
[sudo] password for tiger:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 192.168.5.28:6443 Masq 1 0 0
TCP 10.96.0.10:53 rr
-> 10.244.0.2:53 Masq 1 0 0
-> 10.244.0.3:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.244.0.2:9153 Masq 1 0 0
-> 10.244.0.3:9153 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 10.244.0.2:53 Masq 1 0 0
-> 10.244.0.3:53 Masq 1 0 0
➜ ~

也显示出了相应的配置信息。


至此,kubeadm配置Kubernetes集群的操作就完成了。


相关参考

如有疑问或需要技术讨论,请留言或发邮件到 service@itfanr.cc