Fancy‘s Technology Blog

Fancy的技术博客
tc sc en

kubeadm搭建部署kubernetes集群

2020-03-22 Code Fancy

零零散散看了不少k8s的文档,搭建过几次,每次都有不同的收获,部署根据不同的应用场景比较灵活,对应的姿势也是五花八门,网上关于K8s部署的文档坑实在是太多了,想著能否好好总结下,学习下部署设计,便于自己查阅以及更好的理解k8s。

目前kubeadm支持:

  • Ubuntu 16.04+
  • Debian 9+
  • CentOS 7
  • Red Hat Enterprise Linux (RHEL) 7
  • Fedora 25+
  • HypriotOS v1.0.1 +
  • Container Linux (tested with 1800.6.0)

官方建议至少2G内存,要求双核及以上。并检查网络链接以及用的端口是否开放。更改下防火墙设置放行端口

我这里利用了斐讯N1刷的ArmbianRaspberry Pi 3B+HypriotOS组成最小单元的集成作为示例,之所以选择这两个,主要是因为硬件便宜(家里已经4个N1了),另外想试试HypriotOS这么好用的Docker专用系统,同是debian系的也便于安装命令复用。刚好作为最小集群一个Master节点一个Node节点。

比如Item2 就使用⌘(command) + d 左右分屏,⌘(command) + ⇧(shift) + i 开启多窗口输入命令。省很多功夫。

首先按要求关闭Swap(性能考虑,不关闭会拖慢速度,官方说的是必须的)

sudo swapoff -a

关闭Selinux:

setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

确保主机名(hostname)和MAC, product_uuid是否唯一的,这些是用于K8s辨别Node节点唯一性的值,都相同会导致安装失败,可以分别用以下命令查看 毕竟是ARM,我们的armbian内核是没有加载 dmi sysfs的,所以product_uuid无从谈起。

cat /etc/hostname 
sudo ifconfig -a
sudo cat /sys/class/dmi/id/product_uuid

我的建议是首先更改Hostname,后期便利很多。

# Master节点
sudo hostnamectl --static set-hostname k8s-master
# Node节点1
sudo hostnamectl --static set-hostname k8s-node1

修改桥接网络配置

lsmod | grep br_netfilter. 检查br_netfilter是否运行,如果没有的话可以用 modprobe br_netfilter显式调用。然后运行防止iptables被绕过:

cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

安装Docker

截至2020年3月30号,官方推荐的Docker版本是 19.03.8。我们通过docker -v确保版本是在能稳定运行k8s的1.13.1, 17.03, 17.06, 17.09, 18.06, 18.09, 19.03.08 之中。

安装Docker CE老生常谈了,Azure阿里云这些镜像加速毕竟是有N1的程序员我表示根本不需要,网上也有很多参考,这里可以使用一键脚本

curl -fsSL "https://get.docker.com/" | sh
systemctl enable --now docker

或者Docker官网https://docs.docker.com/install/linux/docker-ce/debian/根据不同发行版和架构安装,我贴的这份仅限Arm架构的Debian安装。

# 允许apt透过HTTPS使用软件包
apt update && apt install -y \
  apt-transport-https ca-certificates curl software-properties-common gnupg2

# 添加Docker的GPGkey
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -

# 添加Docker apt软件包
add-apt-repository \
   "deb [arch=arm64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"

# 安装 Docker CE 及 Container.
apt-get update && apt-get install -y \
  containerd.io=1.2.13-1 \
  docker-ce=5:19.03.8~3-0~debian-$(lsb_release -cs) \
  docker-ce-cli=5:19.03.8~3-0~debian-$(lsb_release -cs)
# sudo apt-get install docker-ce docker-ce-cli containerd.io

###配置镜像

修改daemon.json,配置cgroup驱动,与k8s一致,如果添加镜像加速的话添加多句 "registry-mirrors": ["https://xxx.mirror.aliyuncs.com"],之类,之后重启,如下:

# 这里使用systemd作为Docker croup
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

