K8s笔记之一:在N1集群上部署Kubernetes

硬件说明

2019年的时候听说了斐讯N1这个好东西,因为P2P翻车给市场提供了大量的便宜货,相比当年市场上那些垃圾货,这个的性价比非常好,所以一下买了四个。时过境迁,现在N1的价格已经涨了,市场高性能的便宜盒子也出了几代,比如一些同样用晶晨SoC的运营商盒子,只要N1一半的价格,N1的优势已经不大了。

我的四个N1做了很多用途:一个刷成电视盒子接在旧电视上看电视,一个刷了OMV做NAS,两个刷了Armbian Buster跑ELK。

现在过了一年多,我自己也因为主服务器换了一台AMD A12-9800E(现在又升级成Ryzen3 5300U了),性能比原来的Intel J1900好了很多,所以ELK什么的都迁到新服务器上了。又因为托某个壕朋友的福,送了我一台白裙,所以OMV的NAS也不需要了。于是一下空出三台N1来。

于是想点办法来用起来,就搞了这么个集群来跑Kubernetes玩玩——虽然在主服务器跑三个虚拟机也不是不行,但是虚拟集群毕竟不如物理集群爽。

基本安装配置

当然是先把系统全部重刷一遍,都用Armbian Buster。然后跑一个Ansible剧本做一下基本配置并安装Docker。然后用一个新的角色来安装Kubernetes。

  • roles
    • k8s
      • files
        • docker.systemd
      • handler
        • main.yml
      • tasks
        • main.yml

docker配置

其中docker.systemd是docker的配置文件,用于增加一个代理,因为k8s的docker源在国内无法直接访问。当然另外一个方法是修改k8s的配置,让它使用国内镜像,这个可以参考别的文章。

[Service]
Environment="HTTP_PROXY=http://proxy_ip:proxy_port"
Environment="HTTPS_PROXY=http://proxy_ip:proxy_port"

systemd配置

handler的main.yml用于修改docker配置后重启docker。

---
- name: Restart docker
  systemd:
    name: docker
    state: restarted
    daemon_reload: yes

注意,这里用的不是service模块,而是systemd模块,并且其中需要加上daemon_reload,让systemd重新加载配置,不然重启docker也没用。

角色任务

tasks的main.yml用于安装k8s。

安装前有几个配置工作:

  • docker服务配置代理,用于下载k8s镜像
  • 安装和配置arptables和ebtables
  • 禁用swap

之后为k8s安装工作。

---
- name: Create directory for docker config
  file:
    path: /etc/systemd/system/docker.service.d
    state: directory
    recurse: yes
    owner: root
    group: root
    mode: 0775

- name: Copy docker config file
  copy:
    src: docker.systemd
    dest: "/etc/systemd/system/docker.service.d/override.conf"
    mode: '0644'
  notify:
    - Restart docker

- name: Install packages
  apt:
    pkg:
      - arptables
      - ebtables
    update_cache: no
    install_recommends: no
    autoremove: yes
    autoclean: yes
  environment: "{{ proxy_env }}"

- name: Update alternatives
  alternatives:
    name: "{{ item.name }}"
    path: "{{ item.path }}"
  with_items:
    - { name: 'iptables', path: '/usr/sbin/iptables-legacy' }
    - { name: 'ip6tables', path: '/usr/sbin/ip6tables-legacy' }
    - { name: 'arptables', path: '/usr/sbin/arptables-legacy' }
    - { name: 'ebtables', path: '/usr/sbin/ebtables-legacy' }

- name: Turn off swap
  command: swapoff -a
  
- name: Turn off swap forever
  lineinfile:
    path: /etc/fstab
    regexp: "^([^#].*none\\s+swap\\s+sw.*)$"
    line: "#\\g<1>"
    backrefs: yes

- name: Add apt signing key of kubernetes
  apt_key:
    url: "https://packages.cloud.google.com/apt/doc/apt-key.gpg"
    state: present
  environment: "{{ proxy_env }}"

- name: Add repository of kubernetes
  apt_repository:
    repo: "deb https://apt.kubernetes.io/ kubernetes-xenial main"
    state: present
  environment: "{{ proxy_env }}"

- name: Actually install kubernetes
  apt:
    pkg:
      - kubelet
      - kubeadm
      - kubectl
    state: latest
    update_cache: yes
    install_recommends: no
  environment: "{{ proxy_env }}"

- name: Hold kubernetes version
  dpkg_selections:
    name: "{{ item.name }}"
    selection: hold
  with_items:
    - { name: 'kubelet' }
    - { name: 'kubeadm' }
    - { name: 'kubectl' }

- name: Get kubernetes images
  shell: kubeadm config images pull

安装后配置

三台N1都用上面的剧本完成基本安装后,开始分别安装K8s环境。

首先在其中一台N1(比如叫KUBESVR1)配置Control Plane(就是Master Node,因为狗日的政治正确而改成这样莫名其妙的名字,暂时先不考虑高可用集群配置):

安装网络

K8s支持多种不同的Pod网络插件,这里以最基础的Flannel为例:

# 常规操作是这样:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 但由于国内的网络问题,建议还是先下载这个yml文件,然后在本地安装:
kubectl apply -f kube-flannel.yml

安装完后打开这个yaml文件,可以看到这么一段:

  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

这个网段就是Flannel所用的网段。

初始化Control Plane

准备工作:

确认Control Plane节点的CPU至少是双核(N1是4核所以没问题)
# 如果PATH里没有sbin要加上
export PATH=/sbin:$PATH

开始安装Control Plane

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

其中的网段就是Flannel的,如果使用不同的网络插件,要就指定不同的网段。

初始化完成后返回这么一段内容:

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:
  /docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

其中包含几个重要信息:

第一:如果要用非root用户操作kubectl,则需要在用户目录下创建.kube/config

第二:如果要在集群里部署应用,则使用kubectl apply命令

第三:如果有其它节点要加入这个集群,则使用kubeadm join命令,参数中的token和hash要注意安全保存,如果忘记记录token,可以用kubeadm token list查看

第四:token的有效期只有24小时,过期后需要重新创建kubeadm token create

添加节点

在其它节点(即Slave Node)上简单使用上面提示的命令运行即可:

kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

在另两台N1(KUBESVR2,KUBESVR3)上执行这个命令,完成集群的组建。

现在回到Control Plane(KUBESVR1),运行:

kubectl get nodes

即可查看此Control Plane管理的集群中的节点。

至此K8s集群搭建完成,之后就可以通过Control Plane在集群里部署应用了。

顺便说一下,如果一个节点要退出集群,可以用:

kubeadm reset

需要再次加入时则再执行join命令。

故障排除

如果kubectl get nodes返回节点状态是NotReady则需要检查一下节点详情:

kubectl describe node <node_name>

在返回结果里搜索相关的关键字查找错误原因,比如未安装网络会导致network plugin is not ready: cni config uninitialized错误。

如果确定网络已经安装,新增节点仍然报这个错误,可以看一下是否没有下载成功flannel镜像,有时会因为网络问题导致下载失败,手工下载一下即可。

推送到[go4pro.org]