Kubernetes实践-部署


最近沉迷在 Kubernetes部署中不能自拔,作为初学者,基本上把可能踩的坑都踩了一遍,先分享一下怎么部署 Kubernetes 集群
首先,我们要知道 Kubernetes 是什么:

Kubernetes简称为k8s,它是 Google 开源的容器集群管理系统。在 Docker 技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。

K8s 是一个完备的分布式系统支撑平台,具有完备的集群管理能力,多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、內建负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制以及多粒度的资源配额管理能力。同时 K8s 提供完善的管理工具,涵盖了包括开发、部署测试、运维监控在内的各个环节。

安装

这个教程是对三台机器进行 k8s 部署,系统是Ubuntu 16.04.4 LTS。其中一台是 master ,其他两台是 worker。

安装 Docker

添加使用 HTTPS 传输的软件包以及 CA 证书

1
2
3
4
5
6
$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common

添加软件源的 GPG 密钥

1
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

向 source.list 中添加 Docker 软件源

1
2
3
4
5
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
$ sudo apt-get update

安装指定版本

1
2
$ apt-cache madison docker-ce
$ sudo apt-get install docker-ce=<VERSION>

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装:

1
2
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
安装 kubeadm, kubelet 和 kubectl

官方源

1
2
3
4
5
6
7
8
apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

因为某些你懂的原因,要更换阿里源,并安装kubelet kubeadm kubectl:

1
2
3
4
5
6
7
apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
1
2
关闭swap
$ sudo swapoff -a
使用kubeadm创建一个集群

使用 kubeadm 创建 k8s 集群其实还蛮简单,最大的困难是那堵墙,当我费了一整天把那堵墙问题解决后,发现 1.13.0 版本居然提供了中国特供的一个功能,所以把两种方法都写出来,供大家参考。

1.13.0 版本之前

查看kubeadm 会用到哪几个镜像:

1
$ kubeadm config images list

把得到的

1
2
3
4
5
6
7
k8s.gcr.io/kube-apiserver:v1.13.0
k8s.gcr.io/kube-controller-manager:v1.13.0
k8s.gcr.io/kube-scheduler:v1.13.0
k8s.gcr.io/kube-proxy:v1.13.0
k8s.gcr.io/pause:3.1
k8s.gcr.io/etcd:3.2.24
k8s.gcr.io/coredns:1.2.6

写个批量脚本获取替换成阿里云镜像地址拉取images并打回标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
images=(
kube-apiserver:v1.13.0
kube-controller-manager:v1.13.0
kube-scheduler:v1.13.0
kube-proxy:v1.13.0
pause:3.1
etcd:3.2.24
coredns:1.2.6
)
//pull镜像重新标记tag
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done

拉取完后
kubeadm init
就可以完成 Kubernetes Master 的部署了

1.13.0版本之后

Kubenetes默认Registries地址是k8s.gcr.io,很明显,在国内并不能访问gcr.io,因此在kubeadm v1.13之前的版本,安装起来非常麻烦,但是在1.13版本中终于解决了国内的痛点,其增加了一个–image-repository参数,默认值是k8s.gcr.io,我们将其指定为国内镜像地址:registry.aliyuncs.com/google_containers,其它的就可以完全按照官方文档来愉快的玩耍了。

1
2
3
4
5
$ kubeadm init \
--image-repository registry.aliyuncs.com/google_containers \
--pod-network-cidr=192.168.0.0/16 \
--ignore-preflight-errors=cri \
--kubernetes-version=1.13.1

kubeadm 会生成一行指令:

1
kubeadm join 10.168.0.2:6443 --token 00bwbx.uvnaa2ewjflwu1ry --discovery-token-ca-cert-hash sha256:00eb62a2a6020f94132e3fe1ab721349bbcd3e9b94da9654cfe15f2985ebd711

并提示如下命令执行确保授权配置

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 命令来查看当前唯一一个节点的状态了

1
2
3
4
$ kubectl get nodes

NAME STATUS ROLES AGE VERSION
iz94t4csjq4z NotReady master 82m v1.13.0

其中STATUS 是NotReady
我们通过kubectl describe 来查看这个节点(Node)对象的详细信息、状态和事件(Event)信息