# 创建Docker服务目录

mkdir -p /etc/systemd/system/docker.service.d

# 重启Docker,开启开机启动
systemctl daemon-reload
systemctl enable docker
systemctl restart docker

# 检查Docker
docker -v
# >>> Docker version 19.03.8, build afacb8b
docker run hello-world

安装Runtime

kubeadm的方案

安装kubeadm, kubelet 和 kubectl(Master & Node)

Debian系:

sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl


systemctl enable kubelet && systemctl start kubelet

RedHat系:

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

# Set SELinux in permissive mode (effectively disabling it)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

systemctl enable --now kubelet

配置Cgroup drive

检查docker的cgroup驱动,应与kubelet 的cgroup drive保持一致。

docker info | grep -i cgroup
# >>> Cgroup Driver: cgroupfs / systemd

初始化部署Master(Master)

如果熟悉之后,有更多的灵活性可以按需调整,我个人更建议第二种生成文件的部署方式。

  • 直接初始化init部署

    $ sudo kubeadm init \
        --kubernetes-version=v1.18.0 \
        --apiserver-advertise-address=192.168.123.181 \
        --pod-network-cidr=10.244.0.0/16 \
        --service-cidr=10.96.0.0/12
        --image-repository=registry.aliyuncs.com/google_containers
    

    参数说明:

    • –-pod-network-cidr:集群所属的Pod子网范围,使用fannel网络必须使用这个CIDR。
    • –-kubernetes-version:指定K8S版本,建议与kubeadm, kubelet 和 kubectl一致。
    • –-apiserver-advertise-address:作为Master与其他Node通信的IP地址。
    • –control-plane-endpoint:标志应该被设置成负载均衡器的地址或 DNS 和端口。会取–-apiserver-advertise-address的值
    • –image-repository:指定下载源,例:registry.aliyuncs.com/google_containers
    • –service-cidr:service网段,负载均衡ip
    • –ignore-preflight-errors=Swap/all:忽略 swap/所有 报错
  • 配置文件部署

    创建配置文件

    $ kubeadm config print init-defaults --kubeconfig ClusterConfiguration > kubeadm.yml
    

    根据情况修改配置文件内容,kube-proxy 的 IPVS 模式在大规模下会有更好的性能表现,我们

    apiVersion: kubeadm.k8s.io/v1beta2
    bootstrapTokens:
    - groups:
      - system:bootstrappers:kubeadm:default-node-token
      token: abcdef.0123456789abcdef
      ttl: 24h0m0s
      usages:
      - signing
      - authentication
    kind: InitConfiguration
    localAPIEndpoint: 
      advertiseAddress: 192.168.123.181 # 作为Master与其他Node通信的IP地址。
      bindPort: 6443
    nodeRegistration:
      criSocket: /var/run/dockershim.sock
      name: k8s-node1
      taints:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
    --
    apiServer:
      timeoutForControlPlane: 4m0s
    apiVersion: kubeadm.k8s.io/v1beta2
    certificatesDir: /etc/kubernetes/pki
    clusterName: kubernetes
    controllerManager: {}
    dns:
      type: CoreDNS
    etcd:
      local:
        dataDir: /var/lib/etcd
    imageRepository: k8s.gcr.io    # 指定下载源,例:registry.aliyuncs.com/google_containers
    kind: ClusterConfiguration
    kubernetesVersion: v1.18.0     # 指定K8S版本,建议与kubeadm, kubelet 和 kubectl一致。
    networking:
      dnsDomain: cluster.local
      podSubnet: 192.168.0.0/16    # Pod子网默认网段范围
      serviceSubnet: 10.96.0.0/12  # service网段
    scheduler: {}
    

    保存kubeadm.yml后,查看及拉取镜像

    $ kubeadm config images list --config kubeadm.yml
    $ kubeadm config images pull --config kubeadm.yml
    

    初始化

    $ kubeadm init --config kubeadm-init.yaml
    

