文章目录
- 概述
- K8S架构
- K8S概念组成
-
- Pod
- Pod控制器
-
- ReplicationController(副本控制器)
- [ReplicaSet (副本集)](#ReplicaSet (副本集))
- Deployment
- [StatefulSet (有状态副本集)](#StatefulSet (有状态副本集))
- DaemonSet
- Job
- Cronjob
- Service
- Endpoint
- 网络
- [Ingress Controller](#Ingress Controller)
- K8S安装
- 参考博客
本篇内容属于资料整理,非笔者操作笔记,用于学习记录,其中有问题的地方请指出。
概述
由来
kubernetes,简称K8s,是用8代替8个字符"kubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,即我们常说的容器编排工具,K8S的目标是让部署容器化的应用简单并且高效
k8s是谷歌开源的容器编排工具,其实也是管理应用的全生命周期的一个工具 ,Kubernetes在Docker技术之上,为容器化的应用提供了资源调度、部署运行、服务发现和扩容缩容等丰富多样的功能,从创建应用,应用部署,应用提供服务,扩容缩容,应用更新,都非常的方便,而且可以做到故障自愈,例如一个服务器挂了,可以自动将这个服务器上的服务调度到另外一个主机上进行运行,无需进行人工干涉。如果你曾经用过Docker部署容器,那么可以将Docker看成Kubernetes底层使用的组件,Kubernetes是Docker的上层封装,通过它可以很方便的进行Docker集群的管理。
主要功能
基于容器的应用部署、维护和滚动升级
- 自我修复
- 负载均衡和服务发现
- 跨机器和跨地区的集群调度
- 自动伸缩、水平扩展
- 无状态服务和有状态服务
- 广泛的Volume存储卷的支持
- 插件机制保证扩展性
K8S架构
架构图
组件说明
Cluster
Cluster是计算、存储和网络资源的集合,Kubernetes利用这些资源运行各种基于容器的应用.
Kubernetes Cluster由Master和Node组成,节点上运行着若干Kubernetes服务。
Master
- API server
提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统 的数据总线和数据中心。 - Controlle Manager (kube-controller-manager):
kubernets 里面所有资源对象的自动化控制中心,可以理解为资源对象的大总管;保证集群中各种资 源的状态和用户定义(yaml)的状态一致, 如果出现偏差, 则修正资源的状态(维护容器的数量始终和 定义的一样)。 - Scheduler (kube-scheduler):
负责资源调度(pod调度)的进程,调度器的职责主要是通过调度算 法为新创建的pod在集群中寻找最合适的node,并将pod调度到Node上。 - Controlle Manager (kube-controller-manager)
kubernets 里面所有资源对象的自动化控制中心,可以理解为资源对象的大总管;保证集群中各种资源的状态和用户定义(yaml)的状态一致, 如果出现偏差, 则修正资源的状态(维护容器的数量始终和定义的一样)。 - Scheduler (kube-scheduler)
负责资源调度(pod调度)的进程,调度器的职责主要是通过调度算 法为新创建的pod在集群中寻找最合适的node,并将pod调度到Node上。 - Etcd
Etcd(分布式键值存储)是Kubernetes集群中的一个关键组件。用于持久化存储集群中所有的资源对象,如Node、Service、Pod、RC、Namespace等;API Server提供了操作etcd的封装接口API,这些API基本上都是集群中资源对象的增删改查及监听资源变化的接口。
Etcd是由CoreOS开发的一种高可用性、一致性和分布式的键值存储系统,它作为Kubernetes的后端数据库,负责存储集群状态信息、配置数据和访问控制列表等。Etcd使用Raft一致性算法^1^来保证数据的一致性和可靠性,并提供了简单的API接口供其他组件进行读写操作。
Etcd在Kubernetes中扮演着存储和共享集群配置、元数据和状态信息的角色,为集群的正常运行提供支持。
Node
-
Kubelet
负责pod对应的容器创建、启停等任务,同时与master 节点密切协作,处理 Master 节点下发到本 节点的任务,按照 PodSpec 描述来管理Pod 和其中的容器,实现集群管理的基本功能。
-
kube-proxy
实现Kubernetes Service的服务发现与负载均衡机制的重要组件,比如要通过外网访问k8s就需要该组 件进行代理,容器与容器之间负载均衡也需要kube-proxy。
-
Docker Engine
Docker引擎,负责本机的容器创建和管理工作。
kubectl
kubectl是Kubernetes的命令行工具,用于与Kubernetes集群进行交互和管理。它允许用户通过命令行界面执行各种操作,如创建、删除、更新和查看Kubernetes资源对象(如Pods、Services、Deployments等)。
使用kubectl命令来管理Kubernetes集群,例如:
- 创建和启动应用程序的Pods、Deployments和Services;
- 扩展和缩小应用程序的副本数量;
- 查看和监视集群中的资源状态;
- 更新和回滚应用程序的配置;
- 调试和故障排除集群中的问题;
- 管理命名空间、访问控制和安全策略等。
kubectl提供了丰富的命令选项和参数,可用于满足各种需求。通过与Kubernetes API进行通信,kubectl使得与Kubernetes集群交互变得方便和直观。
组件处理流程
- 通过Kubectl提交一个创建RC的请求,该请求通过API Server被写入etcd中;(存储请求)
- 此时Controller Manager通过API Server的监听资源变化的接口监听到这个RC事件,分析之后,发现当前集群中还没有它所对应的Pod实例,于是根据RC里的Pod模板定义生成一个Pod对象,通过API Server写入etcd;(创建pod)
- 接下来,此事件被Scheduler发现,它立即执行一个复杂的调度流程,为这个新Pod选定一个落户的Node,然后通过API Server将这一结果写入到etcd中;(Pod分配Node)
- 随后,目标Node上运行的Kubelet进程通过API Server监测到这个"新生的"Pod,并按照它的定义,启动该Pod并任劳任怨地负责它的下半生,直到Pod的生命结束。(接管Pod)
- 接着,通过Kubectl提交一个新的映射到该Pod的Service的创建请求;
- Controller Manager会通过Label标签查询到相关联的Pod实例,然后生成Service的Endpoints信息(可被访问的服务端点,即一个状态为running的pod),并通过API Server写入到etcd中;
- 接下来,所有Node上运行的Proxy进程通过API Server查询并监听Service对象与其对应的Endpoints信息,建立一个软件方式的负载均衡器来实现Service访问到后端Pod的流量转发功能。
K8S概念组成
Pod
Pod是K8S中可以创建的最小部署单元,一个Pod代表集群上正在运行的一个进程。Pod代表部署的一个单位,K8S中单个应用的实例,它可能由单个容器或多个容器共享组成。
Pod中的容器共享两种资源:网络和存储。
- 每个Pod被分配一个独立的IP地址,Pod中的每个容器共享网络命名空间,包括IP地址和网络端口;
- Pod可以指定一组共享存储volumes。
Pod管理方式不同,也分为:
- 自助式Pod:Pod退出了,不会被创建。
- 控制器管理的Pod:始终会维持Pod的副本数。
Pod控制器
Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为。
ReplicationController(副本控制器)
确保Pod的数量始终保持设定的个数,如果容器异常退出会自动创建新的Pod来替代,也支持Pod的滚动更新。 已经废弃的Pod建议使用ReplicaSet 。
滚动更新:创建新的版本,然后删除旧的版本,实现版本的最新滚动更新。
ReplicaSet (副本集)
它和ReplicationController没有根本的区别,它支持集合式的Selector(选择多个Pod),但是它不直接使用,由一个声明式更新的控制器叫Deployment来负责管理。
有状态服务:通常指需要持久状态的服务 (Mysql),无状态:通常指无需存储服务状态的服务(tomcat)。
Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 来方便的管理应用,只需要在Deployment中描述你想要的目标状态是什么,Deployment controller就会帮你将Pod和Replica Set的实际状态改变到你的目标状态。
典型的应用场景包括;
- 定义 Deployment 来创建 Pod 和 ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续 Deployment
但是Deployment只能负责管理那些无状态的应用。
StatefulSet (有状态副本集)
负责管理有状态的应用。
使用场景如:
- 稳定的持久化存储,Pod重新调度后还能访问到相同的持久化数据
- 稳定的网络标志,Pod重新调度后PodName和HostName不变
- 有序部署Pod,有序删除Pod
DaemonSet
用来确保每一个Node上只运行一个Pod副本,Node加入集群时为他们创建一个Pod,当有Node从集群中移除时,Pod会被回收,删除DaemonSet将会删除它创建的所有Pod。
使用场景:
为每一个Node创建一个日志收集的Pod
Job
负责批处理任务,即仅执行一次任务。
比如:某个应用生成了一大堆数据集,现在需要临时启动一个Pod去清理这些数据集,清理完成后,这个Pod就可以结束了。 这些不需要一直处于运行状态的应用,就用Job这个类型的控制器去控制。如果Pod运行过程中意外中止了,Job负责重启Pod。如果Pod任务执行完了,就不需要再启动了。
Cronjob
周期性作业。
使用场景:
周期性的执行备份数据库
Service
我们不应该期望 Kubernetes Pod 是健壮的,而是要假设 Pod 中的容器很可能因为各种原因发生故障而死掉。Deployment 等 controller 会通过动态创建和销毁 Pod 来保证应用整体的健壮性。换句话说,Pod 是脆弱的,但应用是健壮的。每个 Pod 都有自己的 IP 地址。当 controller 用新 Pod 替代发生故障的 Pod 时,新 Pod 会分配到新的 IP 地址。
这样就产生了一个问题:
如果一组 Pod 对外提供服务(比如 HTTP),它们的 IP 很有可能发生变化,那么客户端如何找到并访问这个服务呢?Kubernetes 给出的解决方案是 Service。
Service可以看作是一组提供相同服务的Pod对外的访问接口。借助Service,应用可以方便地实现服务发现和负载均衡。
Kubernetes Service 从逻辑上代表了一组 Pod,具体是哪些 Pod 则是由 label 来挑选。Service 有自己 IP,而且这个 IP 是不变的。客户端只需要访问 Service 的 IP,Kubernetes 则负责建立和维护 Service 与 Pod 的映射关系。无论后端 Pod 如何变化,对客户端不会有任何影响,因为 Service 没有变。
ClusterIP
给service指定默认的ClusterIP,这种方式分配的ip只能在集群内部访问。
NodePort
在每个节点上都监听一个同样的端口号(30000-32767),ClusterIP和路由规则会自动创建。集群外部可以访问:联系到集群内部服务,可以配合外部负载均衡使用。
简单理解:使用端口映射方式去访问容器
LoadBalancer
要配合支持公有云负载均衡使用比如GCE、AWS。其实也是NodePort,不过除了使用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。
ExternalName
创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用。
理解Service:
Endpoint
是可被访问的服务端点,即一个状态为running的pod,它是service访问的落点,只有service关联的pod才可能成为endpoint。简单理解:endpoint 用来记录一个service对应的所有pod的访问地址。
网络
- 节点网络
各主机(Master、Node、ETCD等)自身所属的网络,地址配置在主机的网络接口,用于各主机之间的通信,又称为节点网络。 - Pod网络
专用于Pod资源对象的网络,它是一个虚拟网络,用于为各Pod对象设定IP地址等网络参数,其地址配置在Pod中容器的网络接口上。Pod网络需要借助kubenet插件或CNI插件实现。 - Service网络
专用于Service资源对象的网络,它也是一个虚拟网络,用于为K8S集群之中的Service配置IP地址,但是该地址不会配置在任何主机或容器的网络接口上,而是通过Node上的kube-proxy配置为iptables或ipvs规则,从而将发往该地址的所有流量调度到后端的各Pod对象之上。
Ingress Controller
Service 是后端真实服务的抽象,一个 Service 可以代表多个相同的后端服务。
Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上。
Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service。
K8S安装
安装方式选择
安装部署主要方式分为三大类:minikube(单机) ,kubeadmin,二进制包(生产环境) , 我们这里采用kubeadmin的方式来安装。
Minikube
最为单机运行的k8s集群,直接使用官网感受一下,点击launch terminal ,浏览器下发会弹出命令界面。
Kubeadmin
配置基础环境 -> 安装kubeadmin部署工具 -> 使用kubeadmin配置master 、node、网络、dashboard等等。下面使用这种方式安装。
二进制包
相比上述两种有些复杂,但是可以通过二进制安装学到不少东西。
K8S集群准备
环境准备(一个Master两个Node)
推荐配置:内存4G以上,CPU 2 核以上 ,安装ContOS的磁盘 100G以上,网络使用桥接。
- 设置静态IP(三台)
可以通过可视化界面修改
bash
vi /etc/sysconfig/network-scripts/ifcfg-ens32
bash
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static" # 使用静态IP地址,默认为dhcp
IPADDR="192.168.241.100" # 设置的静态IP地址
NETMASK="255.255.255.0" # 子网掩码
GATEWAY="192.168.241.1" # 网关地址
DNS1="192.168.241.1" # DNS服务器
DNS2="119.29.29.29"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="ens33"
DEVICE="ens33"
ONBOOT="yes" #是否开机启用
bash
## 删除
rm -f /etc/udev/rule.d/70-persistent-net.rules
reboot 查看ip,和上网
- 分别设置主机名
bash
hostnamectl set-hostname k8smaster
hostnamectl set-hostname k8snode01
hostnamectl set-hostname k8snode02
- 确保网络ok
bash
ping www.baidu.com
初始化环境(三台)
- 设置hosts
bash
vi /etc/hosts
bash
172.16.7.252 k8snode02
172.16.7.251 k8snode01
172.16.7.250 k8smaster
- 关闭防火墙
bash
# 关闭防火墙,并禁止开机启动
systemctl stop firewalld && systemctl disable firewalld
# 查看防火墙状态
systemctl status firewalld
- 禁用selinux
bash
# 临时禁用
setenforce 0
# 永久禁用
vim /etc/sysconfig/selinux
修改:SELINUX=disabled
#查看selinux的状态信息
/usr/sbin/sestatus
- 禁用交换分区
bash
# 临时关闭
swapoff -a
# 永久关闭
vi /etc/fstab
# 注释掉以下字段
/dev/mapper/cl-swap swap swap defaults 0 0
- 创建k8s配置
bash
# 写入配置
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness=0
EOF
# 执行命令使修改生效
modprobe br_netfilter
# 查看
sysctl -p /etc/sysctl.d/k8s.conf
- kube-proxy开启ipvs的前置条件
bash
# 保证在节点重启后能自动加载所需模块
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
bash
# 加上执行权限
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4
# 查看是否已经正确加载所需的内核模块
lsmod | grep -e ip_vs -e nf_conntrack_ipv4
# 安装了ipset软件包
yum -y install ipset
# 为了便于查看ipvs的代理规则,安装管理工具ipvsadm
yum -y install ipvsadm
- 同步时间
bash
yum -y install ntp ntpdate
ntpdate cn.pool.ntp.org
hwclock --systohc
timedatectl
安装docker(三台)
- 卸载旧版本
bash
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
- 安装
bash
# 预装工具
yum install -y yum-utils device-mapper-persistent-data lvm2
# 配置docker源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 更新yum缓存
sudo yum makecache fast
# 查看版本
yum list docker-ce --showduplicates | sort -r
# 安装指定版本
yum install docker-ce-18.06.3.ce-3.el7
# 安装(最新版本)
sudo yum -y install docker-ce
- 配置镜像加速
bash
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://5pfmrxk8.mirror.aliyuncs.com"]
}
EOF
- 启动
bash
systemctl daemon-reload && systemctl start docker && systemctl enable docker
注意:确认一下iptables filter表中FOWARD链的默认策略(pllicy)为ACCEPT
bash
iptables -nvL
Chain INPUT (policy ACCEPT 9 packets, 760 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
如果不是ACCEPT,则修改
bash
iptables -P FORWARD ACCEPT
8.8.8.8
安装K8S集群
安装kubeadm, kubelet and kubectl(三台)
- 配置yum路径
bash
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
- 安装kubeadm, kubelet and kubectl
bash
yum install -y kubelet-1.15.6 kubeadm-1.15.6 kubectl-1.15.6
- 启动
bash
systemctl enable kubelet && systemctl start kubelet
配置kubeadm(master)
- 创建kubeadm配置文件
bash
kubeadm config print init-defaults --kubeconfig ClusterConfiguration > kubeadm.yml
- 编辑配置文件
bash
vim kubeadm.yml
bash
#只需要Master创建,创建好之后修改配置文件内容
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.1.250 #master地址
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: k8smaster
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: registry.cn-hangzhou.aliyuncs.com/google_containers #修改镜像
kind: ClusterConfiguration
kubernetesVersion: v1.15.0
networking:
dnsDomain: cluster.local
podSubnet: "192.168.0.0/16" # 集群的网络
serviceSubnet: 10.96.0.0/12 #子网掩码
scheduler: {}
# 开启 IPVS 模式,在 scheduler:{}下面加上 --- 然后复制下面内容
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
featureGates:
SupportIPVSProxyMode: true
mode: ipvs
下载镜像(三台)
- 查看所需镜像列表
bash
kubeadm config images list --config kubeadm.yml
# 拉取镜像 - 不要执行下面这个命令
kubeadm config images pull --config kubeadm.yml
# 注意:由于下载很慢,所以采用已经打包好的镜像
docker镜像批量打包
由于在内网环境或网速较慢的时候,下载镜像比较慢,所以可以将镜像打包成文件进行拷贝。这里写了一个批量打包镜像的语句。
批量打包镜像:
bash
将机器上的所有镜像打包到haha.tar文件里面。
docker save $(docker images | grep -v REPOSITORY | awk 'BEGIN{OFS=":";ORS=" "}{print $1,$2}') -o k8simgs.tar
#打包指定镜像:
docker save imgName2:version imgName2:version-o /打包的镜像名.tar
#机器之间拷贝文件
scp -r /k8simgs.tar root@192.168.1.100:/
# 加载镜像:
docker load -i /k8simgs.tar
然后docker images就可以看到拷贝过来的镜像了。
- 上传打包好的镜像
bash
# 使用ftp工具上传到目录
/root/k8simgs.tar
- 在三台机器加载镜像
bash
#拷贝文件到另外两个centos
scp -r /root/k8simgs.tar root@192.168.0.114:/root/k8simgs.tar
也可以把压缩包上传到三个cenos分别再加载。
- 加载镜像
bash
docker load -i /root/k8simgs.tar
初始化master
- 初始化,进入主节点kubeadm.yml 所在目录执行
bash
kubeadm init --config=kubeadm.yml
如果要重新初始化可以执行:kubeadm reset 重置。
- Master执行配置,从上面输出中拷贝
bash
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
- 验证成功
bash
kubectl get node
# 并且拷贝命令到个节点执行
加入node
- 将 slave 加入到集群拷贝命令,从上面输出中拷贝,不要拷贝我的,要拷贝你自己的日志里面
bash
kubeadm join 172.16.40.252:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:9f792d9c1bf57977ff22f317b599504a733b3f66688273ac3aa7505931f8e378
- 验证是否加入成功
bash
kubectl get nodes
这里的status是NotReady是因为容器之间还没通信。
-
加入失败
如果 slave 节点加入 master 时配置有问题可以在 slave 节点上使用 kubeadm reset 重置配置再使用 kubeadm join 命令重新加入即可。希望在 master 节点删除 node ,可以使用 kubeadm delete nodes 删除。
可以使用:journalctl -f -u kubelet查看错误日志
k8s 集群 节点状态显示notready -
Pod 状态查看
bash
kubectl get pod -n kube-system -o wide
由此可以看出 coredns 尚未运行,此时我们还需要安装网络插件。
安装网络插件
-
容器网络
容器之间需要通信需要安装网络插件,我们使用CNI插件 ,容器网络是容器选择连接到其他容器、主和外部网络的机制。容器的 runtime 提供了各种网络模式,每种模式都会产生不同的体验。例如,Docker 默认情况下可以为容器配置以下网络:
-
bridge 网络:这是 Docker 默认的网络模式。在此模式下,Docker 守护进程会创建一个名为 docker0 的虚拟网桥,并为每个新容器分配一个 IP 地址。容器可以通过此网桥与宿主机和其他容器进行通信。它还使用 NAT(Network Address Translation)来实现容器与外部网络的通信。
-
none: 容器没有网络接口。容器仅能通过 Unix Socket 进行与宿主机通信。这种模式适用于一些特殊的用例,如只需要运行某些系统工具的容器。
-
host: 容器与宿主机共享网络栈。容器直接使用宿主机的网络接口和 IP 地址,因此容器可以通过宿主机的 IP 直接与外部网络通信。这意味着容器与宿主机共享相同的网络命名空间。
-
自定义网桥:用户定义的网桥,具有更多的灵活性、隔离性和其他便利功能
默认的网络模式不适用,这里使用CNI。
-
什么是 CNI
CNI(Container Network Interface) 是一个标准的,通用的接口。在容器平台,Docker,Kubernetes,Mesos 容器网络解决方案 flannel(Docker提供),calico(Kubernetes提供),weave(Mesos 提供)。只要提供一个标准的接口,就能为同样满足该协议的所有容器平台提供网络功能,而 CNI 正是这样的一个标准接口协议。
-
Kubernetes 中的 CNI 插件
CNI 的初衷是创建一个框架,用于在配置或销毁容器时动态配置适当的网络配置和资源。插件负责为接口配置和管理 IP 地址,并且通常提供与 IP 管理、每个容器的 IP 分配、以及多主机连接相关的功能。容器运行时会调用网络插件,从而在容器启动时分配 IP 地址并配置网络,并在删除容器时再次调用它以清理这些资源。
运行时或协调器决定了容器应该加入哪个网络以及它需要调用哪个插件。然后,插件会将接口添加到容器网络命名空间中,作为一个 veth 对的一侧。接着,它会在主机上进行更改,包括将 veth 的其他部分连接到网桥。再之后,它会通过调用单独的 IPAM(IP地址管理)插件来分配 IP 地址并设置路由。
在 Kubernetes 中,kubelet 可以在适当的时间调用它找到的插件,为通过 kubelet 启动的 pod进行自动的网络配置。
Kubernetes 中可选的 CNI 插件如下:Flannel、Calico、Canal 、Weave, 这里使用Calico
-
什么是 Calico
Calico 为容器和虚拟机提供了安全的网络连接解决方案,并经过了大规模生产验证(在公有云和跨数千个集群节点中),可与 Kubernetes,OpenShift,Docker,Mesos,DC / OS 和 OpenStack 集成。
Calico 还提供网络安全规则的动态实施。使用 Calico 的简单策略语言,您可以实现对容器,虚拟机工作负载和裸机主机端点之间通信的细粒度控制。
-
安装 Calico(三台)参考官方文档安装
bash
kubectl apply -f https://docs.projectcalico.org/v3.9/manifests/calico.yaml
注意如果node下载不了,直接在所有节点通过docker pull下载
- 验证成功
watch kubectl get pods --all-namespaces - 查看Nodes
kubectl get nodes
测试常用命令
- 检查组件运行状态
bash
kubectl get cs
# 输出如下
NAME STATUS MESSAGE ERROR
# 调度服务,主要作用是将 POD 调度到 Node
scheduler Healthy ok
# 自动化修复服务,主要作用是 Node 宕机后自动修复 Node 回到正常的工作状态
controller-manager Healthy ok
# 服务注册与发现
etcd-0 Healthy {"health":"true"}
- 检查 Master 状态
bash
kubectl cluster-info
# 输出如下
# 主节点状态
Kubernetes master is running at https://172.16.33.165:6443
# DNS 状态
KubeDNS is running at
https://172.16.33.165:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
- 检查 Nodes 状态
bash
kubectl get nodes
# 输出如下,STATUS 为 Ready 即为正常状态
[root@kmaster-01 calico]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
kmaster-01 Ready master 22m v1.15.2
knode-01 Ready <none> 11m v1.15.2
- 查看全部 Pods 的状态
bash
kubectl get pods
kubectl get pods 等价于 kubectl get pods -n default ,default是默认的名称空间
kubectl get pods -n kube-system
# kube-system 是k8s内部组件的名称空间,
输出如下,需要等待一小段实践,STATUS 为 Running 即为运行成功
NAME READY STATUS RESTARTS AGE
nginx-755464dd6c-qnmwp 1/1 Running 0 90m
nginx-755464dd6c-shqrp 1/1 Running 0 90m
- 查看已部署的服务
bash
kubectl get deployment
# 输出如下
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 91m
- 映射服务,让用户可以访问
bash
kubectl expose deployment nginx --port=80 --type=LoadBalancer
# 输出如下
service/nginx exposed
- 查看已发布的服务
bash
kubectl get services
# 输出如下
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 44h
# 由此可见,Nginx 服务已成功发布并将 80 端口映射为 31738
nginx LoadBalancer 10.108.121.244 <pending> 80:31738/TCP 88m
- 查看服务详情
bash
kubectl describe service nginx
# 输出如下
Name: nginx
Namespace: default
Labels: run=nginx
Annotations: <none>
Selector: run=nginx
Type: LoadBalancer
IP: 10.108.121.244
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 31738/TCP
Endpoints: 192.168.17.5:80,192.168.8.134:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
- 验证是否成功
通过浏览器访问 Master 服务器
http://172.16.33.165:31738/
此时 Kubernetes 会以负载均衡的方式访问部署的 Nginx 服务,能够正常看到 Nginx 的欢迎页即表示成功。容器实际部署在其它 Node 节点上,通过访问 Node 节点的 IP:Port 也是可以的。 - 停止服务
bash
kubectl delete deployment nginx
# 输出如下
deployment.extensions "nginx" deleted
kubectl delete service nginx
# 输出如下
service "nginx" deleted
bash
# 看系统日志
cat /var/log/messages
# 用kubectl 查看日志
# 注意:使用Kubelet describe 查看日志,一定要带上 命名空间,否则会报如下错误
[root@node2 ~]# kubectl describe pod coredns-6c65fc5cbb-8ntpv
Error from server (NotFound): pods "coredns-6c65fc5cbb-8ntpv" not found
kubectl describe pod kubernetes-dashboard-849cd79b75-s2snt --namespace kube-system
kubectl logs -f pods/monitoring-influxdb-fc8f8d5cd-dbs7d -n kube-system
kubectl logs --tail 200 -f kube-apiserver -n kube-system |more
kubectl logs --tail 200 -f podname -n jenkins
# 用journalctl查看日志非常管用
journalctl -u kube-scheduler
journalctl -xefu kubelet
journalctl -u kube-apiserver
journalctl -u kubelet |tail
journalctl -xe
# 用docker查看日志
docker logs c36c56e4cfa3 (容器id)
# 换3.9版本
# 先现在node
# 杀死所有正在运行的容器
docker kill $(docker ps -a -q)
删除所有已经停止的容器
docker rm $(docker ps -a -q)
删除所有未打 dangling 标签的镜
docker rmi $(docker images -q -f dangling=true)
删除所有镜像
docker rmi $(docker images -q)
强制删除 无法删除的镜像
docker rmi -f <IMAGE_ID>
docker rmi -f $(docker images -q)
~/.bash_aliases
杀死所有正在运行的容器.
alias dockerkill='docker kill $(docker ps -a -q)'
删除所有已经停止的容器.
alias dockercleanc='docker rm $(docker ps -a -q)'
删除所有未打标签的镜像.
alias dockercleani='docker rmi $(docker images -q -f dangling=true)'
删除所有已经停止的容器和未打标签的镜像.
alias dockerclean='dockercleanc || true && dockercleani'
K8s资源清单
什么是资源
k8s中所有的内容都被抽象为资源,资源实例化之后,叫做对象。简单理解资源清单就是一个编写好的资源文件,k8s根据资源清单来进行pod的创建
资源分类
- 名称空间级别
这一类资源仅在此名称空间下生效,k8s的系统组件是默认放在kube-system名称空间下的,而kubectl get pod等价于kubectl get pod -n default,因此查看不到k8s的系统组件。
- 工作负载型资源(workload):Pod【k8s最小组成部分,共享网络栈共享存储卷】、ReplicaSet【RS,调度器、控制器,通过标签去控制pod的创建、副本数量】、Deployment【控制器,通过控制RS的创建去创建pod】、StatefulSet【为有状态服务所建立的管理器】、DaemonSet【可以在每一个节点都运行一个pod的组件】、Job【工作、任务】、CronJob【轮询工作、轮询任务,为批处理而生的】(ReplicationController在v1.11版本被废弃)
- 服务发现及负载均衡型资源(ServiceDiscovery LoadBalance):Service【简称svc,服务,将服务暴露出去】、Ingress【将服务暴露出去】、...
- 配置与存储型资源:Volume(存储卷)【给pod提供持久化的能力】、CSI(容器存储接口,可以扩展各种各样的第三方存储卷)
- 特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型)【一般用来存储配置文件达到热更新的状态】、Secret(保存敏感数据)【加密方案存储数据,一般用来保存密码文件、密钥等等】、DownwardAPI(把外部环境中的信息输出给容器)【类似于CSI】
-
集群级别
不管在任何名称空间下定义,在其他的名称空间下都能看得到,在定义的时候无需指定名称空间 例如:Namespace【名称空间】、Node【节点】、Role【角色】、ClusterRole、RoleBinding、ClusterRoleBinding
-
元数据级别
提供一个指标,不像是名称空间类型又不像集群级别,本质上更像是在两者之间,但是它有自己的特点,所以更应该作为一个单独的分类,例如HPA【通过cpu的利用率进行平滑扩展】就是一个很明显的元数据类型,通过指标进行操作。
根据一些指标去进行对应的操作
例如:HPA、PodTemplate【pod模板】、LimitRange【资源限制】
资源清单
- 什么是资源清单
k8s一般都是通过定义资源清单的方式去创建资源,资源清单等价于剧本,写好了每一步应该如何去做。在k8s中,一般使用yaml格式的文件来创建符合我们预期期望的资源,这样的yaml文件我们一般称为资源清单。 - 资源清单定义格式
必须存在的字段:
具体定义使用yaml格式如下:
bash
apiVersion: group/apiversion #如果没有给定group名称,那么默认为core,可以使用kubectl api-versions命令获取当前k8s版本上所有的apiversion版本信息(每个版本可能不同)
kind: #资源类别
metadata: #资源元数据
name:
namespace:
lables:
annotations: #主要目的是方便用户阅读查找
spec: #期望的状态(disired state)
status: #当前状态,本字段由Kubernetes自身维护,用户不能去定义
apiVersion: v1
kind: Pod #定义pod资源
metadata:
name: myapp-pod #pod的名字
labels:
app: myApp #pod标签
version: v1 #pod的版本
spec: #pod的详细配置
containers: #pod包含的多个容器配置
- name: app #第一个容器
image: myapp:v1 #容器版本
- name: myapp # 第二个容器,报错,删除后没有问题
image: myapp:v1 #容器版本
- 常见命令
查看pod的yml清单配置语法
bash
kubectl explain pod
# 这个命令会告诉我们,编写一个pod资源的yml清单应该使用那些语法
kubectl explain pod.apiVersion
2. 导出yml资源清单
bash
kubectl get pods # 查看有那些pod
kubectl get pod pod的名字 -o yaml
工作负载型资源(workload)
Pod
Pod是K8S中可以创建的最小部署单元,一个Pod代表集群上正在运行的一个进程。Pod代表部署的一个单位:K8S中单个应用的实例,它可能由单个容器或多个容器共享组成。
演示案例:把一个Nignx容器运行在一个Pod中
- 创建资源文件
bash
vi poddemo.yaml # 内容如下
- 添加如下内容
bash
apiVersion: v1
kind: Pod
metadata:
name: app-pod #pod名字
labels:
app: app-label #pod的标签
version: v1
spec:
containers:
- name: app #容器名字
image: nginx #容器镜像
imagePullPolicy: IfNotPresent #或者 Never 从本地找镜像
- 根据资源文件创建pod
bash
kubectl apply -f poddemo.yaml
- 相关命令
bash
kubectl get pod # 查看pod
kubectl get pod -o wide # 详细信息,包括ip
kubectl describe pod app-pod # 查询pod描述 可以看到那个pod启动状态
kubectl logs app-pod -c app # 查看pod里面那个容器的启动状态
kubectl delete pod app-pod # 删除指定pod
kubectl delete -f poddemo.yaml # 删除全部
kubectl create -f poddemo.yaml # 效果和kubectl apply差不多
Pod控制器Replicaset
通常不直接部署及管理Pod,而是借助控制器Controller进行管理,包括 ReplicationController(老版本的)、ReplicaSet、Deployment、StatefulSet、Job等。Pod控制器通常包含三个组成部分:标签选择器、期望的副本数、Pod模板。
Replicaset是ReplicationController的替代者,确保Pod副本数在任一时刻都精确满足期望值,可以进行扩缩容,也可以进行升级。
- 创建资源文件
bash
vi rs.yaml
- 加入如下内容
bash
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-example #RS的名字
spec:
replicas: 2 #创建2个pod副本
selector: #选择什么样的pod
matchLabels:
app: rs-demo #选择名字叫rs-demo的pod
template: #定义pod的模板
metadata:
labels:
app: rs-demo #pod的标签,正好被RS选择
spec:
containers: #pod中的容器配置
- name: myapp
image: nginx
imagePullPolicy: Never #IfNotPresent如果不存在再去网络拉取
ports: #暴露容器的端口
- name: http
containerPort: 80
- 创建ReplicaSet
bash
kubectl create -f rs.yaml
- 相关命令
bash
kubectl get pods
删除pod后会自动复制
bash
Kubectl delete pod --all
显示标签
bash
kubectl get pods --show-labels
修改标签
bash
kubectl label pod rs-example-knjhx app=rs-demo1 --overwrite=true
更改后lable后重新补齐
Pod控制器Deployment
Deployment构建于ReplicaSet之上, 支持事件和状态查看,回滚,版本记录,暂停和启动升级,多种自动更新方案:Recreate(先删除再新建),Deployment支持RollingUpdate(滚动升级,逐步替换)
什么是滚动升级:如有三个副本,先建立一个新的副本,然后删除一个老的副本,再建立一个新的副本,删除一个老的副本
- 准备镜像(可以跳过)
我们基于tomcat准备三个不同版本的tomcat镜像,为Deployment做滚动升级做准备,您可以按照如下步骤打包三个tomcat镜像,也可以使用课件资料中的resources/tomcatimgs.tar我已经准备好的资源镜像包,如果使用我的镜像包,就上传tomcatimgs.tar到三个k8s服务器(/root目录),执行docker load -i /root/tomcatimgs.tar 即可加载三个版本的镜像。
- 下载tomcat镜像
bash
docker pull tomcat
- 运行tomcat容器
bash
docker run -id --name=tomcat -p 8080:8080 tomcat
- 准备index.jsp
bash
<%@ page language="java" contentType="text/html; charset=utf-8" import="java.net.InetAddress"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>index.jsp</title>
</head>
<body>
<h2>v1</h2>
<%
InetAddress addr = InetAddress.getLocalHost();
out.println("主机地址:"+addr.getHostAddress());
out.println("主机名:"+addr.getHostName());
%>
</body>
</html>
- 创建镜像
修改分别得到tomcat:v1 tomcat:v2 tomcat:v3
bash
docker exec -it tomcat /bin/bash 进入容器
mkdir /usr/local/tomcat/webapps/ROOT
exit 退出容器
vim index.jsp 创建页面,拷贝上面jsp内容
docker cp index.jsp tomcat:/usr/local/tomcat/webapps/ROOT/
http://192.168.0.113:8080/ 访问测试
docker commit tomcat tomcat:v1 构建镜像:tomat:v1
修改index.jsp内容: <h2>v2</h2>
docker cp index.jsp tomcat:/usr/local/tomcat/webapps/ROOT/
http://192.168.0.113:8080/ 访问测试
docker commit tomcat tomcat:v2 构建镜像:tomat:v2
修改index.jsp内容: <h2>v3</h2>
docker cp index.jsp tomcat:/usr/local/tomcat/webapps/ROOT/
http://192.168.0.113:8080/ 访问测试
docker commit tomcat tomcat:v3 构建镜像:tomat:v3
- 拷贝镜像
打包三个镜像共享给其他节点
bash
docker save tomcat:v1 tomcat:v2 tomcat:v3 -o /root/tomcatimgs.tar
# 其他两个节点做
scp -r tomcatimgs.tar root@192.168.0.114:/root
- 加载镜像
bash
docker load -i /root/tomcatimgs.tar
- Deployment控制pod
(1) 创建pod
- 创建资源文件
bash
vi deploy.yaml
- 加入如下内容
bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-example
spec:
replicas: 2
selector:
matchLabels:
app: deploy-demo
template:
metadata:
labels:
app: deploy-demo
spec:
containers:
- name: myapp
image: tomcat:v1 #这里是对应我们三个tomcat镜像
imagePullPolicy: Never #IfNotPresent如果不存在再去网络拉取
ports:
- name: http
containerPort: 8080
- 创建Deployment
bash
kubectl apply -f deploy.yaml
需要注意:三个k8s机器上都要有镜像:tomcat:v1;tomcat:v2:tomcat:v3
- 查看pods
bash
kubectl get pods -o wide # 查看pod详情
curl 192.168.32.168:8080 # 访问容器,通过pod的网络访问,外网目前访问不到
kubectl get deployments # 查看deployments
(2) 扩容缩容
- 方式一
使用命令修改pod数量
bash
kubectl scale deployment deploy-example --replicas=3 # 修改pod数量到 3 个
- 方式2
直接修改yaml文件的方式进行扩容
bash
spec:
replicas: 5
- 方式3
通过打补丁的方式进行扩容 - 了解
bash
kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
(3) 版本更新
这里有两种方式:1)滚动更新(rolling update) ; 2)重新创建(recreate) 。默认为滚动更新
1)滚动更新:使用2个ReplicaSet,RS1删除一个旧的pod,RS2创建一个新的pod,依次类推实现pod滚动升级
2)重新创建:使用1个ReplicaSet,删除一个,创建一个,依次类推
方式1:yaml改镜像版本并应用
-
复制资源文件进行修改
cp deploy.yaml deploy1.yaml
-
把镜像版本修改为tomcat:v2 ,进行镜像升级vi deploy1.yaml
-
应用资源文件
kubectl apply -f deploy1.yaml
-
查看Replicaset
kubectl get rs 查看deployement
多一个deployeement,原本的 3 个pod已经被干掉变成了 0 ,创建了新的 2 个 pod ,因为我新的资源文件中的replicas值为2 -
查看,访问,测试一下,容器中的项目版本已经更新
bash
kubectl get pods -o wide # 查看pod网络
curl 192.168.32.179:8080 # 访问pod
方式2:命令设置镜像
- 设置镜像版本
bash
kubectl set image deployment/deploy-example myapp=tomcat:v2
# deploy-example : deployment的名字
# myapp=tomcat:v2 镜像名=镜像:版本
- 查看rs
bash
kubectl get rs
- 查看pod
bash
kubectl get pods
- 访问容器内容
bash
curl 192.168.185.220:8080
(4) 版本还原
- 查看历史
bash
kubectl rollout history deploy deploy-example
- 查看具体版本
bash
kubectl rollout history deploy deploy-example --revision=1
- 回退版本
bash
kubectl rollout undo deploy deploy-example --to-revision=1
参考博客
-
Raft(Raft一致性算法)是一种用于分布式系统中实现一致性的共识算法。它旨在提供容错性和可理解性,使得在网络不可靠或节点故障的情况下,分布式系统仍能保持一致性。
Raft算法通过选举一个领导者(称为"leader")来管理复制状态机的日志复制过程。领导者负责接收客户端请求,并将它们复制到其他节点上的日志中。当多数节点确认接收到日志后,该日志被认为是已提交的,然后被应用到状态机中。这种方式确保了一致性。
Raft算法关注三个关键问题:领导选举、日志复制和安全性 。领导选举确保了集群中只有一个领导者,避免冲突和混乱。日志复制确保了所有节点持有相同的日志序列,从而达到一致性。安全性方面,Raft算法使用了多数派原则 ,在大多数节点正常运行的情况下,才能保证系统的正常运行。
相比于一些其他共识算法,如Paxos,Raft算法更易于理解和实现。由于其简洁性和可理解性,Raft算法被广泛应用于分布式系统,包括Kubernetes集群中的Etcd组件。 ↩︎