1
2
3
4
5
6
7
8
9
kubectl describe node {NAME}
//$ kubectl describe node iz94t4csjq4z

...
Conditions:
...

Ready False ... KubeletNotReady runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

通过 kubectl describe 指令的输出,我们可以看到 NodeNotReady 的原因在于,我们尚未部署任何网络插件。
后面我们将专门讲关于部署插件。

另外,我们还可以通过 kubectl 检查这个节点上各个系统 Pod 的状态,其中,kube-system 是 Kubernetes
项目预留的系统 Pod 的工作空间(Namepsace,注意它并不是 Linux Namespace,它只是 Kubernetes 划分
不同工作空间的单位):

1
2
3
4
5
6
7
8
9
10
11
$ kubectl get pods -n kube-system

NAME READY STATUS RESTARTS AGE
coredns-78fcdf6894-j9s52 0/1 Pending 0 1h
coredns-78fcdf6894-jm4wf 0/1 Pending 0 1h
etcd-master 1/1 Running 0 2s
kube-apiserver-master 1/1 Running 0 1s
kube-controller-manager-master 0/1 Pending 0 1s
kube-proxy-xbd47 1/1 NodeLost 0 1h
kube-scheduler-master 1/1 Running 0 1s

可以看到,CoreDNS、kube-controller-manager 等依赖于网络的 Pod 都处于 Pending 状态,即调度失败。这当然是符合预期的:因为这个 Master 节点的网络尚未就绪。

命令

获取端部节点

1
2
3
4
$ kubectl get nodes

NAME STATUS ROLES AGE VERSION
iz94t4csjq4z Ready master 3h57m v1.13.0

查看node详细

1
$ kubectl describe node iz94t4csjq4z

查看全部pod

1
$ kubectl get pods --all-namespaces

通过namespaces获取pod

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl get pods -n kube-system

NAME READY STATUS RESTARTS AGE
coredns-86c58d9df4-qqddh 1/1 Running 0 3h58m
coredns-86c58d9df4-xxccw 1/1 Running 0 3h58m
etcd-iz94t4csjq4z 1/1 Running 0 3h57m
kube-apiserver-iz94t4csjq4z 1/1 Running 0 3h57m
kube-controller-manager-iz94t4csjq4z 1/1 Running 1 3h57m
kube-proxy-k4zkp 1/1 Running 0 3h58m
kube-scheduler-iz94t4csjq4z 1/1 Running 1 3h57m
kubernetes-dashboard-79ff88449c-dxbsb 1/1 Running 0 3h27m
weave-net-c7dvl 2/2 Running 0 3h49m

查看pod

1
$ kubectl describe pod -n kube-system

查看pod具体详情

1
$ kubectl describe pod kubernetes-dashboard-767dc7d4d-mg5gw -n kube-system
1
2
$ kubectl edit cm coredns -n kube-system
$ kubectl -n kube-system edit configmap coredns

单节点配置( Master 隔离)

默认情况下 Master 节点是不允许运行用户 Pod 的,而 Kubernetes 做到这一点,依靠的是 是 Kubernetes 的 Taint/Toleration 机制。一旦某个节点被加上了一个 Taint,即被“打上了污点”那么所有 Pod 就都不能在这个节点上运行,因为 Kubernetes 的 Pod 都有“洁癖”。
如果你通过 kubectl describe 检查一下 Master 节点的 Taint 字段,就会有所发现了:

1
2
3
4
5
6
$ kubectl describe node master

Name: master
Roles: master
Taints: node-role.kubernetes.io/master:NoSchedule

可以看到,Master 节点默认被加上了node-role.kubernetes.io/master:NoSchedule这样一个“污点”,其中“键”是node-role.kubernetes.io/master,而没有提供“值”。

如果你就是想要一个单节点的 Kubernetes,删除个 Taint 才是正确的选择:

1
$ kubectl taint nodes --all node-role.kubernetes.io/master-

如上所示,我们在“node-role.io/master”这个键后面加上了一个短横线“-”,这个格式就意味着移除所有以“node-role.kubernetes.io/master”为键的 Taint。

这个步骤的配置最终使Master节点能允许运行用户pod,也是确保下面插件部署能正确运行。

