云原生第一周--ubuntu2204使用containerd容器和kubeadm工具部署单master k8s集群

发布时间 2023-05-01 19:21:38作者: 黑夜有约

1 Kubernetes介绍

Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。

Kubernetes它能做什么

服务发现和负载均衡
Kubernetes 可以使用 DNS 名称或自己的 IP 地址来曝露容器。 如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。

存储编排
Kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。

自动部署和回滚
你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。

自动完成装箱计算
你为 Kubernetes 提供许多节点组成的集群,在这个集群上运行容器化的任务。 你告诉 Kubernetes 每个容器需要多少 CPU 和内存 (RAM)。 Kubernetes 可以将这些容器按实际情况调度到你的节点上,以最佳方式利用你的资源。

自我修复
Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端。

密钥与配置管理
Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。

kubernetes架构

image

image

master节点主要组件概述

  master节点主要是k8s的控制节点,在master节点上主要有三个组件必不可少,apiserver、scheduler和controllermanager;etcd是集群的数据库,是非常核心的组件,一般是单独的一个集群;主要用来存储k8s集群各组件的配置信息以及各类状态信息;

  apiserver:apiserver组件主要负责接入请求、认证用户合法性以及提交资源请求的准入控制,是管理k8s集群的唯一入口,也是读写etcd中数据的唯一组件;其工作原理是集群各组件通过tcp会话,一直监视(watch)apiserver之上的资源变化,一旦有与之相关的资源变化,对应组件会通过apiserver到etcd中去获取应配置信息,然后根据etcd中的配置信息,做对应的操作,然后把操作后的状态信息再通过apiserver写入etcd中;apiserver认证和准入控制过程,用户通过https将管理集群的请求发送给apiserver,apiserver收到对应请求后,首先会验证用户的身份信息以及合法性;这个认证主要通过用户提供的证书信息;如果用户提供的证书信息apiserver能够再etcd中完全匹配到对应信息,那么apiserver会认为该用户是一个合法的用户;除此之外,apiserver还会对用户提交的资源请求进行准入控制,所谓准入控制是指对应用户提交的资源请求做语法格式检查,如果用户提交的请求,不满足apiserver中各api的格式或语法定义,则对应请求同样会被禁止,只有通过了apiserver的认证和准入控制规则以后,对应资源请求才会通过apiserver存入etcd中或从etcd中获取,然后被其他组件通过watch机制去发现与自己相关的消息事件,从而完成用户的资源请求;简单讲apiserver主要作用就是接入用户请求(这里主要是指管理员的各种管理请求和各组件链接apiserver的请求)认证用户合法性以及提交资源请求的准入控制;集群其他组件的数据的读写是不能直接在etcd中读写的,必须通过apiserver代理它们的请求到etcd中做对应数据的操作;

  scheduler:scheduler主要负责为待调度Pod列表的每个Pod从可用Node列表中选择一个最适合的Node,并将信息写入etcd中。node节点上的kubelet通过APIServer监听到kubernetesScheduler产生的Pod绑定信息,然后获取对应的Pod清单,下载Image,并启动容器;这个过程会经历两个阶段,第一个阶段时预选阶段,所谓预选就是通过判断pod所需的卷是否和节点已存在的卷冲突,判读备选节点的资源是否满足备选pod的需求,判断备选系欸但是否包含备选pod的标签选择器指定的标签,以及节点亲和性、污点和污点容忍度的关系来判断pod是否满足节点容忍度的一些条件;来筛选掉不满足pod运行的节点,剩下的节点会进入第二阶段的优选过程;所谓优选就是在通过预选策略留下来的节点中再通过优选策略来选择一个最适合运行pod的节点来;如优先从备用节点列表中选择消耗资源最小的节点(通过cpu和内存来计算资源得分,消耗越少,得分越高,即谁的得分高就把pod调度到对应节点上);优先选择含有指定Label的节点。优先从备选节点列表中选择各项资源使用率最均衡的节点。使用Pod中tolerationList与节点Taint进行匹配并实现pod调度;简单讲scheduler主要作用就是为pod找到一个合适运行的node;通过预选和优选两个节点来实现pod的调度,然后把调度信息写入到etcd中;

  controllermanager:controllermanager主要用来管理集群的其他控制器,比如副本控制器、节点控制器、命名空间控制器和服务账号控制器等;控制器作为集群内部的管理控制中心,负责集群内的Node、Pod副本、服务端点(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)的管理,当某个Node意外宕机时,ControllerManager会及时发现并执行自动化修复流程,确保集群中的pod副本始终处于预期的工作状态。controller-manager控制器每间隔5秒检查一次节点的状态。如果controller-manager控制器没有收到自节点的心跳,则将该node节点被标记为不可达。controller-manager将在标记为无法访问之前等待40秒。如果该node节点被标记为无法访问后5分钟还没有恢复,controller-manager会删除当前node节点的所有pod并在其它可用节点重建这些pod;简单讲controllermanager主要负责集群pod副本始终处于用于期望的状态,如果对应pod不满足用户期望状态,则controllermanager会调用对应控制器,通过重启或重建的方式让对应pod始终和用户期望状态保持一致;

