如何在Hyper-V上的Ubuntu VM上安装kubernetes

借着微服务这阵风,K8S突然之间就火起来。阿里,微软,AWS,Google等等大厂都在大力支持k8s。学习k8s的最好方法就是自己动手练习。由于手头上没有那么多physical machine, 所以在Windows 10上的hyper-v搭建了3台ubuntu,用来组建k8s的cluster. 这篇文章记录整个搭建的过程,方便查阅。

学习k8s的过程中难免要自己动手做练习,有一套k8s cluster是必须的。我最开始使用的微软的AKS,但是这玩意太贵了。为了省钱,需要自己搭动手一套环境。

配置

HOST的系统配置为:

  1. Surface Book (16GB)
  2. Windows 10 (1909)
  3. Hyper-V

Guest 的配置:

  1. 3台Ubuntu的VM,分配内存为2GB,50GB硬盘空间,足足的。
  2. Ubuntu Server 18.04.3 LTS

Ubuntu的VM必须要符合kubeadm的最小配置要求

启用Hyper-V 并且安装ubuntu

Windows 10上的Hyper-V默认是不安装的。Ubuntu的版本方面,我选用了Ubuntu Server 18.04.3 LTS。可以跟着这篇文章启用hyper-V并且安装ubuntu完成ubuntu的安装。我的cluster环境是想配置3台ubuntu。

安装 Docker

完成Ubuntu的安装之后需要安装docker. K8S在运行Pods的时候需要一个container runtime. K8S可以选用多个container runtime:

  • Docker
  • CRI-O
  • Containerd
  • Other CRI runtimes: frakti

这里我使用的是Docker. 安装的步骤如下:

1
2
3
4
5
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable edge"
sudo apt update
sudo apt install docker-ce

如果需要给当前用户允许docker的权限,需要执行下面的命令:

1
sudo usermod -aG docker $USER

验证一下docker的版本:

1
sudo docker version

img

启用docker utility:

1
sudo systemctl enable docker

img

检测docker是否能够正常运作:

1
sudo docker run hello-world

img

上面的操作在3台Ubuntu上分别完成。

安装 kubeadm, kubectl 和 kubelete

下一步就是要安装k8s最常用的工具kubeadm, kubectl和kubelete.

  • kubeadm: the command to bootstrap the cluster.
  • kubelet: the component that runs on all of the machines in your cluster and does things like starting pods and containers.
  • kubectl: the command line util to talk to your cluster.

为了省事,先切换到root账号。

1
sudo -s

然后执行下面的命令:

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 http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

img

k8s无法在swap启用的状态下工作,否则会遇到问题。要在3台VM上都关闭swap.

1
swapoff -a

修改host name

为了区别master和worker node,可以先修改host name.

在master上配置host name:

1
sudo hostnamectl set-hostname master-node

在worker node上配置host name:

1
sudo hostnamectl set-hostname slave-node

这个名字是可选的。

Setup master node

接着下一步是配置master node.

1
kubeadm init --pod-network-cidr=10.244.0.0/16

–pod-network-cidr=10.244.0.0/16 这里是flannel必要的配置,因为在kube-flannel.yml中hardcode了。如果要修改这个ip:port的话,需要同时修改这个yml文件。

完成kubeadm init之后,最重要的是记录下下面的信息. 这个输出的命令行是运行在worker node上,可以让worker node加入到cluster时候使用的命令。

img

为了保证root用户也能使用kubectl:

1
export KUBECONFIG=/etc/kubernetes/admin.conf

按照Flannel的要求执行下面的命令:

1
2
sysctl net.bridge.bridge-nf-call-iptables=1
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

启用Flannel的pods:

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

img

检测pods的运行状态。目前为止master配置完成了。

1
kubectl get pods --all-namespaces

img

如果希望运行master node运行worker containers,可以执行下面的命令。不过这样会降低master node的安全性。

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

最后一步是为非root用户配置k8s admin权限。首先是退出root账号

1
exit

然后切换到希望成为k8s admin账号的用户,执行下面的命令:

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

