摘自知乎:
1、 k8s简介
K8S 是Kubernetes的全称,官方称其是:
Kubernetes is an open source system for managing containerized applications across multiple hosts. It provides basic mechanisms for deployment, maintenance, and scaling of applications.
用于自动部署、扩展和管理“容器化(containerized)应用程序”的开源系统
k8s是负责自当年规划运维管理多个docker程序的集群,比docker swarm门槛高,且功能强大
2、k8s组件
2.1 Master节点组件:
API Server: K8S 的请求入口服务, API Server 负责接收 K8S 所有请求(来自 UI 界面或者 CLI 命令行工具),然后,API Server 根据用户的具体请求,去通知其他组件干活
Scheduler:K8S 所有 Worker Node 的调度器,当用户要部署服务时,Scheduler 会选择最合适的 Worker Node(服务器)来部署
Controller Manager:K8S 所有 Worker Node 的监控器。Controller Manager 有很多具体的 Controller,在文章Components of Kubernetes Architecture中提到的有 Node Controller、Service Controller、Volume Controller 等。Controller 负责监控和调整在 Worker Node 上部署的服务的状态,比如用户要求 A 服务部署 2 个副本,那么当其中一个服务挂了的时候,Controller 会马上调整,让 Scheduler 再选择一个 Worker Node 重新部署服务。
etcd:K8S 的存储服务,etcd 存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server 才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据(见Kubernetes Works Like an Operating System)。
2.2 Work节点组件
Kubelet:Worker Node 的监视器,以及与 Master Node 的通讯器。Kubelet 是 Master Node 安插在 Worker Node 上的“眼线”,它会定期向 Worker Node 汇报自己 Node 上运行的服务的状态,并接受来自 Master Node 的指示采取调整措施。
Kube-Proxy:K8S 的网络代理。私以为称呼为 Network-Proxy 可能更适合?Kube-Proxy 负责 Node 在 K8S 的网络通讯、以及对外部网络流量的负载均衡。
Container Runtime:Worker Node 的运行环境。即安装了容器化所需的软件环境确保容器化程序能够跑起来,比如 Docker Engine。大白话就是帮忙装好了 Docker 运行环境。
Logging Layer:K8S 的监控状态收集器。私以为称呼为 Monitor 可能更合适?Logging Layer 负责采集 Node 上所有服务的 CPU、内存、磁盘、网络等监控项信息。
Add-Ons:K8S 管理运维 Worker Node 的插件组件。有些文章认为 Worker Node 只有三大组件,不包含 Add-On,但笔者认为 K8S 系统提供了 Add-On 机制,让用户可以扩展更多定制化功能,是很不错的亮点。
3、k8s重要概念
3.1 Pod
Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元,可以被理解成一群可以共享网络、存储和计算资源的容器化服务的集合,同一个 Pod 之间的 Container 可以通过 localhost 互相访问,并且可以挂载 Pod 内所有的数据卷;但是不同的 Pod 之间的 Container 不能用 localhost 访问,也不能挂载其他 Pod 的数据卷。
下面是一个Pod的yaml示例:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}
apiVersion
记录 K8S 的 API Server 版本,现在看到的都是v1
,用户不用管。
kind
记录该yaml 的对象,比如这是一份 Pod 的 yaml 配置文件,那么值内容就是Pod。
metadata
记录了 Pod 自身的元数据,比如这个 Pod 的名字、这个 Pod 属于哪个 namespace(命名空间的概念,后文会详述,暂时理解为“同一个命名空间内的对象互相可见”)。
spec
记录了 Pod 内部所有的资源的详细信息,看懂这个很重要:
containers
记录了 Pod 内的容器信息,containers
包括了:name
容器名,image
容器的镜像地址,resources
容器需要的 CPU、内存、GPU 等资源,command
容器的入口命令,args
容器的入口参数,volumeMounts
容器要挂载的 Pod 数据卷等。可以看到,上述这些信息都是启动容器的必要和必需的信息。
volumes
记录了 Pod 内的数据卷信息,后文会详细介绍 Pod 的数据卷
3.2 Volume数据卷
volume 是 K8S 的对象,对应一个实体的数据卷;而 volumeMounts 只是 container 的挂载点,对应 container 的其中一个参数。但是,volumeMounts 依赖于 volume,只有当 Pod 内有 volume 资源的时候,该 Pod 内部的 container 才可能有 volumeMounts。
3.3 Container容器
一个 Pod 内可以有多个容器 container,在 Pod 中,容器也有分类
标准容器 Application Container。
初始化容器 Init Container。
边车容器 Sidecar Container。
临时容器 Ephemeral Container。
一般部署的还是以标准容器为主
3.4 Deployment和ReplicaSet(简称 RS)
Deployment 的作用是管理和控制 Pod 和 ReplicaSet,管控它们运行在用户期望的状态中。哎,打个形象的比喻,Deployment 就是包工头,主要负责监督底下的工人 Pod 干活,确保每时每刻有用户要求数量的 Pod 在工作。如果一旦发现某个工人 Pod 不行了,就赶紧新拉一个 Pod 过来替换它。
ReplicaSet 的作用就是管理和控制 Pod,管控他们好好干活。但是,ReplicaSet 受控于 Deployment。形象来说,ReplicaSet 就是总包工头手下的小包工头。
总结: 从 K8S 使用者角度来看,用户会直接操作 Deployment 部署服务,而当 Deployment 被部署的时候,K8S 会自动生成要求的 ReplicaSet 和 Pod. 用户只需要关心 Deployment 而不操心 ReplicaSet:
ReplicationController 确保在任何时候都有特定数量的 Pod 副本处于运行状态。 换句话说,ReplicationController 确保一个 Pod 或一组同类的 Pod 总是可用的,ReplicationController 是 ReplicaSet 的前身
3.5 Service 和 Ingress
Service官方定义:
将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
使用 Kubernetes,您无需修改应用程序即可使用不熟悉的服务发现机制。 Kubernetes 为 Pods 提供自己的 IP 地址,并为一组 Pod 提供相同的 DNS 名, 并且可以在它们之间进行负载均衡
K8S 中的服务(Service)并不是我们常说的“服务”的含义,而更像是网关层,是若干个 Pod 的流量入口、流量均衡器
Service 主要负责 K8S 集群内部的网络拓扑。那么集群外部怎么访问集群内部呢?这个时候就需要 Ingress 了
Ingress官方定义:
Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。
Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。
3.6 namespace 命名空间
namespace官方定义:
Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。 这些虚拟集群被称为名字空间。
namespace 是为了把一个 K8S 集群划分为若干个资源不可共享的虚拟集群而诞生的,可以通过在 K8S 集群内创建 namespace 来分隔资源和对象
3.7 其他
4、k8s部署
k8s有多种部署方式,对新手来说,kubeadm部署会容易上手些,除非熟悉很多组件并且理解k8s整体框架和流程之后,使用二进制部署才会得心应手,以下为kubeadm部署笔记
4.1. 环境准备
系统环境
系统版本 | docker版本 | role | ip地址 |
CentOS8.4.2105 (Linux version 4.18.0-348.xx Red Hat 8.5.0-4) |
20.10.12 | k8s-master |
192.168.100.129 |
k8s-node1 | 192.168.100.130 | ||
k8s-node2 | 192.168.100.131 |
kubernetes组件
组件 | 版本 |
kubeadm | 1.23.1-0 |
kubectl | 1.23.1-0 |
kubelet | 1.23.1-0 |
docker镜像
REPOSITORY | TAG | IMAGE ID | SIZE |
registry.aliyuncs.com/google_containers/kube-apiserver | v1.23.1 | b6d7abedde39 | 135 MB |
registry.aliyuncs.com/google_containers/kube-proxy | v1.23.1 | b46c42588d51 | 112MB |
registry.aliyuncs.com/google_containers/kube-controller-manager | v1.23.1 | f51846a4fd28 | 125MB |
registry.aliyuncs.com/google_containers/kube-scheduler | v1.23.1 | 71d575efe628 | 53.5MB |
registry.aliyuncs.com/google_containers/etcd | 3.5.1-0 | 25f8c7f3da61 | 293MB |
registry.aliyuncs.com/google_containers/coredns | v1.8.6 | a4ca41631cc7 | 46.8MB |
registry.aliyuncs.com/google_containers/pause | 3.6 | 6270bb605e12 | 683 kB |
4.2. 初始化虚拟机
在开始安装部署之前需要对所有的机器进行初始化环境,避免后续环境问题影响
4.2.1 关闭防火墙
在所有master节点和node节点都需要运行以下命令,只有2.5章节只需要在master上运行即可
systemctl stop firewalld
systemctl disable firewalld
4.2.2 关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config #永久
setenforce 0 # 临时
4.2.3 关闭swap
sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久
swapoff -a # 临时
4.2.4 修改主机名称
hostnamectl set-hostname <hostname> # 示例
hostnamectl set-hostname k8s-master # 在master机器上输入
hostnamectl set-hostname k8s-node1 # 在node1机器上输入
hostnamectl set-hostname k8s-node2 # 在node2机器上输入
4.2.5 只在master中添加hosts
cat > /etc/hosts << EOF
192.168.100.129 k8s-master
192.168.100.130 k8s-node1
192.168.100.131 k8s-node2
EOF
4.2.6 桥接IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
4.2.7 时间同步
rpm -ivh http://mirrors.wlnmp.com/centos/wlnmp-release-centos.noarch.rpm # 添加wlnmp源
yum install wntp
ntpdate time.windows.com
# 如果发现当前区域不一致,可以通过以下命令修改区域
timedatectl # 查看当前区域
timedatectl list-timezone # 查看支持的时区
timedatectl set-timezone Asia/Shanghai # 例如设置当前时区为亚洲/上海时区
4.3. 安装docker/kubeadmi/kubelet
Kubernetes默认CRI(容器运行时)为docker,因此先安装docker,所有节点都要安装并保持版本一致
4.3.1 安装docker
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo # 下载docker-ce源
yum install docker-ce -y # 安装docker-ce
systemctl enable docker && systemctl start docker # 开始docker并设置开机启动
docker --version # 检查docker版本
systemctl status docker # 检查docker当前的状态
4.3.2 添加阿里云软件源
cat << EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
4.3.3 安装kubeadm, kubelet和kubectl
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet && systemctl start kubelet
PS: 由于官网未开放同步方式, 可能会有索引gpg检查失败的情况, 这时请用 yum install -y --nogpgcheck kubelet kubeadm kubectl 安装
4.4 部署Kubernetes Master
4.4.1在 192.168.100.129(master)上执行
kubeadm init \
--apiserver-advertise-address=192.168.100.129 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.23.1 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
# service-cidr和pod-network-cidr需要和其他机器IP不冲突皆可
部署的时候碰到好几个问题还未解决,并且每次init之前都会再reset一下,具体见4.4.2:
1. error execution phase wait-control-plane: couldn't initialize a Kubernetes cluster
To see the stack trace of this error execute with --v=5 or higher
尝试重启下kubelet
systemctl restart kubelet && systemctl enable kubelet
systemctl status kubelet
如果重启kubelet失败,则可能是swap交换分区还开启的原因,再次关闭swapoff -a然后重复上面步骤
2. 我这里初始化一直报错,目前还未解决,后续再更新
[kubelet-check] Initial timeout of 40s passed.
[kubelet-check] It seems like the kubelet isn't running or healthy.
[kubelet-check] The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed with error: Get "http://localhost:10248/healthz": dial tcp [::1]:10248: connect: connection refused.
试过以下办法:
1. 打开/usr/lib/systemd/system/docker.service,然后将代码Environment="NO_PROXY=127.0.0.1/8, 127.0.0.1/16",一定要放在[Service] Type=notify的后面,然后重启daemon和docker,然后重启
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl restart kubelet
无效
2. 在 usr/docker/daemon.json当中添加以下内容, docker的默认驱动为cgroupfs,同步docker驱动到kubelet的默认驱动systemd
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
然后重启
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl restart kubelet
依然无效
3. 有人说swapoff永久关闭,但是我一直都是永久的,重启系统也未起效
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
4. Init的时候增加一个参数--ignore-preflight-errors=Swap
kubeadm init \
--apiserver-advertise-address=192.168.100.129 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.23.1 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
--ignore-preflight-errors=Swap
依然无效
猜测是系统版本,docker版本和k8s版本不兼容
4.4.2 重置kubeadm
sudo kubeadm reset
有时会提示reset process does not clean XXXXX等等信息可以以下方法手动删除
删除net.d
rm -rf /etc/cni/net.d
重置iptables
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
sysctl net.bridge.bridge-nf-call-iptables=1
手动执行以下命令来清除对应的残余网卡信息:
sudo ip link del cni0
sudo ip link del flannel.1
删除 $HOME/.kube/config
rm -rf $HOME/.kube/config