目录
一、Kubernetes简介
1、Kubernetes简介
2、kubernetes设计架构
3、Kubernetes核心组件
4、kubernetes设计结构
二、Kubernetes部署
1、官方文档:
2、使用部署工具kubeadm安装Kubernetes
3、安装flannel网络组件
4、其他节点接入k8s集群
三、Pod管理
1、pod的创建与删除
2、pod中的端口暴露——service微服务
2、Pod扩容与缩容
3、更新pod镜像
四、资源清单
1、资源清单举例
2、资源清单中的参数详情
3、资源清单示例:
五、Pod生命周期
1、Pod生命周期结构图
2、Pod的生命周期官方文档
3、Init 容器
4、init容器实例
5、探针
6、存活探针和就绪探针实例
六、控制器
1、控制器的基本概念
2、控制器的官方文档
3、ReplicaSet控制器示例——容器数量检测(容器挂掉时自动创建)
4、Deployment控制器示例——版本回滚
5、DaemonSet控制器示例——确保全部(或者某些)节点上运行一个 Pod 的副本
6、Job控制器示例——执行批处理任务,仅执行一次任务,做完以后就退出了
7、Cronjob控制器示例——CronJob创建定时任务,周期性地在给定的调度时间执行Job
七、service——微服务
1、Service概念
2、deplyment控制器+svc服务
八、k8s网络通信
1、Flannel vxlan模式跨主机通信原理
2、flannel网络
3、flannel支持多种后端
4、calico网络插件(详细信息在后边介绍)
5、Headless Service “无头服务”
6、第二种从外部访问 Service 的方式LoadBalancer 类型的 Service
7、在单机上部署Metallb-layer2环境
8、第三种从外部访问service的方式ExternalName
9、Ingress 服务——从外网访问集群内部
(1)基本ingress结构的部署步骤:
(2)ingress部署扩展——基于域名的虚拟主机
(3)ingress examples
(4)ingress加密
(5)ingress认证
(6)ingress重定向
10、ingress的高级功能
11、金丝雀(canary)发布实践
12、calico网络插件
(1)calico网络插件官网
(2)calico简介:
(3)calico网络架构
(4)calico工作模式
(5)calico安装及部署
(6)calico网络策略
实验1——设置calico网络策略,内容如下:
实验2——设置calico网络策略,内容如下:
九、kubectl命令指南
在Docker 作为高级容器引擎快速发展的同时,在Google内部,容器技术已经应用了很多年,Borg系统运行管理着成千上万的容器应用。
Kubernetes项目来源于Borg,可以说是集结了Borg设计思想的精华,并且吸收了Borg系统中的经验和教训。
Kubernetes对计算资源进行了更高层次的抽象,通过将容器进行细致的组合,将最终的应用服务交给用户。
Kubernetes的好处:
(1)隐藏资源管理和错误处理,用户仅需要关注应用的开发。
(2)服务高可用、高可靠。
(3)可将负载运行在由成千上万的机器联合而成的集群中。
Kubernetes集群包含有节点代理kubelet和Master组件(APIs, scheduler, etc),一切都基于分布式的存储系统。
Kubernetes主要由以下几个核心组件组成:
etcd | 保存了整个集群的状态 |
apiserver | 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制 |
controller manager | 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等 |
scheduler | 负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上 |
kubelet | 负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理 |
Container runtime | 负责镜像管理以及Pod和容器的真正运行(CRI) |
kube-proxy | 负责为Service提供cluster内部的服务发现和负载均衡 |
除了核心组件,还有一些推荐的Add-ons:
kube-dns | 负责为整个集群提供DNS服务 |
Ingress Controller | 为服务提供外网入口 |
Heapster | 提供资源监控 |
Dashboard | 提供GUI |
Federation | 提供跨可用区的集群 |
Fluentd-elasticsearch | 提供集群日志采集、存储与查询 |
Kubernetes设计理念和功能其实就是一个类似Linux的分层架构
核心层:Kubernetes最核心的功能,对外提供API构建高层的应用,对内提供插件式应用执行环境
应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS解析等)
管理层:系统度量(如基础设施、容器和网络的度量),自动化(如自动扩展、动态Provision等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy等)
接口层:kubectl命令行工具、客户端SDK以及集群联邦
生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴 Kubernetes外部:日志、监控、配置管理、CI、CD、Workflow、FaaS、OTS应用、ChatOps等
Kubernetes内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等
Container runtimes | KubernetesYou need to install a container runtime into each node in the cluster so that Pods can run there. This page outlines what is involved and describes related tasks for setting up nodes.Kubernetes 1.23 requires that you use a runtime that conforms with the Container Runtime Interface (CRI).See CRI version support for more information.This page lists details for using several common container runtimes with Kubernetes, on Linux:https://kubernetes.io/docs/setup/production-environment/container-runtimes/#docker准备工作:本实验以server1为harbor仓库,在server2、server3、server4三台虚拟机上部署k8s,server2作为管理节点。
在server2、server3、server4上重置docker
300 systemctl status docker
301 rm -f /etc/systemd/system/docker.service.d/10-machine.conf
302 systemctl daemon-reload
303 systemctl restart docker.service
304 systemctl restart docker.socket
305 docker info
在server1上清空docker-machine节点
[root@server1 harbor]# docker-machine rm server4
About to remove server4
WARNING: This action will delete both local reference and remote instance.
Are you sure? (y/n): y
Successfully removed server4
[root@server1 harbor]# docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
安装 kubeadm | KubernetesThis page shows how to install the `kubeadm` toolbox. For information on how to create a cluster with kubeadm once you have performed this installation process, see the [Using kubeadm to Create a Cluster](/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) page. -- 本页面显示如何安装 kubeadm 工具箱。 有关在执行此安装过程后如何使用 kubeadm 创建集群的信息,请参见 使用 kubeadm 创建集群 页面。准备开始 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令 每台机器 2 GB 或更多的 RAM (如果少于这个数字将会影响你应用的运行内存) 2 CPU 核或更多 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以) 节点之中不可以有重复的主机名、MAC 地址或 product_uuid。请参见这里了解更多详细信息。 开启机器上的某些端口。请参见这里 了解更多详细信息。 禁用交换分区。为了保证 kubelet 正常工作,你 必须 禁用交换分区。 确保每个节点上 MAC 地址和 product_uuid 的唯一性 你可以使用命令 ip link 或 ifconfig -a 来获取网络接口的 MAC 地址 可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验 一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。 Kubernetes 使用这些值来唯一确定集群中的节点。 如果这些值在每个节点上不唯一,可能会导致安装 失败。https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/准备工作:设置cgroupdriver=systemd;禁用swap交换分区;允许iptables检查桥接流量
#在server2/3/4上更改引擎文件,设置cgroupdriver=systemd
[root@server2 ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://reg.westos.org"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
[root@server2 ~]# systemctl daemon-reload
[root@server2 ~]# systemctl restart docker
#在server2/3/4上禁用swap交换分区
[root@server2 ~]# swapoff -a
[root@server2 ~]# vim /etc/fstab
11 #/dev/mapper/rhel-swap swap swap defaults 0 0
#允许server2/3/4的iptables检查桥接流量
[root@server2 ~]# vim /etc/sysctl.d/docker.conf
[root@server2 ~]# cat /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
[root@server2 ~]# sysctl --system
安装软件:配置软件源并安装软件kubeadm、kubelet 和 kubectl
#在server2/3/4上配置阿里云的软件源,用于安装kubeadm
[root@server2 yum.repos.d]# vim /etc/yum.repos.d/k8s.repo
[root@server2 yum.repos.d]#
[root@server2 yum.repos.d]# cat /etc/yum.repos.d/k8s.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
#在server2/3/4上安装软件并激活及开机自启kubelet
[root@server2 yum.repos.d]# yum install -y kubeadm kubelet kubectl
[root@server2 yum.repos.d]# systemctl enable --now kubelet
部署Kubernetes
kubeadm config print init-defaults //查看默认配置信息
#在server1中删掉所有未使用的镜像
docker images |grep -v REPOSITORY |awk '{system("docker rmi "$1":"$2"")}'
#在server2中查询kubeadm所需镜像
[root@server2 yum.repos.d]# kubeadm config images list --image-repository registry.aliyuncs.com/google_containers
registry.aliyuncs.com/google_containers/kube-apiserver:v1.23.4
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.23.4
registry.aliyuncs.com/google_containers/kube-scheduler:v1.23.4
registry.aliyuncs.com/google_containers/kube-proxy:v1.23.4
registry.aliyuncs.com/google_containers/pause:3.6
registry.aliyuncs.com/google_containers/etcd:3.5.1-0
registry.aliyuncs.com/google_containers/coredns:v1.8.6
#在server1中拉取所需镜像
1146 docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.23.4
1147 docker pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.23.4
1148 docker pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.23.4
1149 docker pull registry.aliyuncs.com/google_containers/kube-proxy:v1.23.4
1150 docker pull registry.aliyuncs.com/google_containers/pause:3.6
1151 docker pull registry.aliyuncs.com/google_containers/etcd:3.5.1-0
1152 docker pull registry.aliyuncs.com/google_containers/coredns:v1.8.6
在server1中修改镜像标签并上传到harbor私有仓库
#在server1中修改镜像标签
[root@server1 ~]# docker images | grep aliyuncs | awk '{print $1":"$2}' |awk -F/ '{system("docker tag "$0" reg.westos.org/k8s/"$3"")}'
#修改完成后如下所示:
[root@server1 ~]# docker images |grep k8s
reg.westos.org/k8s/kube-apiserver v1.23.4 62930710c963 4 days ago 135MB
reg.westos.org/k8s/kube-proxy v1.23.4 2114245ec4d6 4 days ago 112MB
reg.westos.org/k8s/kube-scheduler v1.23.4 aceacb6244f9 4 days ago 53.5MB
reg.westos.org/k8s/kube-controller-manager v1.23.4 25444908517a 4 days ago 125MB
reg.westos.org/k8s/etcd 3.5.1-0 25f8c7f3da61 3 months ago 293MB
reg.westos.org/k8s/coredns v1.8.6 a4ca41631cc7 4 months ago 46.8MB
reg.westos.org/k8s/pause 3.6 6270bb605e12 5 months ago 683kB
#在server1中将改标签后的镜像上传到harbor私有仓库
[root@server1 ~]# docker images |grep k8s | awk '{system("docker push "$1":"$2"")}'
在server2中查询本地私有harbor仓库的镜像并开始部署k8s集群
注意:在初始化时遇到一个坑,要求cpu至少两个;RAM内存至少2G。
如果初始化过程中执行失败,可以使用
命令重置节点。
#在server2中查询私有harbor仓库的镜像
[root@server2 ~]# kubeadm config images list --image-repository reg.westos.org/k8s
#在server2中拉取私有harbor仓库的镜像
[root@server2 ~]# kubeadm config images pull --image-repository reg.westos.org/k8s
#在server2中初始化集群
[root@server2 ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository reg.westos.org/k8s
#执行授权(每次重启系统都要执行,或者直接放到.bash_profile中开机自动执行)
[root@server2 ~]# export KUBECONFIG=/etc/kubernetes/admin.conf
[root@server2 ~]# vim .bash_profile
[root@server2 ~]# cat .bash_profile
export KUBECONFIG=/etc/kubernetes/admin.conf
#Master查看状态
[root@server2 ~]# kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-7b56f6bc55-6httc 0/1 Pending 0 6m10s
kube-system coredns-7b56f6bc55-k5fnm 0/1 Pending 0 6m10s
kube-system etcd-server2 1/1 Running 0 6m24s
kube-system kube-apiserver-server2 1/1 Running 0 6m26s
kube-system kube-controller-manager-server2 1/1 Running 0 6m24s
kube-system kube-proxy-5rgqp 1/1 Running 0 6m11s
kube-system kube-scheduler-server2 1/1 Running 0 6m24s
注意:管理节点server2初始化完成后,会在最后生成一个命令,其他节点执行此命令可以直接加入k8s集群中,命令如下:
GitHub - flannel-io/flannel: flannel is a network fabric for containers, designed for Kuberneteshttps://github.com/coreos/flannel
#在server2上下载flannel插件
[root@server2 ~]# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
从此文件中搜索“/image”得到两个镜像,在server1中拉取镜像,并上传到harbor仓库
#拉取镜像
1160 docker pull rancher/mirrored-flannelcni-flannel-cni-plugin:v1.0.1
1161 docker pull rancher/mirrored-flannelcni-flannel:v0.16.3
#更改镜像标签
1162 docker tag rancher/mirrored-flannelcni-flannel-cni-plugin:v1.0.1 reg.westos.org/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.0.1
1163 docker tag rancher/mirrored-flannelcni-flannel:v0.16.3 reg.westos.org/rancher/mirrored-flannelcni-flannel:v0.16.3
#上传镜像到harbor
1164 docker push reg.westos.org/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.0.1
1165 docker push reg.westos.org/rancher/mirrored-flannelcni-flannel:v0.16.3
注意:需要提前在harbor仓库中创建“rancher”
#安装网络组件
[root@server2 ~]# kubectl apply -f kube-flannel.yml
(
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml)由于上一步已经从该网站下载好,所以可以直接安装
server2的k8s管理节点初始化完成后,server3和server4执行加入节点的命令,加入成功后在server2中可以查看集群成员
#在server3/4中执行此命令,加入server2管理的k8s集群
[root@server3 ~]# kubeadm join 172.25.254.2:6443 --token ksbiu3.b7inb9pr5iseanvs --discovery-token-ca-cert-hash sha256:44c18b0ff87e7ca592fa36d5057e2fe71459e1ce0f6df4c996deb4a12d180b5e
#在server2中查看k8s集群中的节点
[root@server2 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
server2 Ready control-plane,master 41m v1.23.4
server3 Ready 22s v1.23.4
server4 Ready 35s v1.23.4
#在server2中查看集群中所有容器状态都为“running”,则证明k8s集群部署成功
[root@server2 ~]# kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-7b56f6bc55-6httc 1/1 Running 0 47m
kube-system coredns-7b56f6bc55-k5fnm 1/1 Running 0 47m
kube-system etcd-server2 1/1 Running 0 48m
kube-system kube-apiserver-server2 1/1 Running 0 48m
kube-system kube-controller-manager-server2 1/1 Running 0 48m
kube-system kube-flannel-ds-fdwcr 1/1 Running 0 17m
kube-system kube-flannel-ds-vkrd8 1/1 Running 0 7m1s
kube-system kube-flannel-ds-wp5x5 1/1 Running 0 6m47s
kube-system kube-proxy-5pvc7 1/1 Running 0 7m1s
kube-system kube-proxy-5rgqp 1/1 Running 0 47m
kube-system kube-proxy-lbglv 1/1 Running 0 6m47s
kube-system kube-scheduler-server2 1/1 Running 0 48m
kubernetes集群扩容时,新节点直接执行上述命令即可自动加入集群中;但是注意的一点是,命令中的token的有效期为24小时,添加时需要更新命令中的token。具体方法参考官方文档:
使用 kubeadm 创建集群 | Kuberneteshttps://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
kubeadm join --token
: --discovery-token-ca-cert-hash sha256:
: kubeadm token list,如果过期了则使用kubeadm token create
: : cat /etc/kubernetes/admin.conf 中可以查到
: openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
kubectl命令指南:
Kubectl Reference Docshttps://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands
Master查看状态:
kubectl get cs
kubectl get node
kubectl get pod -n kube-system -o wide
查看pod的具体信息
kubectl get pod -n kube-system -o wide #显示所有pod
kubectl describe pod kube-proxy-5pvc7 -n kube-system #显示kube-proxy-5pvc7的所有信息
kubectl logs kube-proxy-5pvc7 -n kube-system #显示kube-proxy-5pvc7日志
-n:指定namespace
#查看所有namespace
[root@server2 ~]# kubectl get ns
NAME STATUS AGE
default Active 3d4h
kube-node-lease Active 3d4h
kube-public Active 3d4h
kube-system Active 3d4h
#指定namespace
[root@server2 ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7b56f6bc55-6httc 1/1 Running 1 (28m ago) 3d4h
coredns-7b56f6bc55-k5fnm 1/1 Running 1 (28m ago) 3d4h
etcd-server2 1/1 Running 1 (28m ago) 3d4h
kube-apiserver-server2 1/1 Running 1 (28m ago) 3d4h
kube-controller-manager-server2 1/1 Running 1 (28m ago) 3d4h
kube-flannel-ds-fdwcr 1/1 Running 1 (28m ago) 3d4h
kube-flannel-ds-vkrd8 1/1 Running 1 (28m ago) 3d3h
kube-flannel-ds-wp5x5 1/1 Running 1 (28m ago) 3d3h
Pod是可以创建和管理Kubernetes计算的最小可部署单元,一个Pod代表着集群中运行的一个进程,每个pod都有一个唯一的ip。
一个pod类似一个豌豆荚,包含一个或多个容器(通常是docker),多个容器间共享IPC、Network和UTC namespace。
pod可以提供一个相对持久化的存储环境,当container重置或挂掉时,数据可以暂时存储在pod中,只要pod不出问题,数据也不会有问题。
#创建并运行pod
kubectl run nginx --image=nginx #在当前namespace创建并运行nginx镜像
kubectl get pod -o wide #查看当前namespace中的镜像信息
#删除pod
kubectl delete pod nginx
注意:使用“kubectl run”命令创建pod时,是自主式的pod,删了就没了;使用“kubectl create deployment”命令创建pod时,会创建一个控制器用于管理此pod。
#在一个pod中同时创建多个container,pod名为my-dep
kubectl create deployment my-dep --image=myapp:v1 --replicas=3
#pod的删除,需要删除控制器
kubectl delete deployments.apps my-dep #删除控制器
kubectl delete svc my-dep #删除网络
注意:创建pod后的IP只能在集群内部访问,外部网络无法访问。 因此需要将集群内的pod向集群外暴露一下。
[root@server2 ~]# kubectl expose deployment my-dep --port=80 --target-port=80
service/my-dep exposed
[root@server2 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 3d5h
my-dep ClusterIP 10.108.77.188 80/TCP 9s
service是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service称为微服务。
创建service
$ kubectl expose deployment nginx --port=80 --target-port=80
此时pod客户端可以通过service的名称访问后端的两个Pod
ClusterIP: 默认类型,自动分配一个仅集群内部可以访问的虚拟IP
使用NodePort类型暴露端口,让外部客户端访问Pod
$ kubectl edit svc nginx //修改service的type为NodePort
$ kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort //也可以在创建service时指定类型
NodePort: 在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过 NodeIP:NodePort 来访问该服务
端口暴露后,会向整个pod分配一个IP,在集群内访问此IP,表现的是负载均衡的。这个负载均衡不是通过lvs实现的,二是通过iptables实现,是随机分配的!!!
第一种从外部访问pod的方式:NodePort
为了解决外部网络访问集群节点的问题,还需做以下配置:
将“ClusterIP”更改为“NodePort”,配置完成后,发现my-dep的网络上新增了一个端口“30212”,可以理解为端口映射。
#显示pod网络信息
[root@server2 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 3d5h
my-dep ClusterIP 10.108.77.188 80/TCP 36m
#编辑my-dep这个pod的网络,网络更改如下
[root@server2 ~]# kubectl edit svc my-dep
service/my-dep edited
#再次查看pod的网络信息
[root@server2 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 3d5h
my-dep NodePort 10.108.77.188 80:30212/TCP 37m
配置完成后在外部网络再次测试,测试时加上映射的端口。可以看到:访问集群中的任何节点都得到同样的结果。
#pod扩容
kubectl scale --replicas=6 deployment my-dep
#pod缩容
kubectl scale --replicas=3 deployment my-dep
#更新pod镜像,从之前的myapp:v1更新到myapp:v2
kubectl set image deployment my-dep myapp=myapp:v2 --record
#查看my-dep的更新历史
kubectl rollout history deployment my-dep
在server2的master端更改完成后,外部网络访问时可以看到版本已经更新了
#pod版本回滚
kubectl rollout undo deployment my-dep --to-revision=1
pod版本回滚后,查看版本更新历史;查看当前pod信息;测试;均可以看到明显效果。
yaml资源清单教程
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/
#创建并运行一个pod
[root@server2 ~]# kubectl run demo --image=nginx
pod/demo created
#查看状态
[root@server2 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
demo 1/1 Running 0 10s
#将此pod输出为demo.yaml文件
[root@server2 ~]# kubectl get pod -o yaml > demo.yaml
#从yaml文件中创建pod
[root@server2 pod]# kubectl apply -f demo.yaml
pod/demo created
#删除pod
[root@server2 pod]# kubectl delete -f demo.yaml
pod "demo" deleted
#查看pod信息
[root@server2 pod]# kubectl describe pod demo
#显示节点标签
[root@server2 pod]# kubectl get nodes --show-labels
#进入交互式容器,demo表示pod名称,busybox表示容器名称,-it表示前台运行
[root@server2 pod]# kubectl attach demo -c busybox -it
If you don't see a command prompt, try pressing enter.
/ # ip addr
格式如下:
apiVersion: group/version //指明api资源属于哪个群组和版本,同一个组可以有多个版本
### kubectl api-versions //查询命令
kind: //标记创建的资源类型,k8s主要支持以下资源类别 Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob
metadata: //元数据
name: //对像名称
namespace: //对象属于哪个命名空间
labels: //指定资源标签,标签是一种键值数据
spec: //定义目标资源的期望状态
### kubectl explain pod //查询帮助文档
### kubectl explain pod.spec //查询pod.spec的详细信息
### kubectl explain pod.spec.containers //查询pod.spec.containers的详细信息
[root@server2 pod]# vim demo.yaml
1 apiVersion: v1
2 kind: Pod
3 metadata:
4 name: demo
5 spec:
6 containers:
7 - name: myapp #创建第一个容器,容器名为myapp
8 image: myapp:v1
9 imagePullPolicy: IfNotPresent
10 ports:
11 - name: http
12 containerPort: 80 #容器内端口
13 hostPort: 80 #宿主机端口
14 resources: #设置资源上限,容器可从节点上分配到的上限
15 limits:
16 cpu: 1
17 memory: 200Mi
18 requests: #设置资源下限,如果节点不符合要求则无法运行
19 cpu: 0.5
20 memory: 100Mi
21 - name: busybox #创建第二个容器,名为busybox
22 image: busyboxplus
23 imagePullPolicy: IfNotPresent
24 stdin: true #应用型容器需要给他一个终端
25 tty: true #这两项都是设置终端
26
27
28 nodeSelector: #指定运行的节点
29 kubernetes.io/hostname: server3
30 hostNetwork: true #默认为false,设置为true表示使用主机网络,类似于docker中的host模式
初始化容器为Init_C,可以为一个,也可以为多个;初始化容器在成功运行后并退出。然后才会运行主容器Main_C;主容器从启动到关闭存在一个生命周期,因此有一个存活探针“Liveness”用来判断主容器是否处于存活状态,容器存活时会显示“running”;就绪探针“readiness”用来探测容器是否准备就绪,准备就绪时会显示“READY”。
Pod 可以包含多个容器,应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点: (1)它们总是运行到完成。 (2)Init 容器不支持 Readiness,因为它们必须在 Pod 就绪之前运行完成,每个 Init 容器必须运行成功,下一个才能够运行。
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 值为 Never,它不会重新启动。
Pod 的生命周期 | Kubernetes本页面讲述 Pod 的生命周期。 Pod 遵循一个预定义的生命周期,起始于 Pending 阶段,如果至少 其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded 或者 Failed 阶段。在 Pod 运行期间,kubelet 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态 并确定使 Pod 重新变得健康所需要采取的动作。在 Kubernetes API 中,Pod 包含规约部分和实际状态部分。 Pod 对象的状态包含了一组 Pod 状况(Conditions)。 如果应用需要的话,你也可以向其中注入自定义的就绪性信息。Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者 被终止。节点(Node) dies, the Pods scheduled to that node are [scheduled for deletion](#pod-garbage-collection) after a timeout period. -- Pod 生命期 和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/
Init 容器能做什么?
Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。
Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。
由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
注意:(1)只要yml剧本中存在定义init容器的语句,将会优先执行,无论书写顺序。(2)yml剧本中拉取的镜像会自动从本地仓库中拉取,本地仓库不存在才会去外网拉取,不指定版本的话默认是最新版
[root@server2 init]# vim init.yml
1 apiVersion: v1
2 kind: Pod
3 metadata:
4 name: nginx
5 labels:
6 app: nginx
7 spec:
8 containers:
9 - name: nginx
10 image: nginx
11 imagePullPolicy: IfNotPresent
12 initContainers:
13 - name: init-container
14 image: busybox
15 command: ["/bin/sh", "-c", "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
这是因为初始化容器init中缺少微服务,也就是service解析,导致初始化容器无法完成,进而导致主容器nginx也无法启动。
编写svc文件,pod名为“myservice”。编写完成后启动svc.yml。主容器nginx已经可以处于正常运行状态。主容器启动以后,初始化容器就已经停止了。
只要创建了svc,就会在集群中提供解析,svc停止后,解析也没有了!!!因此svc是为初始化容器准备的!!!
[root@server2 init]# vim svc.yml
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: myservice #端口随便设置,但是要设置好这个服务名称
5 spec:
6 ports:
7 - protocol: TCP
8 port: 80
9 targetPort: 80
测试svc解析:
方法一:
[root@server2 init]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 4d19h
myservice ClusterIP 10.101.15.64 80/TCP 17m
[root@server2 init]# kubectl run -it demo --image=busybox --restart=Never
If you don't see a command prompt, try pressing enter.
/ # nslookup myservice #第一次解析失败
Server: 10.96.0.10
Address: 10.96.0.10:53
** server can't find myservice.default.svc.cluster.local: NXDOMAIN
/ # nslookup myservice.default.svc.cluster.local. #第二次解析成功
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: myservice.default.svc.cluster.local
Address: 10.101.15.64
方法二:
dig -t A myservice.default.svc.cluster.local. @10.96.0.10 #最后的IP地址表示service被集群分配到的IP
配置存活、就绪和启动探测器 | Kuberneteshttps://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
检测方式有以下三种:
探针 是由 kubelet 对容器执行的定期诊断。
ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
成功:容器通过了诊断。 失败:容器未通过诊断。 未知:诊断失败,因此不会采取任何行动。
探针类型有以下三种:
Kubelet 可以选择是否执行在容器上运行的三种探针执行和做出反应
livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success。
readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
startupProbe: 指示容器中的应用是否已经启动。如果提供了启动探测(startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功Success。
重启策略 PodSpec :
中有一个 restartPolicy 字段,可能的值为 Always、OnFailure 和 Never。默认为 Always。
Pod 的生命 :
一般Pod 不会消失,直到人为销毁他们,这可能是一个人或控制器。
建议创建适当的控制器来创建 Pod,而不是直接自己创建 Pod。因为单独的 Pod 在机器故障的情况下没有办法自动复原,而控制器却可以。
三种可用的控制器:
(1)使用 Job 运行预期会终止的 Pod,例如批量计算。Job 仅适用于重启策略为 OnFailure 或 Never 的 Pod。
(2)对预期不会终止的 Pod 使用 ReplicationController、ReplicaSet 和 Deployment ,例如 Web 服务器。ReplicationController 仅适用于具有 restartPolicy 为 Always 的 Pod。
(3)提供特定于机器的系统服务,使用 DaemonSet 为每台机器运行一个 Pod 。
存活探针检测的是:镜像启动2秒后检测80端口是否可用,每隔3秒钟检测一次,每次检测时允许有1秒的超时时间
就绪探针检测的是:通过80端口检测默认发布目录下是否存在“test.html”文件,检测规则同上。检测通过后传达就绪指令。
[root@server2 init]# vim liveness.yml
1 apiVersion: v1
2 kind: Pod
3 metadata:
4 labels:
5 test: liveness
6 name: liveness-http
7 spec:
8 containers:
9 - name: liveness
10 image: nginx
11 imagePullPolicy: IfNotPresent
12 livenessProbe: #存活探针
13 tcpSocket:
14 port: 80
15 initialDelaySeconds: 2 #镜像启动延迟2秒后检测
16 periodSeconds: 3 #每隔3秒钟探测一次
17 timeoutSeconds: 1 #探测的超时时间
18 readinessProbe: #就绪探针
19 httpGet:
20 path: /test.html
21 port: 80
22 initialDelaySeconds: 2
23 periodSeconds: 3
24 timeoutSeconds: 1
创建一个svc.yml服务,用来暴露pod的端口。微服务通过标签来选择pod,用于向外界展示集群中的端口,当pod状态没有就绪之前,pod不会被微服务发现。微服务具有自动发现的功能,并实现后端的负载均衡。
[root@server2 init]# vim svc.yml
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: myservice
5 spec:
6 selector:
7 test: liveness
8 ports:
9 - protocol: TCP
10 port: 80 #服务端口
11 targetPort: 80 #pod/容器内端口
由于就绪探针无法检测到nginx发布目录的“test.html”文件,所以pod还无法运行,进入pod后(pod名为liveness-http)在发布目录中创建“test.html”文件,再次查看pod状态,已经准备就绪。通过curl命令检查,也已经就绪了。一旦pod准备就绪,就会被myservice的svc自动发现。
[root@server2 init]# kubectl exec -it liveness-http -- bash
注意:就绪探针会一直存在,当就绪探针检测的条件不满足时,会立即停止pod服务,直到再次检测到条件满足时才会允许pod服务运行。 微服务用于发现准备就绪的pod并实现后端的负载均衡。
Pod 的分类:
(1)自主式 Pod:由用户管理,Pod 退出后不会被创建
(2)控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目
控制器类型:
Replication Controller和ReplicaSet、 Deployment、 DaemonSet、 StatefulSet、 Job、 CronJob、 HPA(Horizontal Pod Autoscaler)
控制器类型的详细对比:
Replication Controller和ReplicaSet | ReplicaSet 是下一代的 Replication Controller,官方推荐使用ReplicaSet。 ReplicaSet 和 Replication Controller 的唯一区别是选择器的支持,ReplicaSet 支持新的基于集合的选择器需求。 ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 虽然 ReplicaSets 可以独立使用,但今天它主要被Deployments 用作协调 Pod 创建、删除和更新的机制。 |
Deployment | Deployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法。 典型的应用场景: 用来创建Pod和ReplicaSet、 滚动更新和回滚、 扩容和缩容、 暂停与恢复 |
DaemonSet | DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod 。当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。 DaemonSet 的典型用法: 在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph。 在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash。 在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等 一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用。 一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。 |
StatefulSet | StatefulSet 是用来管理有状态应用的工作负载 API 对象。实例之间有不对等关系,以及实例对外部数据有依赖关系的应用,称为“有状态应用” StatefulSet 用来管理 Deployment 和扩展一组 Pod,并且能为这些 Pod 提供*序号和唯一性保证*。 StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值: 稳定的、唯一的网络标识符。 稳定的、持久的存储。 有序的、优雅的部署和缩放。 有序的、自动的滚动更新。 |
Job | 执行批处理任务,仅执行一次任务,保证任务的一个或多个Pod成功结束。 |
CronJob | Cron Job 创建基于时间调度的 Jobs。 一个 CronJob 对象就像 crontab (cron table) 文件中的一行,它用 Cron 格式进行编写,并周期性地在给定的调度时间执行 Job。 |
HPA | 根据资源利用率自动调整service中Pod数量,实现Pod水平自动缩放。 |
工作负载资源 | Kuberneteshttps://kubernetes.io/zh/docs/concepts/workloads/controllers/
[root@server2 pod]# vim rs.yml
1 apiVersion: apps/v1
2 kind: ReplicaSet #指定控制器类型
3 metadata:
4 name: replicaset-example
5 spec:
6 replicas: 3 #副本数为3(可随意扩容与缩容)
7 selector: #匹配标签
8 matchLabels:
9 app: nginx #匹配的标签为nginx
10 template: #template模板作用是将nginx标签应用到模板下的所有container
11 metadata:
12 labels:
13 app: nginx
14 spec: #定义容器
15 containers:
16 - name: nginx
17 image: nginx
#更改pod标签
[root@server2 pod]# kubectl label pod replicaset-example-8lwkf app=myapp --overwrite
#显示所有pod标签
[root@server2 pod]# kubectl get pod --show-labels
#显示rs控制器
[root@server2 pod]# kubectl get rs
rs管理container的依据是“标签项”,只有符合“app=nginx”的标签才属于rs管理。更改pod标签后,原有的container虽然ID没有变化,但是已经脱离了rs的管理,而rs为了保证有三个副本,会再创建一个container。
[root@server2 pod]# vim deploy.yml
1 apiVersion: apps/v1
2 kind: Deployment #指定控制器类型
3 metadata:
4 name: deployment-nginx
5 spec:
6 replicas: 3
7 selector:
8 matchLabels:
9 app: nginx
10 template:
11 metadata:
12 labels:
13 app: nginx
14 spec:
15 containers:
16 - name: nginx
17 image: nginx:latest
Deployment控制器是在rs控制器基础之上建立的。基础功能同rs控制器一样,以container的标签为标准。更改container标签后,也会创建新的容器。
Deployment的主要功能是镜像版本的变更(升级或回滚)
更改镜像版本后,再次生效,会发现控制器后会有历史信息。
更改回之前的镜像版本,容器可以直接回滚为之前的版本!!!
Deployment的基本结构图如下所示:
当版本从v1变为v2时,会新建一个rs控制器,并通过v2的rs控制器创建新的容器,同时保留v1的rs控制器;版本要回滚到v1时,会直接从v1的rs控制器上创建容器,极大节省了资源。
[root@server2 pod]# vim ds.yml
1 apiVersion: apps/v1
2 kind: DaemonSet
3 metadata:
4 name: daemonset-example
5 labels:
6 k8s-app: zabbix-agent
7 spec:
8 selector:
9 matchLabels:
10 name: zabbix-agent
11 template:
12 metadata:
13 labels:
14 name: zabbix-agent
15 spec:
16 containers:
17 - name: zabbix-agent
18 image: nginx
这里不需要设置副本数量,它会自动为每个节点添加一个镜像。
[root@server2 pod]# vim job.yml
1 apiVersion: batch/v1
2 kind: Job #控制器类型
3 metadata:
4 name: pi
5 spec:
6 template:
7 spec:
8 containers:
9 - name: pi
10 image: perl #镜像名为perl
11 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] #计算pi后2000位
12 restartPolicy: Never
13 backoffLimit: 4
#查看pod运行信息
[root@server2 pod]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
pi-d2r9p 0/1 ContainerCreating 0 11s
#通过logs查看运行结果
[root@server2 pod]# kubectl logs pi-d2r9p
[root@server2 pod]# vim cronjob.yml
1 apiVersion: batch/v1beta1
2 kind: CronJob
3 metadata:
4 name: cronjob-example
5 spec:
6 schedule: "* * * * *" #“分时天月周”的时间执行job
7 jobTemplate:
8 spec:
9 template:
10 spec:
11 containers:
12 - name: cronjob
13 image: busybox
14 args:
15 - /bin/sh
16 - -c
17 - date; echo Hello from k8s cluster #每次通过busybox打印这句话
18 restartPolicy: OnFailure
每隔一分钟执行一次,输出一次语句。
Service可以看作是一组提供相同服务的Pod对外的访问接口(用于pod内端口暴露)。借助Service,应用可以方便地实现服务发现和负载均衡。
service默认只支持4层负载均衡能力,没有7层功能。(可以通过Ingress实现)
service的类型:
ClusterIP:默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问。
NodePort:将Service通过指定的Node上的端口暴露给外部,访问任意一个
NodeIP:nodePort都将路由到ClusterIP。
LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均衡器,并将请求转发到
:NodePort,此模式只能在云服务器上使用。 ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定)。
官方文档:
使用 Service 连接到应用 | Kuberneteshttps://kubernetes.io/zh/docs/concepts/services-networking/connect-applications-service/
Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。
kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的 iptables 规则,如果宿主机有大量的Pod(以及增删pod时),不断刷新iptables规则,会消耗大量的CPU资源。
IPVS模式的service,可以使K8s集群支持更多量级的Pod。
开启kube-proxy的ipvs模式:
#所有节点安装ipvsadm管理器
yum install -y ipvsadm
#修改IPVS模式
kubectl edit cm kube-proxy -n kube-system
mode: "ipvs"
#更新kube-proxy pod
kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
更新完成后,通过ipvsadm看到策略已经更新,如下所示:
并且设置完成后,宿主机的网卡选项会多出来kube-ipvs的接口。所有增加的svc的地址都会增加到这个接口的IP上
[root@server2 pod]# vim deploy.yml
1 apiVersion: apps/v1
2 kind: Deployment
3 metadata:
4 name: deployment-nginx
5 spec:
6 replicas: 3
7 selector:
8 matchLabels:
9 app: nginx
10 template:
11 metadata:
12 labels:
13 app: nginx
14 spec:
15 containers:
16 - name: nginx
17 image: myapp:v1
18 --- #创建微服务Service
19 apiVersion: v1
20 kind: Service
21 metadata:
22 name: myservice
23 spec:
24 selector:
25 app: nginx #注意标签和上边定义的deploy控制器的标签一致
26 ports:
27 - protocol: TCP
28 port: 80 #服务端口
29 targetPort: 80 #pod/容器内端口
通过ipvsadm查看转发规则,svc获取到的虚拟IP地址可以通过rr算法调度到后台的三个容器中。
这样就可以在实现负载均衡的同时,不用频繁地刷新iptables策略,会随着容器的IP动态变更
k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等。 CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist
插件使用的解决方案如下:
虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。
容器间通信:同一个pod内的多个容器间的通信,通过lo即可实现;
pod之间的通信:
同一节点的pod之间通过cni网桥转发数据包。
不同节点的pod之间的通信需要网络插件支持。
pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换。
pod和外网通信:iptables的MASQUERADE。
Service与集群外部客户端的通信:(ingress、nodeport、loadbalancer)
VXLAN,即Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network)。
VTEP:VXLAN Tunnel End Point(虚拟隧道端点),在Flannel中 VNI的默认值是1,这也是为什么宿主机的VTEP设备都叫flannel.1的原因。 Cni0: 网桥设备,每创建一个pod都会创建一对 veth pair。其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡)。
Flannel.1: TUN设备(虚拟网卡),用来进行 vxlan 报文的处理(封包和解包)。不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端。
Flanneld:flannel在每个主机中运行flanneld作为agent,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet,本主机内所有容器的IP地址都将从中分配。同时Flanneld监听K8s集群数据库,为flannel.1设备提供封装数据时必要的mac、ip等网络数据信息。
flannel网络原理:
当容器发送IP包,通过veth pair 发往cni网桥,再路由到本机的flannel.1设备进行处理。
VTEP设备之间通过二层数据帧进行通信,源VTEP设备收到原始IP包后,在上面加上一个目的MAC地址,封装成一个内部数据帧,发送给目的VTEP设备。
内部数据桢,并不能在宿主机的二层网络传输,Linux内核还需要把它进一步封装成为宿主机的一个普通的数据帧,承载着内部数据帧通过宿主机的eth0进行传输。
Linux会在内部数据帧前面,加上一个VXLAN头,VXLAN头里有一个重要的标志叫VNI,它是VTEP识别某个数据桢是不是应该归自己处理的重要标识。
flannel.1设备只知道另一端flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。在linux内核里面,网络设备进行转发的依据,来自FDB的转发数据库,这个flannel.1网桥对应的FDB信息,是由flanneld进程维护的。
linux内核在IP包前面再加上二层数据帧头,把目标节点的MAC地址填进去,MAC地址从宿主机的ARP表获取。
此时flannel.1设备就可以把这个数据帧从eth0发出去,再经过宿主机网络来到目标节点的eth0设备。目标主机内核网络栈会发现这个数据帧有VXLAN Header,并且VNI为1,Linux内核会对它进行拆包,拿到内部数据帧,根据VNI的值,交给本机flannel.1设备处理,flannel.1拆包,根据路由表发往cni网桥,最后到达目标容器。
Vxlan:
vxlan //报文封装,默认
Directrouting //直接路由,跨网段使用vxlan,同网段使用host-gw模式。
host-gw: //主机网关,性能好,但只能在二层网络中,不支持跨网络。如果有成千上万的Pod,容易产生广播风暴,不推荐
UDP: //性能差,不推荐
配置flannel:
#配置flannel
[root@server2 ~]# kubectl edit cm -n kube-system kube-flannel-cfg
27 net-conf.json: |
28 {
29 "Network": "10.244.0.0/16",
30 "Backend": {
31 "Type": "host-gw" #由xvlan改为host-gw
32 }
33 }
#删除旧的flannel,控制器会按照新配置重新建立flannel
[root@server2 ~]# kubectl get pod -n kube-system |grep flannel | awk '{system("kubectl delete pod "$1" -n kube-system")}'
官网:https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises
calico简介:
flannel实现的是网络通信,calico的特性是在pod之间的隔离。
通过BGP路由,但大规模端点的拓扑计算和收敛往往需要一定的时间和计算资源。
纯三层的转发,中间没有任何的NAT和overlay,转发效率最好。
Calico 仅依赖三层路由可达。Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景。
calico网络架构:
Felix:监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。
BIRD:一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,路由的时候到这里来。
Headless Service不需要分配一个VIP,而是直接以DNS记录的方式解析出被代理Pod的IP地址。 域名格式:$(servicename).$(namespace).svc.cluster.local
Headless Service实例:
[root@server2 service]# vim headless.yml
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: nginx-svc
5 spec:
6 ports:
7 - name: http
8 port: 80
9 targetPort: 80
10 selector:
11 app: nginx
12 clusterIP: None
从外部访问 Service 的第二种方式,适用于公有云上的 Kubernetes 服务。这时候,你可以指定一个 LoadBalancer 类型的 Service。(第一种是NodePort方式,第二种是LoadBalancer方式)
[root@server2 service]# vim lb.yml
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: lb-nginx
5 spec:
6 ports:
7 - name: http
8 port: 80
9 targetPort: 80
10 selector:
11 app: nginx
12 type: LoadBalancer
在service提交后,Kubernetes就会调用 CloudProvider 在公有云上为你创建一个负载均衡服务,并且把被代理的 Pod 的 IP地址配置给负载均衡服务做后端。在本例中的“EXTERNAL-IP”可以理解为一个负载均衡器。
注意:关于“EXTERNAL-IP”会在下一节设置
基本结构图:
(1)云端环境如下:
(2)单机环境下:bare metal(裸金属方式)
官方文档:
MetalLB, bare metal load-balancer for Kuberneteshttps://metallb.universe.tf/installation/
先启动一个svc服务,在其中添加了deployment控制器控制的nginx镜像,便于后续测试。
[root@server2 service]# vim lb.yml
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: lb-nginx
5 spec:
6 ports:
7 - name: http
8 port: 80
9 targetPort: 80
10 selector:
11 app: nginx
12 type: LoadBalancer
13
14 ---
15 apiVersion: apps/v1
16 kind: Deployment
17 metadata:
18 name: deployment-nginx
19 spec:
20 replicas: 3
21 selector:
22 matchLabels:
23 app: nginx
24 template:
25 metadata:
26 labels:
27 app: nginx
28 spec:
29 containers:
30 - name: nginx
31 image: myapp:v1
部署metallb-layer2
#设置ipvs模式
kubectl edit configmap -n kube-system kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
#重新加载容器使更改生效
kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}
#安装新的namespace,并部署metallb
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
注意:部署metallb时 ,metallb.yaml文件中会有拉取镜像,所以可以先将镜像下载到本地仓库中
#拉取镜像
[root@server1 ~]# docker pull quay.io/metallb/speaker:v0.12.1
[root@server1 ~]# docker pull quay.io/metallb/controller:v0.12.1
#更改镜像标签
[root@server1 ~]# docker tag quay.io/metallb/controller:v0.12.1 reg.westos.org/metallb/controller:v0.12.1
[root@server1 ~]# docker tag quay.io/metallb/speaker:v0.12.1 reg.westos.org/metallb/speaker:v0.12.1
#上传镜像
[root@server1 ~]# docker push reg.westos.org/metallb/controller:v0.12.1
[root@server1 ~]# docker push reg.westos.org/metallb/speaker:v0.12.1
#更改metallb.yaml的镜像获取地址
[root@server2 metallb]# vim metallb.yaml
365 image: metallb/speaker:v0.12.1
444 image: metallb/controller:v0.12.1
#运行metallb,并在指定的namespace中查看
[root@server2 metallb]# kubectl apply -f metallb.yaml
[root@server2 metallb]# kubectl get pod -n metallb-system
NAME READY STATUS RESTARTS AGE
controller-5764b9c97c-nqfpj 0/1 Running 0 14s
speaker-9fdrs 0/1 CreateContainerConfigError 0 15s
speaker-b97qz 0/1 CreateContainerConfigError 0 15s
speaker-dww54 0/1 CreateContainerConfigError 0 15s
配置地址池:
[root@server2 metallb]# vim config.yaml
1 apiVersion: v1
2 kind: ConfigMap
3 metadata:
4 namespace: metallb-system
5 name: config
6 data:
7 config: |
8 address-pools:
9 - name: default
10 protocol: layer2
11 addresses:
12 - 172.25.254.100-172.25.254.200 #设置为自己的IP地址池(要求外部可以访问)
测试:svc获得了一个“EXTERNAL-IP”后,外部网络就可以直接访问这个IP来访问后台的容器,并且访问是负载均衡的。测试结果如下
[root@server2 service]# vim ex-svc.yml
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: ex-service
5 spec:
6 type: ExternalName
7 externalName: test.westos.org
由于svc在集群内的IP地址总是在变化,因此可以提供一个解析使其相对固定下来;外部网络访问时只需要去找域名就可以自动解析到svc的IP。
也可以直接为svc绑定一个IP,svc启动后,需要手工向节点中加上一个IP地址,然后集群外部就可以访问,一般不推荐,这对后期的维护成本要求较高。
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: ex-service
5 spec:
6 selector:
7 app: nginx
8 ports:
9 - name: http
10 protocol: TCP
11 port: 80
12 targetPort: 80
13 externalIPs:
14 - 172.25.254.200
一种全局的、为了代理不同后端 Service 而设置的负载均衡服务,就是 Kubernetes 里的Ingress 服务。
Ingress由两部分组成:Ingress controller和Ingress服务。 Ingress Controller 会根据你定义的 Ingress 对象,提供对应的代理能力。
业界常用的各种反向代理项目,比如 Nginx、HAProxy、Envoy、Traefik 等,都已经为Kubernetes 专门维护了对应的 Ingress Controller。
换言之:Ingress用来负载均衡svc,svc再去负载均衡pod
官方文档:
Installation Guide - NGINX Ingress Controllerhttps://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters
在server2中
#下载deploy.yml文件
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/baremetal/deploy.yaml
在server1中拉取上面deply.yaml文件中需要的两个镜像,修改标签后上传到本地仓库
1044 docker pull liangjw/ingress-nginx-controller:v1.1.1
1045 docker pull liangjw/kube-webhook-certgen:v1.1.1
1046 docker tag liangjw/ingress-nginx-controller:v1.1.1 reg.westos.org/ingress-nginx/controller:v1.1.1
1047 docker tag liangjw/kube-webhook-certgen:v1.1.1 reg.westos.org/ingress-nginx/kube-webhook-certgen:v1.1.1
1048 docker push reg.westos.org/ingress-nginx/controller:v1.1.1
1049 docker push reg.westos.org/ingress-nginx/kube-webhook-certgen:v1.1.1
在server2中的deploy.yaml文件中镜像地址改为私有仓库的地址。
部署完成后效果如下:
基本逻辑是:client——>ingress——>svc——>pod。因此可以将ingress控制器改为LoadBalancer模式,会自动获取到一个IP地址,就可以从外部网络直接访问svc了。
先在的需求是,在外部主机访问“www1.westos.org”域名就可以通过ingress的方式访问到pod内部。因此需要重新设置一个svc
[root@server2 ingress]# cat ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-demo
5 spec:
6 ingressClassName: nginx
7 rules:
8 - host: www1.westos.org
9 http:
10 paths:
11 - path: / #直接访问根目录
12 pathType: Prefix
13 backend: #设置后端的svc
14 service:
15 name: myservice #后端的svc名称,必须匹配
16 port:
17 number: 80
#ingress.yml文件生效后,查看详细信息
[root@server2 ingress]# kubectl apply -f ingress.yaml
ingress.networking.k8s.io/ingress-demo created
[root@server2 ingress]# kubectl get ingress
下图绿框中表明,当外部网络访问“www1.westos.org”时,会自动访问后端“myservice:80”上的3个pod
在外部主机测试:
Ingress | KubernetesFEATURE STATE: Kubernetes v1.19 [stable] An API object that manages external access to the services in a cluster, typically HTTP. aka: tags: - networking - architecture - extension --- -- Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。术语 为了表达更加清晰,本指南定义了以下术语:服务(Service) that identifies a set of Pods using label selectors. Unless mentioned otherwise, Services are assumed to have virtual IPs only routable within the cluster network. -- 节点(Node): Kubernetes 集群中其中一台工作机器,是集群的一部分。 集群(Cluster): 一组运行由 Kubernetes 管理的容器化应用程序的节点。 在此示例和在大多数常见的 Kubernetes 部署环境中,集群中的节点都不在公共网络中。 边缘路由器(Edge router): 在集群中强制执行防火墙策略的路由器(router)。 可以是由云提供商管理的网关,也可以是物理硬件。 集群网络(Cluster network): 一组逻辑的或物理的连接,根据 Kubernetes 网络模型 在集群内实现通信。 服务(Service):Kubernetes 服务使用 标签选择算符(selectors)标识的一组 Pod。 除非另有说明,否则假定服务只具有在集群网络中可路由的虚拟 IP。 services within the cluster.https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
为了和一步实验稍作区分,这里新建一个实验域名为“www2.westos.org”,并且svc服务名称为“myapp-svc”。
#新建svc服务
[root@server2 pod]# vim deploy-2.yml
1 apiVersion: apps/v1
2 kind: Deployment
3 metadata:
4 name: deployment-myapp
5 spec:
6 replicas: 3
7 selector:
8 matchLabels:
9 app: myapp
10 template:
11 metadata:
12 labels:
13 app: myapp
14 spec:
15 containers:
16 - name: myapp
17 image: myapp:v2
18 ---
19 apiVersion: v1
20 kind: Service
21 metadata:
22 name: myapp-svc
23 spec:
24 selector:
25 app: myapp
26 ports:
27 - protocol: TCP
28 port: 80 #服务端口
29 targetPort: 80 #pod/容器内端口
#在之前的ingress.yaml文件中添加www2.westos.org的域名
[root@server2 ingress]# vim ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-demo
5 spec:
6 ingressClassName: nginx
7 rules:
8 - host: www1.westos.org
9 http:
10 paths:
11 - path: / #直接访问根目录
12 pathType: Prefix
13 backend: #设置后端的svc
14 service:
15 name: myservice #后端的svc名称,必须匹配
16 port:
17 number: 80
18 - host: www2.westos.org
19 http:
20 paths:
21 - path: / #直接访问根目录
22 pathType: Prefix
23 backend: #设置后端的svc
24 service:
25 name: myapp-svc #后端的svc名称,必须匹配
26 port:
27 number: 80
测试:在外部主机上分别访问这两个域名,会被ingress调度到不同的svc上
Introduction - NGINX Ingress Controllerhttps://kubernetes.github.io/ingress-nginx/examples/
TLS termination - NGINX Ingress Controllerhttps://kubernetes.github.io/ingress-nginx/examples/tls-termination/ 创建证书并导入kubectl
#生成证书和密钥
[root@server2 ingress]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
Generating a 2048 bit RSA private key
..............................................................+++
..........+++
writing new private key to 'tls.key'
-----
#导入证书和密钥
[root@server2 ingress]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created
#查看kubectl中的证书
[root@server2 ingress]# kubectl get secrets
NAME TYPE DATA AGE
default-token-tcwmq kubernetes.io/service-account-token 3 7d21h
tls-secret kubernetes.io/tls 2 11s
[root@server2 ingress]# vim ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-demo
5 spec:
6 tls: #添加加密策略
7 - hosts:
8 - www1.westos.org
9 secretName: tls-secret #指定加密的pod
10 ingressClassName: nginx
11 rules:
12 - host: www1.westos.org
13 http:
14 paths:
15 - path: / #直接访问根目录
16 pathType: Prefix
17 backend: #设置后端的svc
18 service:
19 name: myservice #后端的svc名称,必须匹配
20 port:
21 number: 80
22 - host: www2.westos.org
23 http:
24 paths:
25 - path: / #直接访问根目录
26 pathType: Prefix
27 backend: #设置后端的svc
28 service:
29 name: myapp-svc #后端的svc名称,必须匹配
30 port:
31 number: 80
测试:当外部主机访问80端口时,会自动重定向到ingress的443端口
Basic Authentication - NGINX Ingress Controllerhttps://kubernetes.github.io/ingress-nginx/examples/auth/basic/生成认证文件并导入kubectl资源中
#安装生成认证密钥的工具httpd-tools
yum install -y httpd-tools
#创建认证用户
[root@server2 ingress]# htpasswd -c auth admin
New password: westos
Re-type new password: westos
Adding password for user admin
#将用户认证文件加载到kubectl资源中
[root@server2 ingress]# kubectl create secret generic basic-auth --from-file=auth
#查看用户认证pod资源是否就绪
[root@server2 ingress]# kubectl get secrets
NAME TYPE DATA AGE
basic-auth Opaque 1 20s
default-token-tcwmq kubernetes.io/service-account-token 3 7d21h
tls-secret kubernetes.io/tls 2 19m
在ingress.yaml中添加用户认证的选项
[root@server2 ingress]# vim ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-demo
5 annotations: #添加用户认证的选项
6 nginx.ingress.kubernetes.io/auth-type: basic
7 nginx.ingress.kubernetes.io/auth-secret: basic-auth
8 nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - admin'
9 spec:
10 tls:
11 - hosts:
12 - www1.westos.org
13 secretName: tls-secret
14 ingressClassName: nginx
15 rules:
16 - host: www1.westos.org
17 http:
18 paths:
19 - path: / #直接访问根目录
20 pathType: Prefix
21 backend: #设置后端的svc
22 service:
23 name: myservice #后端的svc名称,必须匹配
24 port:
25 number: 80
26 - host: www2.westos.org
27 http:
28 paths:
29 - path: / #直接访问根目录
30 pathType: Prefix
31 backend: #设置后端的svc
32 service:
33 name: myapp-svc #后端的svc名称,必须匹配
34 port:
35 number: 80
重新运行ingress.yaml文件后,可以看到认证信息。意味着访问这个域名需要认证。
测试:
Rewrite - NGINX Ingress Controllerhttps://kubernetes.github.io/ingress-nginx/examples/rewrite/
需求:访问“www1.westos.org“时直接重定向到“www1.westos.org.hostname.html”
在ingress.yaml文件中添加重定向语句,格式如下:
[root@server2 ingress]# vim ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-demo
5 annotations:
6 nginx.ingress.kubernetes.io/app-root: /hostname.html #重定向
******
测试:设置好后,通过浏览器测试,输入“www1.westos.org”时会自动重定向到“www1.westos.org/hostname.html”
annotations参数:
金丝雀发布(canary):
Annotations - NGINX Ingress Controllerhttps://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary金丝雀发布的简介:
kubernetes基于nginx-ingress进行蓝绿部署/金丝雀发布(canary)在关闭版本A后部署版本B. 此技术意味着服务的停机时间取决于应用程序的关闭和启动持续时间。 对用户的影响很大http://idcsec.com/2019/09/12/kubernetes%E5%9F%BA%E4%BA%8Enginx-ingress%E8%BF%9B%E8%A1%8C%E8%93%9D%E7%BB%BF%E9%83%A8%E7%BD%B2-%E9%87%91%E4%B8%9D%E9%9B%80%E5%8F%91%E5%B8%83canary/几年前的发布方式:
在关闭版本A后部署版本B. 此技术意味着服务的停机时间取决于应用程序的关闭和启动持续时间。 对用户的影响很大
kubernetes滚动更新方式:
滚动更新策略包括通过逐个替换实例来逐步更新应用程序的版本,直到所有实例都更新为止。它通常遵循以下过程:在负载均衡器后面使用版本A池,部署版本B的一个实例。当服务准备好接受流量时,该实例将添加到池中。然后,从池中删除一个版本A的实例并关闭。
您可以调整以下参数以增加部署时间:
maxSurge:除当前数量外还要添加多少个实例。
maxUnavailable:滚动更新过程中的不可用实例数。
蓝绿部署:
蓝/绿部署策略,版本B(绿色)与版本A(蓝色)一起部署,实例数量完全相同。在测试新版本满足所有要求后,流量在负载均衡器级别从版本A切换到版本B.
canary:
丝雀部署包括逐渐将生产流量从版本A转移到版本B.通常,流量根据权重进行划分。例如,90%的请求转到版本A,10%请求转到版本B.
A / B测试:
A / B测试部署包括在特定条件下将用户子集路由到新功能。它通常是一种基于统计信息而非部署策略制定业务决策的技术。可以通过为canary部署添加额外的功能来实现
在之前实验的基础上,将两个svc的名称分别更改为“myapp-v1”和“myapp-v2”,用于模拟两套版本,查看版本迭代效果。(删掉之前的ingress,防止对本实验有影响)
“myapp-v1”版本如下:
[root@server2 ingress]# vim v1-ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-myapp
5 spec:
6 ingressClassName: nginx
7 rules:
8 - host: myapp.westos.org
9 http:
10 paths:
11 - path: /
12 pathType: Prefix
13 backend:
14 service:
15 name: myapp-v1
16 port:
17 number: 80
令其生效后,在外部主机访问,可以看到当前镜像版本为“mapp-v1”
如果现在需要更新到“myapp-v2”版本,用金丝雀的方式让v1的流量慢慢移动到v2上。
[root@server2 ingress]# vim v2-ingress.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: Ingress
3 metadata:
4 name: ingress-myapp-canary
5 annotations:
6 nginx.ingress.kubernetes.io/canary: "true" #启用金丝雀方式
7 nginx.ingress.kubernetes.io/canary-weight: "10" #先转移10%的流量
8 spec:
9 ingressClassName: nginx
10 rules:
11 - host: myapp.westos.org
12 http:
13 paths:
14 - path: /
15 pathType: Prefix
16 backend:
17 service:
18 name: myapp-v2
19 port:
20 number: 80
在宿主机测试,大约是每访问10次就会有一次的被分配到v2上
接下来将流量比例调整为50,意味着每访问100次,就有50次被分配到v2上。在宿主机通过一个脚本实现,脚本内容如下:
[root@westos_student50 docker]# vim v1-v2.sh
1 #!/bin/bash
2
3 v1=0
4 v2=0
5
6 for (( i=0; i<100; i++))
7 do
8 response=`curl -s myapp.westos.org |grep -c v1`
9
10 v1=`expr $v1 + $response`
11 v2=`expr $v2 + 1 - $response`
12
13 done
14
15 echo "v1:$v1, v2:$v2"
如果想要在集群中控制某些服务对网络的访问,需要设定相应的网络策略。设定网络策略需要网络插件的支持。
而之前用到的"flannel网络插件"无法提供这样的服务,因此需要更换可以提供此服务的网络插件“calico网络插件”。
Install Calico networking and network policy for on-premises deploymentshttps://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises
flannel实现的是网络通信,calico的特性是在pod之间的隔离。
通过BGP路由,但大规模端点的拓扑计算和收敛往往需要一定的时间和计算资源。
纯三层的转发,中间没有任何的NAT和overlay,转发效率最好。
Calico 仅依赖三层路由可达。Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景。
Felix:监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。
BIRD:一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,路由的时候到这里来。
IPIP工作模式:适用于互相访问的pod不在同一个网段中,跨网段访问的场景。
BGP工作模式:适用于互相访问的pod在同一个网段,适用于大型网络。
#下载calico.yaml文件
curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O calico.yaml
#更改calico.yaml中的镜像源为本地镜像仓库的名称
[root@server2 calico]# cat calico.yaml |grep image
image: calico/cni:v3.22.0
image: calico/cni:v3.22.0
image: calico/pod2daemon-flexvol:v3.22.0
image: calico/node:v3.22.0
image: calico/kube-controllers:v3.22.0
calico.yaml文件中涉及到的几个镜像已经打包好放在本地仓库中了。
#在server2中清除之前的flannel组件
[root@server2 ~]# kubectl delete -f kube-flannel.yml
#在每个节点中删除掉冗余的配置文件
[root@server2 net.d]# rm -f /etc/cni/net.d/10-flannel.conflist
#运行calico.yml文件,并查看各节点是否准备就绪
[root@server2 calico]# kubectl apply -f calico.yaml
[root@server2 calico]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-599bb85f6d-pkzzv 1/1 Running 0 80s
calico-node-7r29t 1/1 Running 0 80s
calico-node-fn49q 0/1 Running 0 80s
calico-node-qf6t2 0/1 Running 0 80s
为了不受之前实验的干扰,删除掉之前所有的pod
579 kubectl delete -f v1-ingress.yaml
580 kubectl delete -f v2-ingress.yaml
581 kubectl delete svc --all
582 kubectl delete deployments.apps deployment-myapp
583 kubectl delete deployments.apps deployment-nginx
然后重新新建一个项目。并且在集群内测试已经没有问题了。
要从集群外部访问还需要一个ingress,所以就启动一个之前的“v1-ingress.yaml”
测试:在外部主机上访问集群内部,已经可以正常访问了 。因此证明calico已经安装完成
NetworkPolicy策略模型:控制某个namespace下的pod的网络出入站规则
calico网络策略官方文档:
声明网络策略 | Kubernetes本文可以帮助你开始使用 Kubernetes 的 NetworkPolicy API 声明网络策略去管理 Pod 之间的通信说明: 本部分链接到提供 Kubernetes 所需功能的第三方项目。Kubernetes 项目作者不负责这些项目。此页面遵循CNCF 网站指南,按字母顺序列出项目。要将项目添加到此列表中,请在提交更改之前阅读内容指南。 准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 建议在至少有两个节点的集群上运行本教程,且这些节点不作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建: Katacoda 玩转 Kubernetes 您的 Kubernetes 服务器版本必须不低于版本 v1.8. 要获知版本信息,请输入 kubectl version. 你首先需要有一个支持网络策略的 Kubernetes 集群。已经有许多支持 NetworkPolicy 的网络提供商,包括: Antrea Calico Cilium Kube-router Romana Weave 网络 创建一个nginx Deployment 并且通过服务将其暴露 为了查看 Kubernetes 网络策略是怎样工作的,可以从创建一个nginx Deployment 并且通过服务将其暴露开始kubectl create deployment nginx --image=nginx deployment.apps/nginx created 将此 Deployment 以名为 nginx 的 Service 暴露出来:https://kubernetes.io/zh/docs/tasks/administer-cluster/declare-network-policy/网络策略 | Kubernetespod is allowed to communicate with various network "entities" (we use the word "entity" here to avoid overloading the more common terms such as "endpoints" and "services", which have specific Kubernetes connotations) over the network. -- 如果你希望在 IP 地址或端口层面(OSI 第 3 层或第 4 层)控制网络流量, 则你可以考虑为集群中特定应用使用 Kubernetes 网络策略(NetworkPolicy)。 NetworkPolicy 是一种以应用为中心的结构,允许你设置如何允许 Pod 与网络上的各类网络“实体” (我们这里使用实体以避免过度使用诸如“端点”和“服务”这类常用术语, 这些术语在 Kubernetes 中有特定含义)通信。Pod 可以通信的 Pod 是通过如下三个标识符的组合来辩识的: 其他被允许的 Pods(例外:Pod 无法阻塞对自身的访问) 被允许的名字空间 IP 组块(例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址) selector to specify what traffic is allowed to and from the Pod(s) that match the selector.https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/
[root@server2 calico]# vim policy.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: NetworkPolicy
3 metadata:
4 name: access-nginx
5 spec:
6 podSelector:
7 matchLabels:
8 app: nginx #只针对nginx的标签作出限制
9 ingress: #入站的请求只有通过有此标签的pod才能访问
10 - from:
11 - podSelector:
12 matchLabels:
13 access: "true"
policy.yaml文件策略生效后,只针对标签为“app=nginx”的pod有效。
由于网络策略中设置为“入站的请求只有通过有此标签的pod才能访问”,而发出请求的pod标签不是“nginx”,因此在集群内无法访问该pod了
再通过其他镜像测试,可以看到因为新建的busyboxplus镜像的标签为“demo”,因此还是无法访问pod内部。
在另一个终端上连接server2,将demo的标签改为“access=true”。拥有此标签后,再次从busyboxplus中访问,可以访问到pod内部了。
#更改demo的标签
[root@server2 ~]# kubectl label pod demo access=true
pod/demo labeled
#查看demo的标签
[root@server2 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
demo 1/1 Running 0 51s access=true,run=demo
表示匹配pod标签为“access=true”的请求可以访问;或者从namespace上限制“test”的pod可以访问
[root@server2 calico]# vim policy.yaml
1 apiVersion: networking.k8s.io/v1
2 kind: NetworkPolicy
3 metadata:
4 name: access-nginx
5 spec:
6 podSelector:
7 matchLabels:
8 app: nginx
9 ingress:
10 - from:
11 - podSelector: #策略1
12 matchLabels:
13 access: "true"
14 - namespaceSelector: #策略2
15 matchLabels:
16 role: "test"
新建一个test的namespace,但是它的标签还是默认的
#创建一个名为test的namespace
[root@server2 calico]# kubectl create namespace test
重新运行之前的demo,这次运行的namespace在test上。在busyboxplus中测试,无法访问内部pod。
#为test的namespace为添加标签
[root@server2 calico]# kubectl label ns test role=test
namespace/test labeled
[root@server2 calico]# kubectl get ns --show-labels
test Active 5m30s kubernetes.io/metadata.name=test,role=test
再次测试后可以看到,允许正常访问pod了。
注意:写多个策略时,加不加“-”有很大区别,加上“-”表示或者,满足一个条件即可;不加“-”表示并且,所有条件必须同时满足。
kubectl命令指南:
Kubectl Reference Docshttps://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands
#导入本地镜像包
docker load -i base-debian10.tar (镜像名)
Master查看状态:
kubectl get cs
kubectl get node
kubectl get pod -n kube-system -o wide
#创建pod
[root@server2]# kubectl apply -f demo.yml
#删除pod(两种方式)
[root@server2]# kubectl delete -f demo.yml
[root@server2]# kubectl delete pod liveness-http
#查看pod的具体信息
kubectl get pod -n kube-system -o wide #显示kube-system域中的所有pod
kubectl describe pod nginx #显示名为nginx的pod信息,不加-n表示在默认namespace查看
kubectl logs nginx -n kube-system #显示nginx日志,-n:指定namespace为kube-system
kubectl logs nginx -c init-container #显示名为nginx的pod下的init-container容器的日志
#查看所有namespace
[root@server2 ~]# kubectl get ns
NAME STATUS AGE
default Active 3d4h
kube-node-lease Active 3d4h
kube-public Active 3d4h
kube-system Active 3d4h
#指定namespace
[root@server2 ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7b56f6bc55-6httc 1/1 Running 1 (28m ago) 3d4h
coredns-7b56f6bc55-k5fnm 1/1 Running 1 (28m ago) 3d4h
#手动创建容器
kubectl run -it demo --image=busybox --restart=Never #-it,交互式
#查看pod的标签
[root@server2 init]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
liveness-http 0/1 Running 0 64m test=liveness
#进入pod内部,并通过bash操作
[root@server2 init]# kubectl exec -it liveness-http -- bash #liveness-http为pod名字
#显示pod标签
[root@server2 pod]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-8lwkf 1/1 Running 0 3m50s app=nginx
replicaset-example-hdgc8 1/1 Running 0 3m50s app=nginx
replicaset-example-w4zpt 1/1 Running 0 3m50s app=nginx
#更改上述pod标签
[root@server2 pod]# kubectl label pod replicaset-example-8lwkf app=myapp --overwrite