到此为止,k8s的master node基本配置完成了。

Setup worker node

worker node同样要安装docker, kubeadm, kubectl, kubelet等。在上面的步骤中已经提到了。另外也要确保swap是关闭的。如果忘记关闭swap就会遇到错误。确保执行下面的命令:

1
swapoff -a

执行下面的命令加入到cluster中。

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

这里的token, 和master-ip等等输入项,都是在安装master node的执行kubeadm init --pod-network-cidr=10.244.0.0/16时候生成结果。

img

回到master node执行下面的命令可以检测是否加入成功:

1
kubectl get nodes

img

Recovering

如果中间步骤发生错误,需要重置可以执行下面的命令。这个命令在master node或者worker node都可以分别执行。

1
kubeadm reset

后记

在一次重新发布k8s cluster的过程中遇到了问题。当完成好master node的配置之后,运行kubectl get pods --all-namespaces遇到了coredns pods一直处于pending状态的问题。

1
2
3
4
5
6
7
8
9
10
11
root@k8smaster:/home/sonic# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6955765f44-4snpq 0/1 **Pending** 0 10m
kube-system coredns-6955765f44-wjmkv 0/1 **Pending** 0 10m
kube-system etcd-k8smaster 1/1 Running 0 9m59s
kube-system kube-apiserver-k8smaster 1/1 Running 0 9m59s
kube-system kube-controller-manager-k8smaster 1/1 Running 0 9m59s
kube-system kube-proxy-82mrd 0/1 ContainerCreating 0 52s
kube-system kube-proxy-dnwpk 1/1 Running 0 67s
kube-system kube-proxy-v9vq8 1/1 Running 0 10m
kube-system kube-scheduler-k8smaster 1/1 Running 0 9m59s

为了检测pods的状态,运行命令kubectl --namespace=kube-system describ pod coredns-6955765f44-wjmkv

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
root@k8smaster:/home/sonic# kubectl --namespace=kube-system describe pods coredns-6955765f44-wjmkv
Name: coredns-6955765f44-wjmkv
Namespace: kube-system
Priority: 2000000000
Priority Class Name: system-cluster-critical
Node: <none>
Labels: k8s-app=kube-dns
pod-template-hash=6955765f44
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Controlled By: ReplicaSet/coredns-6955765f44
Containers:
coredns:
Image: k8s.gcr.io/coredns:1.6.5
Ports: 53/UDP, 53/TCP, 9153/TCP
Host Ports: 0/UDP, 0/TCP, 0/TCP
Args:
-conf
/etc/coredns/Corefile
Limits:
memory: 170Mi
Requests:
cpu: 100m
memory: 70Mi
Liveness: http-get http://:8080/health delay=60s timeout=5s period=10s #success=1 #failure=5
Readiness: http-get http://:8181/ready delay=0s timeout=1s period=10s #success=1 #failure=3
Environment: <none>
Mounts:
/etc/coredns from config-volume (ro)
/var/run/secrets/kubernetes.io/serviceaccount from coredns-token-9fftj (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
config-volume:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: coredns
Optional: false
coredns-token-9fftj:
Type: Secret (a volume populated by a Secret)
SecretName: coredns-token-9fftj
Optional: false
QoS Class: Burstable
Node-Selectors: beta.kubernetes.io/os=linux
Tolerations: CriticalAddonsOnly
node-role.kubernetes.io/master:NoSchedule
node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 10m (x49 over 15m) default-scheduler 0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
Warning FailedScheduling 43s (x7 over 6m42s) default-scheduler 0/3 nodes are available: 3 node(s) had taints that the pod didn't tolerate.

做了一些research之后发现这个问题跟network方面的配置有关系,执行下面两条命令之后问题得到了解决:

1
2
sudo sysctl net.bridge.bridge-nf-call-iptables=1
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

参考资料

kubernetes Getting started
installing Kubernetes in a HyperV VM
Install and Deploy Kubernetes on Ubuntu 18.04 LTS
Understanding kubeadm init command for flannel
Running a Tight Ship: Deploying Kubernetes to Run Windows Containers