到了这一步,一个基本完整的 Kubernetes 集群就完毕了。

部署插件

部署 Dashboard 可视化插件

kubernetes-dashboard先从国内镜像拉下来:

1
2
3
$ docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.10.0
$ docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.10.0 k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.0
$ docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.10.0

打上kis.gcr.io的tag,这样执行Dashboard拉取的时候就直接本地拿pull下来的直接安装。

1
2
3
4
安装
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml
删除
$ kubectl delete -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml

安装后

1
$ kubectl describe pod kubernetes-dashboard -n kube-system 

可查看Dashboard状态

部署网络插件

部署网络插件非常简单
因为这里的镜像来源不是kis.gcr.io,所以我们就不先拉取镜像下来.

1
2
3
4
安装
$ kubectl apply -f https://git.io/weave-kube-1.6
删除
$ kubectl delete -f https://git.io/weave-kube-1.6

部署完成后,我们可以通过 kubectl get 重新检查Pod的状态:

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl get pods -n kube-system

NAME READY STATUS RESTARTS AGE
coredns-78fcdf6894-j9s52 1/1 Running 0 1d
coredns-78fcdf6894-jm4wf 1/1 Running 0 1d
etcd-master 1/1 Running 0 9s
kube-apiserver-master 1/1 Running 0 9s
kube-controller-manager-master 1/1 Running 0 9s
kube-proxy-xbd47 1/1 Running 0 1d
kube-scheduler-master 1/1 Running 0 9s
weave-net-cmk27 2/2 Running 0 19s

部署容器存储插件
1
2
3
4
5
6
7
8
9
10
11
12
安装
$ kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/operator.yaml
$ kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/cluster.yaml


删除
$ kubectl delete -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/operator.yaml
$ kubectl delete -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/cluster.yaml

查看安装情况
$ kubectl get pods -n rook-ceph-system
$ kubectl get pods -n rook-ceph

加入工作节点

SSH到其他机器上,成为 root 用户(如:sudo su -),安装 kubeadm, kubelet and kubectl。

然后复制上面的运行kubeadm init命令时最后一句输出,并运行它的:

1
$ kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>

这时候回到master 节点服务器,运行下面命令查看节点状态:

1
$ kubectl get nodes

NAME STATUS ROLES AGE VERSION
izuf6e4bl8eavupeu7q9a0z Ready 98s v1.13.0
izuf6e4bl8eavupeu7q9a1z Ready master 75m v1.13.0
如果我们忘记了Master节点的加入token,可以使用如下命令来查看:

1
$ kubeadm token list

默认情况下,token的有效期是24小时,如果我们的token已经过期的话,可以使用以下命令重新生成:

1
$ kubeadm token create

如果我们也没有–discovery-token-ca-cert-hash的值,可以使用以下命令生成:

1
$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

至此一个简单的 k8s 集群部署就差不多了。

常见问题

Q1:

1
2
2018/11/05 04:04:18 [INFO] plugin/reload: Running configuration MD5 = f65c4821c8a9b7b5eb30fa4fbc167769
2018/11/05 04:04:24 [FATAL] plugin/loop: Seen "HINFO IN 6900627972087569316.7905576541070882081." more than twice, loop detected
1
2
3
4
5
6
7
8
9
配置:--resolv-conf
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
https://stackoverflow.com/questions/53075796/coredns-pods-have-crashloopbackoff-or-error-state/53414041#53414041
https://stackoverflow.com/questions/52645473/coredns-fails-to-run-in-kubernetes-cluster
https://www.jianshu.com/p/e4dcd56fad38

systemctl daemon-reload && systemctl restart kubelet


Q2:

1
Unable to connect to the server: dial tcp 192.168.1.169:6443: connect: network is unreachable

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

sudo swapoff -a

Q3:

1
2
3
4
5
 	[ERROR DirAvailable--etc-kubernetes-manifests]: /etc/kubernetes/manifests is not empty
[ERROR FileAvailable--etc-kubernetes-kubelet.conf]: /etc/kubernetes/kubelet.conf already exists
[ERROR Port-10250]: Port 10250 is in use
[ERROR FileAvailable--etc-kubernetes-pki-ca.crt]: /etc/kubernetes/pki/ca.crt already exists