若执行kubeadm init出错或强制终止,则再需要执行该命令时,需要先执行kubeadm reset重置配置后再进行kubeadm init

如果两种方法没有异常,那么你将在最后看到类似这样的返回:

Your Kubernetes control-plane 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/

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

kubeadm join 192.168.123.181:6443 --token 1lfiq6.tyiic0y0gjybw4vq \
    --discovery-token-ca-cert-hash sha256:a407b3d77b8cb9942c06d32a3aa51ed4ed34e4faec3186d9eabd0c4ef307562e

最后一句务必要先记录下来。

配置 kubectl 环境(Master)

如果是root账户不必最后一句chown赋予权限操作

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

使用Dashboard(Master)

如果使用Dashboard,应在配置 kubectl 环境后,Node Join前部署,否则:

W0401 18:20:37.196454   22044 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set.

可以使用这句命令一键部署

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

$ kubectl get pods --all-namespaces | grep dashboard

node加入集群:(Node)

如以上的最后一句,我们可以使用root权限将Worker添加节点进来集群。

$ sudo kubeadm join 192.168.123.181:6443 --token 1lfiq6.tyiic0y0gjybw4vq \
    --discovery-token-ca-cert-hash sha256:a407b3d77b8cb9942c06d32a3aa51ed4ed34e4faec3186d9eabd0c4ef307562e
[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.18" 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] Starting the kubelet
[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上查看节点状态:

$ kubectl get pods --all-namespaces

k8s部署下来,理解也不是很深入,如果有问题欢迎共同讨论。可能自己这篇也不免成为一个新坑吧。另外树莓派3B+做master节点不太合适,这里用的N1作为主节点,往后计划试试k3s部署,相较之下更加适合Arm架构以及树莓派这种低效能的服务器集群吧。这里先用HypriotOS做个过渡。

附:Raspberry Pi 如何使用 HypriotOS

Etcher在写入之后,可以编辑一下根目录的user-data

如果你有Wifi连接的需求的话,这个步骤将是必须的。

尝试过很多官网或者帖子上的内容,官方Github博客源代码一个关闭的Issue里可以找到很好的解法

#cloud-config
# vim: syntax=yaml
#

# Set your hostname here, the manage_etc_hosts will update the hosts file entries as well
hostname: black-pearl
manage_etc_hosts: true

# You could modify this for your own user information
users:
  - name: pirate                                                # 用户名
    gecos: "Hypriot Pirate"
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    groups: users,docker,video,input
    plain_text_passwd: hypriot                                  # 明文密码
    lock_passwd: false
    ssh_pwauth: true
    chpasswd: { expire: false }

# # Set the locale of the system
locale: "en_US.UTF-8"

# # Set the timezone
# # Value of 'timezone' must exist in /usr/share/zoneinfo
timezone: "Asia/Harbin"                                         # 时区

# # Update apt packages on first boot
# package_update: true
# package_upgrade: true
# package_reboot_if_required: true
package_upgrade: false

# # Install any additional apt packages you need here
# packages:
#  - ntp

# # WiFi connect to HotSpot
# # - use `wpa_passphrase SSID PASSWORD` to encrypt the psk
write_files:
  - content: |
      allow-hotplug wlan0
      iface wlan0 inet dhcp
      wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
      iface default inet dhcp
    path: /etc/network/interfaces.d/wlan0
  - content: |                                                  # 如果启动wifi则按此编辑
      country=CN
      ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
      update_config=1
# 密码(明文加引号)
      network={
      ssid="YourID"
      psk="12345678"                                            
      key_mgmt=WPA-PSK
      }
    path: /etc/wpa_supplicant/wpa_supplicant.conf

# These commands will be ran once on first boot only
runcmd:
  # Pickup the hostname changes
  - 'systemctl restart avahi-daemon'

#  # Activate WiFi interface
# 开启wifi支持
  - 'ifup wlan0'
bootcmd:
# 开机自动连接wifi
  - [ ifup, wlan0 ]

comments powered by Disqus