操作系统:Raspbian GNU/Linux 9(Stretch Desktop)
内核:4.14.50-v7+
关闭ufw防火墙,树莓派系统没有ufw模块,无需设置。
$ sudo ufw disable
备注:
- ufw的底层是使用iptables进行数据过滤,建立在iptables之上,这可能会与 Docker 产生冲突。
- 为避免不必要的麻烦,这里把firewalld关掉。
树莓派系统默认不安装selinux,无需设置。假如安装了的话,按如下步骤禁用selinux
临时禁用(重启后失效)
$ sudo setenforce 0 #0代表permissive 1代表enforcing
永久禁用
$ sudo vi /etc/selinux/config
SELINUX=permissive
备注:
- kubelet目前对selinux的支持还不好,需要禁用掉。
- 不禁用selinux的话有时还会出现明明容器里是root身份运行,操作挂载进来的主机文件夹时没有权限的情况,这时候要么配置selinux的权限,要么就禁掉selinux
- 另外,当docker的
storage-driver
使用overlay2的时候,低版本内核的selinux不支持overlay2文件驱动,docker启动时设置为--selinux-enabled
会失败报错:“Error starting daemon: SELinux is not supported with the overlay2 graph driver on this kernel”,需设置--selinux-enabled=false
1.修改/etc/sysctl.conf,开启ipv4转发:
$ sudo vim /etc/sysctl.conf
net.ipv4.ip_forward = 1 #开启ipv4转发,允许内置路由
2.写入后执行如下命令生效:
$ sudo sysctl -p
备注:
- 什么是ipv4转发:出于安全考虑,Linux系统默认是禁止数据包转发的。转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的ip地址将数据包发往本机另一块网卡,该网卡根据路由表继续发送数据包。这通常是路由器所要实现的功能。
- kube-proxy的ipvs模式和calico(都涉及路由转发)都需要主机开启ipv4转发。
- 另外,不使用k8s,即使只使用docker的时候,以下两种情况也依赖ipv4转发:
<1>当同一主机上的两个跨bridge(跨bridge相当于跨网段,跨网络需要路由)的容器互访
<2>从容器内访问外部
参考: https://docs.docker.com/v17.09/engine/userguide/networking/default_network/container-communication/#communicating-to-the-outside-world
数据包经过路由后,假如不是发往本机的流量,下一步会走iptables的FORWARD链,而docker从1.13版本开始,将FORWARD链的默认策略设置为DROP,会导致出现一些例如跨主机的两个pod使用podIP互访失败等问题。解决方案有2个:
方案一
临时生效:
$ sudo iptables -P FORWARD ACCEPT
iptables的配置重启后会丢失,可以将配置写进/etc/rc.local中,重启后自动执行:
/usr/sbin/iptables -P FORWARD ACCEPT
方案二
设置docker启动参数添加--iptables=false
选项,使docker不再操作iptables,比如1.10版以上可编辑docker daemon默认配置文件/etc/docker/daemon.json
:
{
"iptables": false
}
备注:
- 建议方案二
- kubernetes官网建议和k8s结合的时候docker的启动参数设置
--iptables=false
使得docker不再操作iptables,完全由kube-proxy来操作iptables。- 参考:
<1>https://docs.docker.com/v17.09/engine/userguide/networking/default_network/container-communication/#container-communication-between-hosts
<2>https://github.com/kubernetes/kubernetes/issues/40182
<3>https://kubernetes.io/docs/setup/scratch/#docker
<4>https://github.com/moby/moby/pull/28257
1.禁掉所有的swap分区
$ sudo swapoff -a
2.同时还需要修改/etc/fstab文件,注释掉 SWAP 的自动挂载,防止机子重启后swap启用。
备注:
- Kubernetes 1.8开始要求关闭系统的Swap,如果不关闭,默认配置下kubelet将无法启动,虽然可以通过kubelet的启动参数
--fail-swap-on=false
更改这个限制,但不建议,最好还是不要开启swap。- 一些为什么要关闭swap的讨论:
<1>https://github.com/kubernetes/kubernetes/issues/7294
<2>https://github.com/kubernetes/kubernetes/issues/53533
$ sudo tee /etc/sysctl.d/k8s.conf <<-'EOF'
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sudo sysctl --system
备注:
- 网络插件需要为kube-proxy提供一些特定的支持,比如kube-proxy的iptables模式基于iptables,网络插件就需要确保容器的流量可以流过iptables。比如一些网络插件会用到网桥,而网桥工作在数据链路层,
iptables/netfilter
防火墙工作在网络层,以上配置则可以使得通过网桥的流量也进入iptables/netfilter防火墙中,确保iptables模式的kube-proxy可以正常工作。- 默认没有指定kubelet网络插件的情况下,会使用
noop
插件,它也会设置net/bridge/bridge-nf-call-iptables=1
来确保iptables模式的kube-proxy可以正常工作。- 参考:
<1>https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#network-plugin-requirements
<2>https://kubernetes.io/docs/setup/independent/install-kubeadm/
树莓派是基于debian的系统,而debian默认没有mount memory的cgroup,这里需要手动开启
编辑/boot/cmdline.txt,在该行的末尾添加此文本,但不要创建任何新行:
cgroup_enable=memory
重启:
sudo reboot
修改树莓派的源,换成中科大的源(http://mirrors.ustc.edu.cn/help/raspbian.html)
$ sudo sed -i 's|raspbian.raspberrypi.org|mirrors.ustc.edu.cn/raspbian|g' /etc/apt/sources.list
$ sudo apt-get update
树莓派目前不支持通过软件源安装,需要下载好deb包,使用dpkg安装
1.卸载旧docker
$ sudo apt-get remove docker docker-engine docker.io
2.查看内核版本,确保大于3.10
$ uname -r
3.下载deb包:
到docker下载页(https://download.docker.com/linux/raspbian/dists/stretch/pool/stable/armhf/) 下载安装包:
$ wget https://download.docker.com/linux/raspbian/dists/stretch/pool/stable/armhf/docker-ce_18.06.1~ce~3-0~raspbian_armhf.deb
4.dpkg安装
sudo dpkg -i docker-ce_18.06.1_ce_3-0_raspbian_armhf.deb
5.启动并设置开机自启动docker
$ sudo systemctl enable docker && sudo systemctl start docker
6.将当前登录用户加入docker用户组中
$ sudo usermod -aG docker $(whoami)
然后退出,重新登录,使用docker命令就不用加sudo了。
备注:
树莓派3B+是基于armv8的64位CPU,但是树莓派官方只维护了基于debian的32位arm版本Raspbian,并没有官方支持的arm64位版本。本实验装的官方系统是32位的,所以只能选择armhf版docker安装包。
为docker做如下配置:
MASQUERADE
,否则docker会将podIP这个源地址SNAT成nodeIP最终配置如下:
$ sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"],
"iptables": false,
"ip-masq": false,
"storage-driver": "overlay2",
"graph": "/home/lk/docker"
}
EOF
$ sudo systemctl restart docker
备注:
- docker的所有启动参数可见:https://docs.docker.com/engine/reference/commandline/dockerd/
- 将xxxxxxxx替换成阿里云为你生成的镜像代理仓库前缀
假如机器在内网环境无法直接访问外网的话,还需要为docker设置一个http_proxy。
$ sudo mkdir /etc/systemd/system/docker.service.d
$ sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<-'EOF'
[Service]
Environment="HTTP_PROXY=http://xxx.xxx.xxx.xxx:xxxx"
Environment="NO_PROXY=localhost,127.0.0.0/8"
EOF
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
创建kubernetes的source文件:
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
sudo curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo tee /etc/apt/sources.list.d/kubernetes.list <<-'EOF'
deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main
EOF
sudo apt-get update
google地址被墙的情况下可以使用阿里云或者中科大的镜像站:
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
sudo curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -
sudo tee /etc/apt/sources.list.d/kubernetes.list <<-'EOF'
deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main
EOF
sudo apt-get update
备注:
虽然我的ubuntu版本是18.04.1(bionic),但k8s的apt包目前还没支持到这么高,使用xenial。
1.查看可用软件版本:
$ apt-cache madison kubeadm
kubeadm | 1.12.1-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main armhf Packages
kubeadm | 1.12.0-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main armhf Packages
kubeadm | 1.11.3-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main armhf Packages
kubeadm | 1.11.2-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main armhf Packages
......
2.安装指定版本:
$ sudo apt-get install -y kubelet=1.12.0-00 kubeadm=1.12.0-00 kubectl=1.12.0-00
$ sudo apt-mark hold kubelet=1.12.0-00 kubeadm=1.12.0-00 kubectl=1.12.0-00
3.设置开机自启动并运行kubelet:
sudo systemctl enable kubelet && sudo systemctl start kubelet
备注:
此时kubelet的服务运行状态是异常的(因为缺少主配置文件kubelet.conf等,可以暂不处理,因为在完成Master节点的初始化后才会生成这个配置文件)
本章节参考: https://kubernetes.io/docs/setup/independent/install-kubeadm/
看一下kubernetes v1.12.0需要哪些镜像:
$ kubeadm config images list --kubernetes-version=v1.12.0 --feature-gates CoreDNS=false
k8s.gcr.io/kube-apiserver:v1.12.0
k8s.gcr.io/kube-controller-manager:v1.12.0
k8s.gcr.io/kube-scheduler:v1.12.0
k8s.gcr.io/kube-proxy:v1.12.0
k8s.gcr.io/pause:3.1
k8s.gcr.io/etcd:3.2.24
k8s.gcr.io/k8s-dns-kube-dns:1.14.13
k8s.gcr.io/k8s-dns-sidecar:1.14.13
k8s.gcr.io/k8s-dns-dnsmasq-nanny:1.14.13
备注:
- 1.12.0版本之前,镜像形式是需要带体系结构名的:
镜像前缀-${ARCH}:tag
,如k8s.gcr.io/kube-proxy-arm:v1.11.2
,从1.12.0开始,不再带体系结构名。但是后来发现使用不带体系结构的镜像是不行的,会报错standard_init_linux.go:190: exec user process caused "exec format error"
,还是要用带-arm的镜像。- 默认会使用coredns,但是coredns目前没有1.2.2版的arm架构镜像,所以通过指定
--feature-gates CoreDNS=false
来使用kubedns
1.由于gcr.io被墙,从anjia0532镜像地址下载:
docker pull anjia0532/google-containers.kube-apiserver-arm:v1.12.0
docker pull anjia0532/google-containers.kube-controller-manager-arm:v1.12.0
docker pull anjia0532/google-containers.kube-scheduler-arm:v1.12.0
docker pull anjia0532/google-containers.kube-proxy-arm:v1.12.0
docker pull anjia0532/google-containers.pause-arm:3.1
docker pull anjia0532/google-containers.etcd-arm:3.2.24
docker pull anjia0532/google-containers.k8s-dns-kube-dns-arm:1.14.13
docker pull anjia0532/google-containers.k8s-dns-sidecar-arm:1.14.13
docker pull anjia0532/google-containers.k8s-dns-dnsmasq-nanny-arm:1.14.13
2.重新打回k8s.gcr.io的镜像tag:
由于yaml文件里指定的镜像都不带-arm,所以,还需要将镜像中的-arm去掉
docker tag anjia0532/google-containers.kube-apiserver-arm:v1.12.0 k8s.gcr.io/kube-apiserver:v1.12.0
docker tag anjia0532/google-containers.kube-controller-manager-arm:v1.12.0 k8s.gcr.io/kube-controller-manager:v1.12.0
docker tag anjia0532/google-containers.kube-scheduler-arm:v1.12.0 k8s.gcr.io/kube-scheduler:v1.12.0
docker tag anjia0532/google-containers.kube-proxy-arm:v1.12.0 k8s.gcr.io/kube-proxy:v1.12.0
docker tag anjia0532/google-containers.pause-arm:3.1 k8s.gcr.io/pause:3.1
docker tag anjia0532/google-containers.etcd-arm:3.2.24 k8s.gcr.io/etcd:3.2.24
docker tag anjia0532/google-containers.k8s-dns-kube-dns-arm:1.14.13 k8s.gcr.io/k8s-dns-kube-dns:1.14.13
docker tag anjia0532/google-containers.k8s-dns-sidecar-arm:1.14.13 k8s.gcr.io/k8s-dns-sidecar:1.14.13
docker tag anjia0532/google-containers.k8s-dns-dnsmasq-nanny-arm:1.14.13 k8s.gcr.io/k8s-dns-dnsmasq-nanny:1.14.13
1.加载所需的内核模块:
$ sudo modprobe br_netfilter
设置开机自动加载,打开/etc/rc.local,加入如下内容:
modprobe br_netfilter
2.部署:
sudo kubeadm init --apiserver-advertise-address=192.168.1.192 --pod-network-cidr=172.16.0.0/16 --service-cidr=10.233.0.0/16 --kubernetes-version=v1.12.0 --feature-gates CoreDNS=false
3.部署成功会输出如下内容:
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/
You can now join any number of machines by running the following on each node
as root:
kubeadm join 192.168.1.192:6443 --token gomx6b.u5or5yxkm8orths8 --discovery-token-ca-cert-hash sha256:24fa1c34e97b14f85b06726e5f4d1987c61da978e2f740d829280a84f54aa8f2
记下其中的token,加入node节点时会用到。
备注:
- 确保没有设置http_proxy和https_proxy代理,kubeadm init过程首先会检查代理服务器,确定跟
kube-apiserver
等的 http/https 连接方式,如果有代理设置可能会有问题导致不能访问自身和内网。 需要在/etc/profile中增加kubeadm init指定的apiserver-advertise-address
、pod-network-cidr
、service-cidr
三个地址段到no_proxy里后重试:export no_proxy=10.142.232.155,192.168.0.0/16,10.233.0.0/16
- 集群初始化如果遇到问题,可以使用下面的命令进行清理再重新初始化:
sudo kubeadm reset
kubelet启动时指定的cgroup driver需要和docker所使用的保持一致。
1.查看 Docker 使用的 cgroup driver:
$ docker info | grep -i cgroup
-> Cgroup Driver: cgroupfs
可以看出docker 17.03默认使用的Cgroup Driver为cgroupfs。
2.查看kubelet指定的cgroup driver
Kubernetes文档中kubelet的启动参数--cgroup-driver string Driver that the kubelet uses to manipulate cgroups on the host. Possible values: 'cgroupfs', 'systemd' (default "cgroupfs")
。默认值为cgroupfs。yum安装kubelet、kubeadm时生成10-kubeadm.conf文件中可能将这个参数值改成了systemd。
查看kubelet的配置文件(1.12.0版本的封装在/var/lib/kubelet/kubeadm-flags.env文件中),如果是默认的cgroupfs,不需要修改。否则需要修改/etc/default/kubelet(或者/var/lib/kubelet/kubeadm-flags.env)文件:
$ sudo vim /etc/default/kubelet
KUBELET_KUBEADM_EXTRA_ARGS=--cgroup-driver=
$ sudo systemctl daemon-reload
$ sudo systemctl restart kubelet
参考:https://kubernetes.io/docs/setup/independent/install-kubeadm/#configure-cgroup-driver-used-by-kubelet-on-master-node
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
创建完成即可使用kubectl操作集群。
使用kubeadm初始化的集群,将master节点做了taint(污点),使得默认情况下(不设置容忍)Pod不会被调度到master上。这里搭建的是测试环境可以使用下面的命令去掉master的taint,使master参与工作负载:
$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/raspberrypi untainted
备注:
本部分参考:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/
可以选择不同的网络插件,但是calico目前没有32位arm的镜像(只有arm64),本文介绍flannel的部署。
flannel的部署只会初始化一些cni的配置文件,并不会部署cni的可执行文件,需要手动部署,所以flannel部署分为两步:
1.创建cni插件目录
sudo mkdir -p /opt/cni/bin && cd /opt/cni/bin
2.到release页面下载arm架构二进制文件
wget https://github.com/containernetworking/plugins/releases/download/v0.7.1/cni-plugins-arm-v0.7.1.tgz
3.在/opt/cni/bin目录下解压即安装好
sudo tar -zxvf cni-plugins-arm-v0.7.1.tgz
添加了如下插件:
[docker@k8s ]$ ll /opt/cni/bin
总用量 60032
-rwxr-xr-x 1 root root 3653505 4月 12 2018 bridge
-rw-r--r-- 1 pi pi 16051784 9月 27 17:37 cni-plugins-arm-v0.7.1.tgz
-rwxr-xr-x 1 root root 8843152 4月 12 2018 dhcp
-rwxr-xr-x 1 root root 2600302 4月 12 2018 flannel
-rwxr-xr-x 1 root root 2886491 4月 12 2018 host-device
-rwxr-xr-x 1 root root 2812425 4月 12 2018 host-local
-rwxr-xr-x 1 root root 3300255 4月 12 2018 ipvlan
-rwxr-xr-x 1 root root 2819115 4月 12 2018 loopback
-rwxr-xr-x 1 root root 3303763 4月 12 2018 macvlan
-rwxr-xr-x 1 root root 3232319 4月 12 2018 portmap
-rwxr-xr-x 1 root root 3651705 4月 12 2018 ptp
-rwxr-xr-x 1 root root 2392245 4月 12 2018 sample
-rwxr-xr-x 1 root root 2602702 4月 12 2018 tuning
-rwxr-xr-x 1 root root 3300211 4月 12 2018 vlan
1.获取yaml文件
$ wget https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
2.修改配置文件
<1>保留arm的daemonset,删除其他架构的daemonset
<2>修改其中net-conf.json
中的Network
参数使其与kubeadm init时指定的--pod-network-cidr
保持一致。
<2>这里v0.10.0版有一个bug,需要为启动flannel的daemonset添加toleration,以允许在尚未Ready的节点上部署flannel pod:
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
#添加下面这个toleration
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoSchedule
可以参考这个issue:https://github.com/coreos/flannel/issues/1044
3.提前下载所需镜像
下载arm架构的镜像,并重新打tag成x64的,以骗过daemonset:
docker pull fishead/quay.io.coreos.flannel:v0.10.0-arm
docker tag fishead/quay.io.coreos.flannel:v0.10.0-arm quay.io/coreos/flannel:v0.10.0-arm
4.部署
kubectl apply -f kube-flannel.yml
部署好后集群就可以正常运行了。
备注:
假如网络部署失败或出问题需要重新部署,执行以下内容清除生成的网络接口:
sudo ifconfig cni0 down
sudo ip link delete cni0
sudo ifconfig flannel.1 down
sudo ip link delete flannel.1
sudo rm -rf /var/lib/cni/
同样按照上述步骤安装好docker、kubelet,然后在slave节点上执行以下命令即可加入集群:
kubeadm join 192.168.1.192:6443 --token 4k5jyn.2ss2zcn44c7e7zc1 --discovery-token-ca-cert-hash sha256:0e3e9348b5372aceedab8ca5f3e6537d5eaf7134dce24523f512c0ef2f1a54f6
更多精彩内容,请订阅本人微信公众号:K8SPractice
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
支付宝: