kubernetes,简称K8s,是用8代替8个字符“kubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,即我们常说的容器编排工具,K8S的目标是让部署容器化的应用简单并且高效
k8s是谷歌开源的容器编排工具,其实也是管理应用的全生命周期的一个工具,Kubernetes在Docker技术之上,为容器化的应用提供了资源调度、部署运行、服务发现和扩容缩容等丰富多样的功能,从创建应用,应用部署,应用提供服务,扩容缩容,应用更新,都非常的方便,而且可以做到故障自愈,例如一个服务器挂了,可以自动将这个服务器上的服务调度到另外一个主机上进行运行,无需进行人工干涉。如果你曾经用过Docker部署容器,那么可以将Docker看成Kubernetes底层使用的组件,Kubernetes是Docker的上层封装,通过它可以很方便的进行Docker集群的管理。
基于容器的应用部署、维护和滚动升级
Cluster是计算、存储和网络资源的集合,Kubernetes利用这些资源运行各种基于容器的应用.
Kubernetes Cluster由Master和Node组成,节点上运行着若干Kubernetes服务。
Kubelet
负责pod对应的容器创建、启停等任务,同时与master 节点密切协作,处理 Master 节点下发到本 节点的任务,按照 PodSpec 描述来管理Pod 和其中的容器,实现集群管理的基本功能。
kube-proxy
实现Kubernetes Service的服务发现与负载均衡机制的重要组件,比如要通过外网访问k8s就需要该组 件进行代理,容器与容器之间负载均衡也需要kube-proxy。
Docker Engine
Docker引擎,负责本机的容器创建和管理工作。
kubectl是Kubernetes的命令行工具,用于与Kubernetes集群进行交互和管理。它允许用户通过命令行界面执行各种操作,如创建、删除、更新和查看Kubernetes资源对象(如Pods、Services、Deployments等)。
使用kubectl命令来管理Kubernetes集群,例如:
kubectl提供了丰富的命令选项和参数,可用于满足各种需求。通过与Kubernetes API进行通信,kubectl使得与Kubernetes集群交互变得方便和直观。
Pod是K8S中可以创建的最小部署单元,一个Pod代表集群上正在运行的一个进程。Pod代表部署的一个单位,K8S中单个应用的实例,它可能由单个容器或多个容器共享组成。
Pod中的容器共享两种资源:网络和存储。
Pod管理方式不同,也分为:
Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为。
确保Pod的数量始终保持设定的个数,如果容器异常退出会自动创建新的Pod来替代,也支持Pod的滚动更新。 已经废弃的Pod建议使用ReplicaSet 。
滚动更新:创建新的版本,然后删除旧的版本,实现版本的最新滚动更新。
它和ReplicationController没有根本的区别,它支持集合式的Selector(选择多个Pod),但是它不直接使用,由一个声明式更新的控制器叫Deployment来负责管理。
有状态服务:通常指需要持久状态的服务 (Mysql),无状态:通常指无需存储服务状态的服务(tomcat)。
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 来方便的管理应用,只需要在Deployment中描述你想要的目标状态是什么,Deployment controller就会帮你将Pod和Replica Set的实际状态改变到你的目标状态。
典型的应用场景包括;
但是Deployment只能负责管理那些无状态的应用。
负责管理有状态的应用。
使用场景如:
用来确保每一个Node上只运行一个Pod副本,Node加入集群时为他们创建一个Pod,当有Node从集群中移除时,Pod会被回收,删除DaemonSet将会删除它创建的所有Pod。
使用场景:
为每一个Node创建一个日志收集的Pod
负责批处理任务,即仅执行一次任务。
比如:某个应用生成了一大堆数据集,现在需要临时启动一个Pod去清理这些数据集,清理完成后,这个Pod就可以结束了。 这些不需要一直处于运行状态的应用,就用Job这个类型的控制器去控制。如果Pod运行过程中意外中止了,Job负责重启Pod。如果Pod任务执行完了,就不需要再启动了。
周期性作业。
使用场景:
周期性的执行备份数据库
我们不应该期望 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 没有变。
给service指定默认的ClusterIP,这种方式分配的ip只能在集群内部访问。
在每个节点上都监听一个同样的端口号(30000-32767),ClusterIP和路由规则会自动创建。集群外部可以访问:联系到集群内部服务,可以配合外部负载均衡使用。
简单理解:使用端口映射方式去访问容器
要配合支持公有云负载均衡使用比如GCE、AWS。其实也是NodePort,不过除了使用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。
创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用。
理解Service:
是可被访问的服务端点,即一个状态为running的pod,它是service访问的落点,只有service关联的pod才可能成为endpoint。简单理解:endpoint 用来记录一个service对应的所有pod的访问地址。
Service 是后端真实服务的抽象,一个 Service 可以代表多个相同的后端服务。
Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上。
Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service。
安装部署主要方式分为三大类:minikube(单机) ,kubeadmin,二进制包(生产环境) , 我们这里采用kubeadmin的方式来安装。
最为单机运行的k8s集群,直接使用官网感受一下,点击launch terminal ,浏览器下发会弹出命令界面。
配置基础环境 -> 安装kubeadmin部署工具 -> 使用kubeadmin配置master 、node、网络、dashboard等等。下面使用这种方式安装。
相比上述两种有些复杂,但是可以通过二进制安装学到不少东西。
推荐配置:内存4G以上,CPU 2 核以上 ,安装ContOS的磁盘 100G以上,网络使用桥接。
vi /etc/sysconfig/network-scripts/ifcfg-ens32
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" #是否开机启用
## 删除
rm -f /etc/udev/rule.d/70-persistent-net.rules
reboot 查看ip,和上网
hostnamectl set-hostname k8smaster
hostnamectl set-hostname k8snode01
hostnamectl set-hostname k8snode02
ping www.baidu.com
vi /etc/hosts
172.16.7.252 k8snode02
172.16.7.251 k8snode01
172.16.7.250 k8smaster
# 关闭防火墙,并禁止开机启动
systemctl stop firewalld && systemctl disable firewalld
# 查看防火墙状态
systemctl status firewalld
# 临时禁用
setenforce 0
# 永久禁用
vim /etc/sysconfig/selinux
修改:SELINUX=disabled
#查看selinux的状态信息
/usr/sbin/sestatus
# 临时关闭
swapoff -a
# 永久关闭
vi /etc/fstab
# 注释掉以下字段
/dev/mapper/cl-swap swap swap defaults 0 0
# 写入配置
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
# 保证在节点重启后能自动加载所需模块
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
# 加上执行权限
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
yum -y install ntp ntpdate
ntpdate cn.pool.ntp.org
hwclock --systohc
timedatectl
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
# 预装工具
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
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://5pfmrxk8.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload && systemctl start docker && systemctl enable docker
注意:确认一下iptables filter表中FOWARD链的默认策略(pllicy)为ACCEPT
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,则修改
iptables -P FORWARD ACCEPT
8.8.8.8
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
yum install -y kubelet-1.15.6 kubeadm-1.15.6 kubectl-1.15.6
systemctl enable kubelet && systemctl start kubelet
kubeadm config print init-defaults --kubeconfig ClusterConfiguration > kubeadm.yml
vim kubeadm.yml
#只需要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
kubeadm config images list --config kubeadm.yml
# 拉取镜像 - 不要执行下面这个命令
kubeadm config images pull --config kubeadm.yml
# 注意:由于下载很慢,所以采用已经打包好的镜像
docker镜像批量打包
由于在内网环境或网速较慢的时候,下载镜像比较慢,所以可以将镜像打包成文件进行拷贝。这里写了一个批量打包镜像的语句。
批量打包镜像:
将机器上的所有镜像打包到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就可以看到拷贝过来的镜像了。
# 使用ftp工具上传到目录
/root/k8simgs.tar
#拷贝文件到另外两个centos
scp -r /root/k8simgs.tar root@192.168.0.114:/root/k8simgs.tar
也可以把压缩包上传到三个cenos分别再加载。
docker load -i /root/k8simgs.tar
kubeadm init --config=kubeadm.yml
如果要重新初始化可以执行:kubeadm reset 重置。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get node
# 并且拷贝命令到个节点执行
kubeadm join 172.16.40.252:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:9f792d9c1bf57977ff22f317b599504a733b3f66688273ac3aa7505931f8e378
kubectl get nodes
这里的status是NotReady是因为容器之间还没通信。
加入失败
如果 slave 节点加入 master 时配置有问题可以在 slave 节点上使用 kubeadm reset 重置配置再使用 kubeadm join 命令重新加入即可。希望在 master 节点删除 node ,可以使用 kubeadm delete nodes 删除。
可以使用:journalctl -f -u kubelet查看错误日志
k8s 集群 节点状态显示notready
Pod 状态查看
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(三台)参考官方文档安装
kubectl apply -f https://docs.projectcalico.org/v3.9/manifests/calico.yaml
注意如果node下载不了,直接在所有节点通过docker pull下载
kubectl get cs
# 输出如下
NAME STATUS MESSAGE ERROR
# 调度服务,主要作用是将 POD 调度到 Node
scheduler Healthy ok
# 自动化修复服务,主要作用是 Node 宕机后自动修复 Node 回到正常的工作状态
controller-manager Healthy ok
# 服务注册与发现
etcd-0 Healthy {"health":"true"}
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'.
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
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
kubectl get deployment
# 输出如下
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 91m
kubectl expose deployment nginx --port=80 --type=LoadBalancer
# 输出如下
service/nginx exposed
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
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>
kubectl delete deployment nginx
# 输出如下
deployment.extensions "nginx" deleted
kubectl delete service nginx
# 输出如下
service "nginx" deleted
# 看系统日志
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根据资源清单来进行pod的创建
集群级别
不管在任何名称空间下定义,在其他的名称空间下都能看得到,在定义的时候无需指定名称空间 例如:Namespace【名称空间】、Node【节点】、Role【角色】、ClusterRole、RoleBinding、ClusterRoleBinding
元数据级别
提供一个指标,不像是名称空间类型又不像集群级别,本质上更像是在两者之间,但是它有自己的特点,所以更应该作为一个单独的分类,例如HPA【通过cpu的利用率进行平滑扩展】就是一个很明显的元数据类型,通过指标进行操作。
根据一些指标去进行对应的操作
例如:HPA、PodTemplate【pod模板】、LimitRange【资源限制】
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 #容器版本
kubectl explain pod
# 这个命令会告诉我们,编写一个pod资源的yml清单应该使用那些语法
kubectl explain pod.apiVersion
2. 导出yml资源清单
kubectl get pods # 查看有那些pod
kubectl get pod pod的名字 -o yaml
Pod是K8S中可以创建的最小部署单元,一个Pod代表集群上正在运行的一个进程。Pod代表部署的一个单位:K8S中单个应用的实例,它可能由单个容器或多个容器共享组成。
演示案例:把一个Nignx容器运行在一个Pod中
vi poddemo.yaml # 内容如下
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 从本地找镜像
kubectl apply -f poddemo.yaml
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,而是借助控制器Controller进行管理,包括 ReplicationController(老版本的)、ReplicaSet、Deployment、StatefulSet、Job等。Pod控制器通常包含三个组成部分:标签选择器、期望的副本数、Pod模板。
Replicaset是ReplicationController的替代者,确保Pod副本数在任一时刻都精确满足期望值,可以进行扩缩容,也可以进行升级。
vi rs.yaml
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
kubectl create -f rs.yaml
kubectl get pods
删除pod后会自动复制
Kubectl delete pod --all
显示标签
kubectl get pods --show-labels
修改标签
kubectl label pod rs-example-knjhx app=rs-demo1 --overwrite=true
更改后lable后重新补齐
Deployment构建于ReplicaSet之上, 支持事件和状态查看,回滚,版本记录,暂停和启动升级,多种自动更新方案:Recreate(先删除再新建),Deployment支持RollingUpdate(滚动升级,逐步替换)
什么是滚动升级:如有三个副本,先建立一个新的副本,然后删除一个老的副本,再建立一个新的副本,删除一个老的副本
docker pull tomcat
docker run -id --name=tomcat -p 8080:8080 tomcat
<%@ 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>
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
docker save tomcat:v1 tomcat:v2 tomcat:v3 -o /root/tomcatimgs.tar
# 其他两个节点做
scp -r tomcatimgs.tar root@192.168.0.114:/root
docker load -i /root/tomcatimgs.tar
(1) 创建pod
vi deploy.yaml
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
kubectl apply -f deploy.yaml
需要注意:三个k8s机器上都要有镜像:tomcat:v1;tomcat:v2:tomcat:v3
kubectl get pods -o wide # 查看pod详情
curl 192.168.32.168:8080 # 访问容器,通过pod的网络访问,外网目前访问不到
kubectl get deployments # 查看deployments
(2) 扩容缩容
kubectl scale deployment deploy-example --replicas=3 # 修改pod数量到 3 个
spec:
replicas: 5
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
查看,访问,测试一下,容器中的项目版本已经更新
kubectl get pods -o wide # 查看pod网络
curl 192.168.32.179:8080 # 访问pod
方式2:命令设置镜像
kubectl set image deployment/deploy-example myapp=tomcat:v2
# deploy-example : deployment的名字
# myapp=tomcat:v2 镜像名=镜像:版本
kubectl get rs
3. 查看pod
kubectl get pods
4. 访问容器内容
curl 192.168.185.220:8080
(4) 版本还原
kubectl rollout history deploy deploy-example
2. 查看具体版本
kubectl rollout history deploy deploy-example --revision=1
3. 回退版本
kubectl rollout undo deploy deploy-example --to-revision=1
Raft(Raft一致性算法)是一种用于分布式系统中实现一致性的共识算法。它旨在提供容错性和可理解性,使得在网络不可靠或节点故障的情况下,分布式系统仍能保持一致性。
Raft算法通过选举一个领导者(称为"leader")来管理复制状态机的日志复制过程。领导者负责接收客户端请求,并将它们复制到其他节点上的日志中。当多数节点确认接收到日志后,该日志被认为是已提交的,然后被应用到状态机中。这种方式确保了一致性。
Raft算法关注三个关键问题:领导选举、日志复制和安全性。领导选举确保了集群中只有一个领导者,避免冲突和混乱。日志复制确保了所有节点持有相同的日志序列,从而达到一致性。安全性方面,Raft算法使用了多数派原则,在大多数节点正常运行的情况下,才能保证系统的正常运行。
相比于一些其他共识算法,如Paxos,Raft算法更易于理解和实现。由于其简洁性和可理解性,Raft算法被广泛应用于分布式系统,包括Kubernetes集群中的Etcd组件。 ??