node节点主要组件概述

  kube-proxy:kube-proxy是k8s网络代理,运行在node之上它反映了node上KubernetesAPI中定义的服务,并可以通过一组后端进行简单的TCP、UDP和SCTP流转发或者在一组后端进行循环TCP、UDP和SCTP转发,用户必须使用apiserverAPI创建一个服务来配置代理,其实就是kube-proxy通过在主机上维护网络规则并执行连接转发来实现Kubernetes服务访问;kube-proxy运行在每个节点上,监听APIServer中服务对象的变化,再通过管理IPtables或者IPVS规则来实现网络的转发;IPVS相对IPtables效率会更高一些,使用IPVS模式需要在运行Kube-Proxy的节点上安装ipvsadm、ipset工具包和加载ip_vs内核模块,当Kube-Proxy以IPVS代理模式启动时,Kube-Proxy将验证节点上是否安装了IPVS模块,如果未安装,则Kube-Proxy将回退到IPtables代理模式;使用IPVS模式,Kube-Proxy会监视KubernetesService对象和Endpoints,调用宿主机内核Netlink接口以相应地创建IPVS规则并定期与KubernetesService对象Endpoints对象同步IPVS规则,以确保IPVS状态与期望一致,访问服务时,流量将被重定向到其中一个后端Pod,IPVS使用哈希表作为底层数据结构并在内核空间中工作,这意味着IPVS可以更快地重定向流量,并且在同步代理规则时具有更好的性能,此外,IPVS为负载均衡算法提供了更多选项,例如:rr(轮询调度)、lc(最小连接数)、dh(目标哈希)、sh(源哈希)、sed(最短期望延迟)、nq(不排队调度)等。kubernetesv1.11之后默认使用IPVS,默认调度算法为rr;

  kubelet:kubelet是运行在每个worker节点的代理组件,它会监视已分配给节点的pod;它主要功能有,向master汇报node节点的状态信息;接受指令并在Pod中创建docker容器;准备Pod所需的数据卷;返回pod的运行状态;在node节点执行容器健康检查;

客户端工具组件

  命令行工具kubectl:它时一个通过命令行对k8s集群进行管理的客户端工具;工作逻辑是,默认情况是在用户家目录的.kube目录中查找一个名为config的配置文件,这个配置文件主要是保存用于连接k8s集群的认证信息;当然我们也可以使用设置KUBECONFIG环境变量或者使用--kubeconfig参数来指定kubeconfig配置文件来使用此工具;

  Dashboard:该工具是基于web网页的k8s客户端工具;我们可以使用该web页面查看集群中的应用概览信息,也可以创建或者修改k8s资源,也可以对deployment实现弹性伸缩、发起滚动升级、删除pod或这是用向导创建新的应用;

2 部署k8s详细步骤

系统初始化

挂载br_netfilter模块
lsmod |grep br_netfilter
而后修改sysctl.conf文件

cat /etc/sysctl.conf

image

sysctl -p

内核模块开机挂载

image

安装依赖包
apt update && apt install bash-completion conntrack ipset ipvsadm jq libseccomp2 nfs-common psmisc rsync socat -y

配置资源限制并重启服务器

tail -10 /etc/security/limits.conf
root    soft    core            unlimited
root    hard    core            unlimited
root    soft    nproc           1000000
root    hard    nproc           1000000
root    soft    nofile          1000000
root    hard    nofile          1000000
root    soft    memlock         32000
root    hard    memlock         32000
root    soft    msgqueue        8192000
root    hard    msgqueue        8192000

关闭swap分区

swapoff -a
cat /etc/fstab 删除交换分区配置
image

脚本安装containerd

root@192:/usr/local/src# cat runtime-install.sh
#!/bin/bash
DIR=`pwd`
PACKAGE_NAME="docker-20.10.19.tgz"
DOCKER_FILE=${DIR}/${PACKAGE_NAME}
#read -p "请输入使用docker server的普通用户名称,默认为docker:" USERNAME
if test -z ${USERNAME};then
  USERNAME=docker
