赶在 2019 年快结束之际,写一篇博客作为本年度的收官之作吧。
前言
虽然现在各大云平台厂商都提供了一键搭建 kubenetes 的服务,但缺点是费用太贵了,如果仅仅把它作为自己没事折腾的小玩具非常不划算,另外虽然也可以用公司的账号,但并不想把自己的折腾的东西跟工作混为一谈。
所以决定自己在主机上手动搭建一个。
准备工作
一般 kubenetes 至少要三台 linux 主机组建成一个 cluster,因为手头没有三台 linux 物理主机,所以要用虚拟机代替。
kubenetes 各个虚拟机节点的规划如下:
主机名 | 主机 IP | OS | 集群角色 |
---|---|---|---|
192-168-56-10.master | 192.168.56.10 | Ubuntu 18.04 | master |
192-168-56-11.node | 192.168.56.11 | Ubuntu 18.04 | node1 |
192-168-56-12.node | 192.168.56.12 | Ubuntu 18.04 | node2 |
准备工作主要为下面几步:
- 物理主机内存 16G,操作系统为 Ubuntu 18.04
- 安装 Virtualbox 6.1
- 创建三台虚拟机,每台内存 4G
- 对三台虚拟机做基本配置
VirtualBox 虚拟机配置
默认只有一个 NAT 适配器,我们需要添加一个 Host-Only Adapter
。NAT 适配器是虚拟机用来访问互联网的,Host-Only 适配器是用来虚拟机之间通信的。上面表格所指的 主机 IP 也是这个 Host only IP。
vbox 上配置一个 host only adapter, 默认名字 vboxnet0
,网络地址 192.168.56.1/24
VirtualBox > File > Host Network Manager > Add (you will get vboxnet0)
接着每台虚拟机再加一个网卡,所以每台现在有两个网卡,一个 NAT 到互联网,一个用于本地 cluster 相互通信。
VM's Settings > System > check "Enable I/O APIC."
VM's Settings > Network > Adapter 2 > host-only vboxnet0
配置好网卡以后,host only 的网卡 enp0s8
需要设置静态地址,master 的示例如下:
test@master:~$ cat /etc/netplan/50-cloud-init.yaml
network:
ethernets:
enp0s3:
dhcp4: true
enp0s8:
addresses:
- 192.168.56.10/24
dhcp4: false
version: 2
修改好以后,
$ sudo netplan generate
$ sudo netplan apply
可以看到,虚拟机有两个 ip 地址,10 开头的用于外部通信,192 开头的用于相互通信,
之后 k8s 搭建过程中都是用的 192 地址,不会用到 10 开头的,这个地址是虚拟机从网络上下载各种软件时自动选择使用。
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.4 netmask 255.255.255.0 broadcast 10.0.2.255
inet6 fe80::a00:27ff:fee6:c5c7 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:e6:c5:c7 txqueuelen 1000 (Ethernet)
RX packets 514969 bytes 748728432 (748.7 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 294223 bytes 18448150 (18.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.56.10 netmask 255.255.255.0 broadcast 192.168.56.255
inet6 fe80::a00:27ff:fe76:4048 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:76:40:48 txqueuelen 1000 (Ethernet)
RX packets 213918 bytes 20708155 (20.7 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 220695 bytes 95399920 (95.3 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
虚拟机上安装 docker
这里的需要注意的是不要用 ubuntu 自带的 apt install, 也不要用 ubuntu 新推出的 snap install,两者都不对。
推荐的是从 docker 官方源安装,其实也很简单,把下面的所有命令运行一遍就 OK。
sudo apt update
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 bionic stable"
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker
关闭 swap 分区
没什么好说的,官方文档明确说了。
运行 swapoff -a
立即生效,但重启后失效。
修改 /etc/fstab
, 把 swap 相关的那一行注释掉,永久生效。
free -m
确认 swap 相关的都是 0, 说明已经关闭。
设置 hostname
有的资料说最好把虚拟机 hostname 改成 xxx.yy 的形式。
- 编辑/etc/hostname,将 hostname 修改为 192-168-56-10.master
- sysctl kernel.hostname=new-hostname
- 编辑/etc/hosts,追加内容 192-168-56-10.master
最后运行 hostname
确认修改生效。
每台虚拟机上的 hosts 文件都需要修改,以 master 为例,最后应该是这样
$ cat /etc/hosts
127.0.0.1 192-168-56-10.master
192.168.56.11 192-168-56-11.node
192.168.56.12 192-168-56-12.node
安装 Kube 组件
前面的准备工作完成了,到这里我们有 3 台虚拟机,相互都能通过 hostname ping 通,并且都安装了 docker。
现在来安装 kubernetes 相关的三个重要组件 kubelet, kubeadm, kubectl
也是把下面这些命令都运行一遍就 OK 了。
apt-get update && apt-get install -y apt-transport-https
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
systemctl enable kubelet
systemctl start kubelet
kubeadm 自动安装 k8s
官方提供了 kubeadm 这样一个优秀的工具帮助我们搭建 k8s,方便了不少,否则的话光是手动生成各种证书就要花很多时间了。
kubeadm init --apiserver-advertise-address=192.168.56.10 --pod-network-cidr=22.22.0.0/16
--apiserver-advertise-address
绑定 apiserver 到 master 节点的 Host-Only 适配器的地址,默认是绑到 NAT 的地址上,这样其他机器是永远也访问不到的。--pod-network-cidr
指定 pod 网络地址空间,使用 flannel 等网络 组件必须使用这个空间- 若执行kubeadm init出错或强制终止,则再需要执行该命令时,需要先执行kubeadm reset重置
init 命令运行成功的话,最后会输出下面这段
Your Kubernetes master has initialized successfully!
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
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/
kubeadm join 192.168.56.10:6443 --token vtu4u1.upnimfemwgk8zpou \
--discovery-token-ca-cert-hash sha256:dcfd3261d6e5c315c71c59984d17827c6008c2d563b1133f3e7cfd3214c5c49d
按照上面的提示,拷贝文件(也可以把 config 文件 copy 到所有节点上),在 node 节点上运行 join 命令。
上面的 join 命令可以使用 kubeadm token create --print-join-command
重新生成。
当我们改变了 master 节点,比如重新安装 k8s 后,node 节点无法加入到集群,这时在 node 节点上kubeadm reset
,然后 join 命令重新加入。
之后,能看到节点都加入了集群,并且状态为 ready。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
192-168-56-10.master Ready master 15h v1.17.0
192-168-56-11.node Ready <none> 15h v1.17.0
192-168-56-12.node Ready <none> 15h v1.17.0
安装 flannel 网络
按照参考资料中的安装方式,运行下面这个命令,发现 flannel pod 一直在 crash,而 coredns pod 停在 creatingContainer 状态。
kubectl create -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
所以上面的方法并不靠谱,一番搜索之后,下面这个命令似乎能正常工作。
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/k8s-manifests/kube-flannel-rbac.yml
kubectl apply -f kube-flannel-rbac.yml
但是是不是能正常工作要等到部署网络相关的 app 之后才知道,先这样吧。
完成
至此,kubenetes 集群的搭建就完成了,我们可以运行几个命令来获取集群的相关信息。
$ kubectl cluster-info
Kubernetes master is running at https://192.168.56.10:6443
KubeDNS is running at https://192.168.56.10:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
$ kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default redis-master-68b5d7cd85-n4hvc 1/1 Running 0 149m
kube-system coredns-6955765f44-p7mkd 1/1 Running 0 15h
kube-system coredns-6955765f44-ssf5m 1/1 Running 0 15h
kube-system etcd-192-168-56-10.master 1/1 Running 0 15h
kube-system kube-apiserver-192-168-56-10.master 1/1 Running 0 15h
kube-system kube-controller-manager-192-168-56-10.master 1/1 Running 0 15h
kube-system kube-flannel-ds-amd64-dh6tf 1/1 Running 0 3h35m
kube-system kube-flannel-ds-amd64-kzfvx 1/1 Running 0 3h35m
kube-system kube-flannel-ds-amd64-wxr42 1/1 Running 0 3h35m
kube-system kube-proxy-8hlxp 1/1 Running 0 15h
kube-system kube-proxy-b59t4 1/1 Running 0 15h
kube-system kube-proxy-lsv4v 1/1 Running 0 15h
kube-system kube-scheduler-192-168-56-10.master 1/1 Running 0 15h
kubernetes-dashboard dashboard-metrics-scraper-76585494d8-c7sdp 1/1 Running 0 3h8m
kubernetes-dashboard kubernetes-dashboard-5996555fd8-tvpbg 0/1 CrashLoopBackOff 39 3h8m
部署一个 Redis 服务
现在有一个 k8s 集群,那么来运行一个小的测试用例吧.
部署一个 Redis ,并在 master 节点上通过 redis client 连接到 redis。
deployment
$ cat redis-master-deployment.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: redis-master
labels:
app: redis
spec:
selector:
matchLabels:
app: redis
role: master
tier: backend
replicas: 1
template:
metadata:
labels:
app: redis
role: master
tier: backend
spec:
containers:
- name: master
image: k8s.gcr.io/redis
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379
service
$ cat redis-master-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
role: master
tier: backend
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
role: master
tier: backend
kubectl apply 之后,可以看到 default namespace 下,pod 已经在运行。
kubectl get pod
NAME READY STATUS RESTARTS AGE
redis-master-68b5d7cd85-n4hvc 1/1 Running 0 154m
然后通过 port forward 把 pod 的端口映射到 master 节点。
$ kubectl port-forward svc/redis-master 7000:6379
Forwarding from 127.0.0.1:7000 -> 6379
Forwarding from [::1]:7000 -> 6379
$ redis-cli -p 7000
127.0.0.1:7000> set hello world
OK
127.0.0.1:7000> get hello
"world"
参考资料
- https://github.com/c-rainstorm/blog/blob/master/devops/%E6%9C%AC%E6%9C%BA%E6%90%AD%E5%BB%BA%E4%B8%89%E8%8A%82%E7%82%B9k8s%E9%9B%86%E7%BE%A4.md
- https://gist.github.com/c-rainstorm/1bbd44b388acd35ca6eaf07d1fbd9bc7
- https://www.jianshu.com/p/e43f5e848da1
- https://www.qikqiak.com/post/use-kubeadm-install-kubernetes-1.15.3/
- https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/