fi
centos_install_docker(){
  grep "Kernel" /etc/issue &> /dev/null
  if [ $? -eq 0 ];then
    /bin/echo  "当前系统是`cat /etc/redhat-release`,即将开始系统初始化、配置docker-compose与安装docker" && sleep 1
    systemctl stop firewalld && systemctl disable firewalld && echo "防火墙已关闭" && sleep 1
    systemctl stop NetworkManager && systemctl disable NetworkManager && echo "NetworkManager" && sleep 1
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux && setenforce  0 && echo "selinux 已关闭" && sleep 1
    \cp ${DIR}/limits.conf /etc/security/limits.conf
    \cp ${DIR}/sysctl.conf /etc/sysctl.conf
    /bin/tar xvf ${DOCKER_FILE}
    \cp docker/*  /usr/local/bin
    mkdir /etc/docker && \cp daemon.json /etc/docker
 
    \cp containerd.service /lib/systemd/system/containerd.service
    \cp docker.service  /lib/systemd/system/docker.service
    \cp docker.socket /lib/systemd/system/docker.socket
 
    \cp ${DIR}/docker-compose-Linux-x86_64_1.28.6 /usr/bin/docker-compose
     
    groupadd docker && useradd docker -s /sbin/nologin -g docker
    id -u  ${USERNAME} &> /dev/null
    if [ $? -ne 0 ];then
      useradd ${USERNAME}
      usermod ${USERNAME} -G docker
    else
      usermod ${USERNAME} -G docker
    fi
    docker_install_success_info
  fi
}
 
ubuntu_install_docker(){
  grep "Ubuntu" /etc/issue &> /dev/null
  if [ $? -eq 0 ];then
    /bin/echo  "当前系统是`cat /etc/issue`,即将开始系统初始化、配置docker-compose与安装docker" && sleep 1
    \cp ${DIR}/limits.conf /etc/security/limits.conf
    \cp ${DIR}/sysctl.conf /etc/sysctl.conf
     
    /bin/tar xvf ${DOCKER_FILE}
    \cp docker/*  /usr/local/bin
    mkdir /etc/docker && \cp daemon.json /etc/docker
 
    \cp containerd.service /lib/systemd/system/containerd.service
    \cp docker.service  /lib/systemd/system/docker.service
    \cp docker.socket /lib/systemd/system/docker.socket
 
    \cp ${DIR}/docker-compose-Linux-x86_64_1.28.6 /usr/bin/docker-compose
 
    groupadd docker && useradd docker -r -m -s /sbin/nologin -g docker
    id -u  ${USERNAME} &> /dev/null
    if [ $? -ne 0 ];then
      groupadd  -r  ${USERNAME}
      useradd -r -m -s /bin/bash -g ${USERNAME} ${USERNAME}
      usermod ${USERNAME} -G docker
    else
      usermod ${USERNAME} -G docker
    fi 
    docker_install_success_info
  fi
}
 
ubuntu_install_containerd(){
  DIR=`pwd`
  PACKAGE_NAME="containerd-1.6.20-linux-amd64.tar.gz"
  CONTAINERD_FILE=${DIR}/${PACKAGE_NAME}
  NERDCTL="nerdctl-1.3.0-linux-amd64.tar.gz"
  CNI="cni-plugins-linux-amd64-v1.2.0.tgz"
  RUNC="runc.amd64"
   
  mkdir -p /etc/containerd /etc/nerdctl
  tar xvf ${CONTAINERD_FILE} &&  cp bin/* /usr/local/bin/
  \cp runc.amd64   /usr/bin/runc && chmod  a+x /usr/bin/runc
  \cp config.toml  /etc/containerd/config.toml
  \cp containerd.service /lib/systemd/system/containerd.service
 
  #CNI
  mkdir  /opt/cni/bin -p
  tar xvf ${CNI}  -C  /opt/cni/bin/
 
  #nerdctl
  tar xvf ${NERDCTL}  -C /usr/local/bin/
  \cp nerdctl.toml /etc/nerdctl/nerdctl.toml
 
  containerd_install_success_info
}
 
containerd_install_success_info(){
    /bin/echo "正在启动containerd server并设置为开机自启动!"
    #start containerd  service
    systemctl daemon-reload && systemctl  restart  containerd && systemctl  enable containerd
    /bin/echo "containerd is:" `systemctl  is-active  containerd`
    sleep 0.5 && /bin/echo "containerd server安装完成,欢迎进入containerd的容器世界!" && sleep 1
}
 
docker_install_success_info(){
    /bin/echo "正在启动docker server并设置为开机自启动!"
    systemctl  enable containerd.service && systemctl  restart containerd.service
    systemctl  enable docker.service && systemctl  restart docker.service
    systemctl  enable docker.socket && systemctl  restart docker.socket
    sleep 0.5 && /bin/echo "docker server安装完成,欢迎进入docker世界!" && sleep 1
}
 
usage(){
    echo "使用方法为[shell脚本  containerd|docker]"
}
 
main(){
  RUNTIME=$1
  case ${RUNTIME}  in
    docker)
      centos_install_docker 
      ubuntu_install_docker
      ;;
    containerd)
      ubuntu_install_containerd
      ;;
    *)
      usage;
    esac;
}
 
main $1

执行脚本 参数为containerd
sh runtime-install.sh containerd

查看containerd是否安装成功
image

启动一个nginx测试容器
nerdctl run -it -p 80:80 nginx:1.16.1 /bin/bash

image

3 配置apt源并安装kubeadm、kubelet、kubectl

在master1和node1 node2节点执行

apt-get update && apt-get install -y apt-transport-https -y
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
apt-get update && apt-cache madison kubeadm
apt-get install -y kubeadm=1.26.3-00 kubectl=1.26.3-00 kubelet=1.26.3-00

验证kubeadm的版本信息
kubeadm version

查看部署k8s所需的镜像
kubeadm config images list --kubernetes-version v1.26.3

registry.k8s.io/kube-apiserver:v1.26.3
registry.k8s.io/kube-controller-manager:v1.26.3
registry.k8s.io/kube-scheduler:v1.26.3
registry.k8s.io/kube-proxy:v1.26.3
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.6-0
registry.k8s.io/coredns/coredns:v1.9.3

以上镜像需要FQ下载,因此需要替换国内镜像源

kubeadm config images list  --kubernetes-version v1.26.3 --image-repository="registry.aliyuncs.com/google_containers"
registry.aliyuncs.com/google_containers/kube-apiserver:v1.26.3
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.26.3
registry.aliyuncs.com/google_containers/kube-scheduler:v1.26.3
registry.aliyuncs.com/google_containers/kube-proxy:v1.26.3
registry.aliyuncs.com/google_containers/pause:3.9
registry.aliyuncs.com/google_containers/etcd:3.5.6-0
registry.aliyuncs.com/google_containers/coredns:v1.9.3

指定k8s组件从阿里镜像源下载
kubeadm config images pull --kubernetes-version v1.26.3 --image-repository="registry.aliyuncs.com/google_containers"

k8s初始化

master初始化

kubeadm init --apiserver-advertise-address=196.168.110.206\
 --apiserver-bind-port=6443 \
>              --kubernetes-version=v1.26.3 \
>              --pod-network-cidr=10.100.0.0/16 \
>              --service-cidr=10.200.0.0/16 \
>              --service-dns-domain=cluster.local \
>              --image-repository="registry.aliyuncs.com/google_containers"\ 
>              --ignore-preflight-errors=swap

执行结果

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
 
Alternatively, if you are the root user, you can run:
 
  export KUBECONFIG=/etc/kubernetes/admin.conf
 
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.110.206:6443 --token xc1xea.briuce4ykh8qulcn \
        --discovery-token-ca-cert-hash sha256:9f25b985efb36eefc91dbc6cc1a7591537dd563cfd13e7504ef06b68c3535484

以上代表master初始化完成

创建.kube目录,并拷贝配置文件

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

image

加入node节点

kubeadm join 192.168.110.206:6443 --token xc1xea.briuce4ykh8qulcn \
        --discovery-token-ca-cert-hash sha256:9f25b985efb36eefc91dbc6cc1a7591537dd563cfd13e7504ef06b68c3535484

部署calico网络组件

wget https://docs.projectcalico.org/v3.25/manifests/calico.yaml --no-check-certificate
cat calico.yaml
image

下载calico所需镜像 并根据配置文件声明式部署calico
nerdctl pull docker.io/calico/cni:v3.25.0
kubectl apply -f calico.yaml

之后可看出node网络已正常
image

将配置文件复制到node节点上
scp 192.168.110.206:/root/.kube/config ./.kube/

部署dashboard

下载官方yaml文件 并执行
image

kubectl apply -f dashboard-v2.7.0.yaml -f admin-user.yaml -f admin-secret.yaml
kubectl get pod -n kubernetes-dashboard
image

获取token
kubectl get secret -A | grep admin
kubectl describe secret -n kubernetes-dashboard dashboard-admin-user
image

查看dashboard端口
kubectl get svc -A
image

登录dashboard并将token复制过去

image

成功进入dashboard界面即部署成功
image