目录
1.内容介绍
1. k8s概述;(掌握)
2. k8s安装;(掌握)
2. k8s概述
云原生:https://www.cnblogs.com/IT-Evan/p/CloudNative.html
2.1.K8s由来
kubernetes,简称K8s,是用8代替8个字符“kubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,即我们常说的容器编排工具,K8S的目标是让部署容器化的应用简单并且高效。
由Google的几位工程师创立的,2014年6月首次对外公布。K8S的开发深受谷歌内部的一个叫做Borg系统的影响,Borg系统是谷歌内部稳定运行了十几年的大规模容器编排工具。谷歌沿用Borg系统的思路,用GO语言重新构建了这个容器编排工具,并命名为K8S。
k8s是谷歌开源的容器编排工具,其实也是管理应用的全生命周期的一个工具,Kubernetes在Docker技术之上,为容器化的应用提供了资源调度、部署运行、服务发现和扩容缩容等丰富多样的功能,从创建应用,应用部署,应用提供服务,扩容缩容,应用更新,都非常的方便,而且可以做到故障自愈,例如一个服务器挂了,可以自动将这个服务器上的服务调度到另外一个主机上进行运行,无需进行人工干涉。如果你曾经用过Docker部署容器,那么可以将Docker看成Kubernetes底层使用的组件,Kubernetes是Docker的上层封装,通过它可以很方便的进行Docker集群的管理
主要功能包括:
基于容器的应用部署、维护和滚动升级
自我修复
负载均衡和服务发现
跨机器和跨地区的集群调度
自动伸缩、水平扩展
无状态服务和有状态服务
广泛的Volume存储卷的支持
插件机制保证扩展性
2.2.K8S架构
2.2.1.架构图
2.2.2.架构组件说明
2.2.2.1 Cluster
Cluster是计算、存储和网络资源的集合,Kubernetes利用这些资源运行各种基于容器的应用.
Kubernetes Cluster由Master和Node组成,节点上运行着若干Kubernetes服务
2.2.2.2 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上 -
Etcd
用于持久化存储集群中所有的资源对象,如Node、Service、Pod、RC、Namespace等;API Server提 供了操作etcd的封装接口API,这些API基本上都是集群中资源对象的增删改查及监听资源变化的接 口。
2.2.2.3 Node
- Kubelet:
负责pod对应的容器创建、启停等任务,同时与master 节点密切协作,处理 Master 节点下发到本 节点的任务,按照 PodSpec 描述来管理Pod 和其中的容器,实现集群管理的基本功能; - kube-proxy
实现Kubernetes Service的服务发现与负载均衡机制的重要组件,比如要通过外网访问k8s就需要该组 件进行代理,容器与容器之间负载均衡也需要kube-proxy - Docker Engine
Docker引擎,负责本机的容器创建和管理工作。
2.2.3组件处理流程
-
通过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的流量转发功能。
2.3.K8S逻辑概念
2.3.1 Pod
Pod是K8S中可以创建的最小部署单元,一个Pod代表集群上正在运行的一个进程。Pod代表部署的一个单位:K8S中单个应用的实例,它可能由单个容器或多个容器共享组成。
Pod中的容器共享两种资源:网络和存储。
- 每个Pod被分配一个独立的IP地址,Pod中的每个容器共享网络命名空间,包括IP地址和网络端口;
- Pod可以指定一组共享存储volumes。
另外,Pod分为
- 自助式Pod:Pod退出了,不会被创建
- 控制器管理的Pod:始终会维持Pod的副本数
2.3.2 Pod控制器
Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为
2.3.2.1.ReplicationController(副本控制器)
确保Pod的数量始终保持设定的个数,如果容器异常退出会自动创建新的Pod来替代,也支持Pod的滚动更新。 已经废弃建议使用ReplicaSet
滚动跟新:创建新的版本,然后删除旧的版本,实现版本的最新滚动跟新
2.3.2.2.ReplicaSet (副本集)
它和ReplicationController没有根本的区别,它支持集合式的Selector(选择多个Pod),但是它不直接使用,由一个声明式更新的控制器叫Deployment来负责管理。
有状态服务:通常指需要持久状态的服务 (Mysql),无状态:通常指无需存储服务状态的服务(tomcat)
2.3.2.3.Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 来方便的管理应用,只需要在Deployment中描述你想要的目标状态是什么,Deployment controller就会帮你将Pod和Replica Set的实际状态改变到你的目标状态典型的应用场景包括;
- 定义 Deployment 来创建 Pod 和 ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续 Deployment
但是Deployment只能负责管理那些无状态的应用。
2.3.2.4.StatefulSet (有状态副本集):
负责管理有状态的应用。使用场景如:
稳定的持久化存储,Pod重新调度后还能访问到相同的持久化数据,
稳定的网络标志,Pod重新调度后PodName和HostName不变
有序部署Pod,有序删除Pod
2.3.2.5.DaemonSet
用来确保每一个Node上只运行一个Pod副本,Node加入集群时为他们创建一个Pod,当有Node从集群中移除时,Pod会被回收,删除DaemonSet将会删除它创建的所有Pod。
使用场景:为每一个Node创建一个日志收集的Pod
2.3.2.6.Job
负责批处理任务,即仅执行一次任务,比如:某个应用生成了一大堆数据集,现在需要临时启动一个Pod去清理这些数据集,清理完成后,这个Pod就可以结束了。 这些不需要一直处于运行状态的应用,就用Job这个类型的控制器去控制。如果Pod运行过程中意外中止了,Job负责重启Pod。如果Pod任务执行完了,就不需要再启动了。
2.3.2.7.Cronjob
周期性作业。使用场景:周期性的执行备份数据库
2.3.3 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 没有变。
K8S提供了一个简单的Endpoints API,这个Endpoints api的作用就是当一个服务中的pod发生变化时,Endpoints API随之变化。
Service的类型
理解service
2.3.3.1.ClusterIP
给service指定默认的ClusterIP,这种方式分配的ip只能在集群内部访问
2.3.3.2.NodePort
在每个节点上都监听一个同样的端口号(30000-32767),ClusterIP和路由规则会自动创建。集群外部可以访问<NodeIP>
:<NodePort>
联系到集群内部服务,可以配合外部负载均衡使用。
简单理解:使用端口映射方式去访问容器
2.3.3.3.LoadBalancer
要配合支持公有云负载均衡使用比如GCE、AWS。其实也是NodePort,不过除了使
用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。
2.3.3.4.ExternalName
创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用。
理解Service:
2.3.4 Enpoint
是可被访问的服务端点,即一个状态为running的pod,它是service访问的落点,只有service关联的pod才可能成为endpoint。简单理解:endpoints 用来记录一个service对应的所有pod的访问地址
2.3.5 网络
节点网络:各主机(Master、Node、ETCD等)自身所属的网络,地址配置在主机的网络接口,用于各主机之间的通信,又称为节点网络。
Pod网络:专用于Pod资源对象的网络,它是一个虚拟网络,用于为各Pod对象设定IP地址等网络参数,其地址配置在Pod中容器的网络接口上。Pod网络需要借助kubenet插件或CNI插件实现。
Service网络:专用于Service资源对象的网络,它也是一个虚拟网络,用于为K8S集群之中的Service配置IP地址,但是该地址不会配置在任何主机或容器的网络接口上,而是通过Node上的kube-proxy配置为iptables或ipvs规则,从而将发往该地址的所有流量调度到后端的各Pod对象之上。
2.3.6 Ingress Controller
Service 是后端真实服务的抽象,一个 Service 可以代表多个相同的后端服务
Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上
Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service
2.4.总结
3. k8s安装
3.1.安装方式选择
装部署主要方式分为三大类:minikube(单机) ,kubeadmin,二进制包(生产环境) , 我们这里采用kubeadmin的方式来安装
3.1.1 Minikube
最为单机运行的k8s集群,直接使用官网感受一下,点击launch terminal ,浏览器下发会弹出命令界面。
https://kubernetes.io/zh/docs/tutorials/hello-minikube/
3.1.2 Kubeadmin
配置基础环境 》 安装kubeadmin部署工具 》 使用kubeadmin配置master ,node,网络,dashboard等等 等会我们就使用这中方式安装
3.1.3 二进制包
相比上述两种有些复杂,但是可以通过二进制安装学到不少东西。
3.2.k8s集群准备
3.3.1 准备环境-一主,二node
推荐配置:内存4G以上,CPU 2 核以上 ,安装Conts的磁盘 100G以上,网络使用桥接
1.设置静态IP(三台)
可以通过可视化界面修改
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,和上网
2.分别设置主机名
hostnamectl set-hostname k8smaster
hostnamectl set-hostname k8snode01
hostnamectl set-hostname k8snode02
3.确保网络ok
ping www.baidu.com
3.3.2 初始化环境(三台)
1.设置hosts
vi /etc/hosts
172.16.7.252 k8snode02
172.16.7.251 k8snode01
172.16.7.250 k8smaster
2.关闭防火墙
# 关闭防火墙,并禁止开机启动
systemctl stop firewalld && systemctl disable firewalld
# 查看防火墙状态
systemctl status firewalld
3.禁用selinux
# 临时禁用
setenforce 0
# 永久禁用
vi /etc/sysconfig/selinux
修改:SELINUX=disabled
#查看selinux的状态信息
/usr/sbin/sestatus
4.禁用交换分区
# 临时关闭
swapoff -a
永久关闭:
vi /etc/fstab
# 注释掉以下字段
/dev/mapper/cl-swap swap swap defaults 0 0
5.创建k8s配置
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
6.kube-proxy开启ipvs的前置条件
#保证在节点重启后能自动加载所需模块
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
7 同步时间
yum -y install ntp ntpdate
ntpdate cn.pool.ntp.org
hwclock --systohc
timedatectl
3.3.3 安装docker(三台)
https://www.runoob.com/docker/centos-docker-install.html
1.卸载
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
2.安装
#预装工具
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(最新版本)
3.配置镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://5pfmrxk8.mirror.aliyuncs.com"]
}
EOF
4.启动
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
kubeadm初始化警告”cgroupfs“解决 : https://blog.whsir.com/post-5312.html
3.3.安装K8S集群
3.3.1.安装kubeadm, kubelet and kubectl(三台)
1.配置yum路径
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
2.安装kubeadm, kubelet and kubectl
yum install -y kubelet-1.15.6 kubeadm-1.15.6 kubectl-1.15.6
3.启动
systemctl enable kubelet && systemctl start kubelet
3.3.2.配置kubeadm(master)
1.创建kubeadm配置文件
kubeadm config print init-defaults --kubeconfig ClusterConfiguration >
kubeadm.yml
vi 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
3.3.3.下载镜像(三台)
- 查看所需镜像列表
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就可以看到拷贝过来的镜像了
2.上传打包好的镜像
使用ftp工具上传到目录
/root/k8simgs.tar
3.在三台机器加载镜像
#拷贝文件到另外两个centos
scp -r /root/k8simgs.tar root@192.168.0.114:/root/k8simgs.tar
当然也可以吧压缩包上传到三个cenos分别再加载
4.加载镜像
docker load -i /root/k8simgs.tar
3.3.4 初始化master
1初始化,进入主节点kubeadm.yml 所在目录执行
kubeadm init --config=kubeadm.yml
如果要重新初始化可以执行:kubeadm reset 重置
2.Master执行配置,从上面输出中拷贝
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
3.验证成功
kubectl get node 并且拷贝命令到个节点执行
kubeadm初始化警告”cgroupfs“解决
https://blog.whsir.com/post-5312.html
3.3.5 加入node
1.将 slave 加入到集群拷贝命令,从上面输出中拷贝,不要拷贝我的,要拷贝你自己的日志里面
kubeadm join 172.16.40.252:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:9f792d9c1bf57977ff22f317b599504a733b3f66688273ac3aa7505931f8e378
2.验证是否加入成功
kubectl get nodes
这里的status是NotReady是因为容器之间还没通信。
3.加入失败
如果 slave 节点加入 master 时配置有问题可以在 slave 节点上使用 kubeadm reset 重置配置再使用 kubeadm join 命令重新加入即可。希望在 master 节点删除 node ,可以使用 kubeadm delete nodes <NAME> 删除。
可以使用:journalctl -f -u kubelet查看错误日志
k8s 集群 节点状态显示notready:https://www.cnblogs.com/lph970417/p/11805934.html
4.Pod 状态查看
kubectl get pod -n kube-system -o wide
由此可以看出 coredns 尚未运行,此时我们还需要安装网络插件。
3.3.6 安装网络插件
1.容器网络
容器之间需要通信需要安装网络插件,我们使用CNI插件 ,容器网络是容器选择连接到其他容器、主和外部网络的机制。容器的 runtime 提供了各种网络模式,每种模式都会产生不同的体验。例如,Docker 默认情况下可以为容器配置以下网络:
- none: 将容器添加到一个容器专门的网络堆栈中,没有对外连接。
- host: 将容器添加到主机的网络堆栈中,没有隔离。
- default bridge: 默认网络模式。每个容器可以通过 IP 地址相互连接。
- 自定义网桥: 用户定义的网桥,具有更多的灵活性、隔离性和其他便利功能
默认的网络模式我们都不适用,我们使用CNI
2.什么是 CNI
CNI(Container Network Interface) 是一个标准的,通用的接口。在容器平台,Docker,Kubernetes,Mesos 容器网络解决方案 flannel(Docker提供),calico(Kubernetes提供),weave(Mesos 提供)。只要提供一个标准的接口,就能为同样满足该协议的所有容器平台提供网络功能,而 CNI 正是这样的一个标准接口协议。
3.Kubernetes 中的 CNI 插件
CNI 的初衷是创建一个框架,用于在配置或销毁容器时动态配置适当的网络配置和资源。插件负责为接口配置和管理 IP 地址,并且通常提供与 IP 管理、每个容器的 IP 分配、以及多主机连接相关的功能。容器运行时会调用网络插件,从而在容器启动时分配 IP 地址并配置网络,并在删除容器时再次调用它以清理这些资源。
运行时或协调器决定了容器应该加入哪个网络以及它需要调用哪个插件。然后,插件会将接口添加到容器网络命名空间中,作为一个 veth 对的一侧。接着,它会在主机上进行更改,包括将 veth 的其他部分连接到网桥。再之后,它会通过调用单独的 IPAM(IP地址管理)插件来分配 IP 地址并设置路由。
在 Kubernetes 中,kubelet 可以在适当的时间调用它找到的插件,为通过 kubelet 启动的 pod进行自动的网络配置。
Kubernetes 中可选的 CNI 插件如下:Flannel ;Calico ;Canal ;Weave 我们使用calico
4.什么是 Calico
Calico 为容器和虚拟机提供了安全的网络连接解决方案,并经过了大规模生产验证(在公有云和跨数千个集群节点中),可与 Kubernetes,OpenShift,Docker,Mesos,DC / OS 和 OpenStack 集成。
Calico 还提供网络安全规则的动态实施。使用 Calico 的简单策略语言,您可以实现对容器,虚拟机工作负载和裸机主机端点之间通信的细粒度控制。
5.安装 Calico 三台
参考官方文档安装:https://docs.projectcalico.org/v3.9/getting-started/kubernetes/
kubectl apply -f https://docs.projectcalico.org/v3.9/manifests/calico.yaml
注意如果node下载不了,直接在所有节点通过docker pull下载
6.验证成功
watch kubectl get pods --all-namespaces
7.查看Nodes
kubectl get nodes
3.3.7 测试与常用命令
- 检查组件运行状态
kubectl get cs
# 输出如下
NAME STATUS MESSAGE ERROR
# 调度服务,主要作用是将 POD 调度到 Node
scheduler Healthy ok
# 自动化修复服务,主要作用是 Node 宕机后自动修复 Node 回到正常的工作状态
controller-manager Healthy ok
# 服务注册与发现
etcd-0 Healthy {"health":"true"}
- 检查 Master 状态
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 状态
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 的状态
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
9.1 检查组件运行状态
kubectl get cs
# 输出如下
NAME STATUS MESSAGE ERROR
# 调度服务,主要作用是将 POD 调度到 Node
scheduler Healthy ok
# 自动化修复服务,主要作用是 Node 宕机后自动修复 Node 回到正常的工作状态
controller-manager Healthy ok
# 服务注册与发现
etcd-0 Healthy {"health":"true"}
9.2 检查 Master 状态
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'.
9.3 检查 Nodes 状态
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
9.4 查看全部 Pods 的状态
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
9.5 查看已部署的服务
kubectl get deployment
# 输出如下
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 91m
9.6 映射服务,让用户可以访问
kubectl expose deployment nginx --port=80 --type=LoadBalancer
# 输出如下
service/nginx exposed
9.7 查看已发布的服务
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
9.9 查看服务详情
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>
9.10 验证是否成功
通过浏览器访问 Master 服务器
http://172.16.33.165:31738/
此时 Kubernetes 会以负载均衡的方式访问部署的 Nginx 服务,能够正常看到 Nginx 的欢迎页即表示成功。容器实际部署在其它 Node 节点上,通过访问 Node 节点的 IP:Port 也是可以的。
9.11 停止服务
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'
4.K8s资源清单
4.1.什么是资源
k8s中所有的内容都被抽象为资源,资源实例化之后,叫做对象。简单理解资源清单就是一个编写好的资源文件,k8s根据资源清单来进行pod的创建
4.2.资源分类
4.2.1 名称空间级别
这一类资源仅在此名称空间下生效,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,】
4.2.2 集群级别
不管在任何名称空间下定义,在其他的名称空间下都能看得到,在定义的时候无需指定名称空间 例如:Namespace【名称空间】、Node【节点】、Role【角色】、ClusterRole、RoleBinding、ClusterRoleBinding
4.2.3 元数据级别
提供一个指标,不像是名称空间类型又不像集群级别,本质上更像是在两者之间,但是它有自己的特点,所以更应该作为一个单独的分类,例如HPA【通过cpu的利用率进行平滑扩展】就是一个很明显的元数据类型,通过指标进行操作。
根据一些指标去进行对应的操作
例如:HPA、PodTemplate【pod模板】、LimitRange【资源限制】
4.3.资源清单
4.3.1 什么是资源清单
k8s一般都是通过定义资源清单的方式去创建资源,资源清单等价于剧本,写好了每一步应该如何去做。在k8s中,一般使用yaml格式的文件来创建符合我们预期期望的资源,这样的yaml文件我们一般称为资源清单。
4.3.2 资源清单定义格式
必须存在的字段:
具体定义使用yaml格式如下:
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 #容器版本
4.3.3 常见命令
1.查看pod的yml清单配置语法
kubectl explain pod
kubectl explain pod.apiVersion
这个命令会告诉我们,编写一个pod资源的yml清单应该使用那些语法
2.导出yml资源清单
kubectl get pods 查看有那些pod
kubectl get pod pod的名字 -o yaml
5.工作负载型资源(workload)
5.1.Pod
Pod是K8S中可以创建的最小部署单元,一个Pod代表集群上正在运行的一个进程。Pod代表部署的一个单位:K8S中单个应用的实例,它可能由单个容器或多个容器共享组成。
演示案例:把一个Nignx容器运行在一个Pod中
1.创建资源文件
vi poddemo.yaml 内容如下
2.添加如下内容
apiVersion: v1
kind: Pod
metadata:
name: app-pod #pod名字
labels:
app: app-label #pod的标签
version: v1
spec:
containers:
- name: app #容器名字
image: nginx:latest #容器镜像
imagePullPolicy: IfNotPresent #或者 Never 从本地找镜像
3.根据资源文件创建pod
kubectl apply -f poddemo.yaml
4.相关命令
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差不多
5.2.Pod控制器ReplicaSet
通常不直接部署及管理Pod,而是借助控制器Controller进行管理,包括 ReplicationController(老版本的)、ReplicaSet、Deployment、StatefulSet、Job等。Pod控制器通常包含三个组成部分:标签选择器,期望的副本数,Pod模板
Replicaset是ReplicationController的替代者,确保Pod副本数在任一时刻都精确满足期望值,可以进行扩缩容,也可以进行升级。
1.创建资源文件
vi rs.yaml
2.加入如下内容
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
3.创建ReplicaSet
kubectl create -f rs.yaml
4.相关命令
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后重新补齐
5.3.Pod控制器Deployment
Deployment构建于ReplicaSet之上, 支持事件和状态查看,回滚,版本记录,暂停和启动升级,多种自动更新方案:Recreate(先删除再新建);Deployment支持RollingUpdate(滚动升级,逐步替换)
什么是滚动升级:如有三个副本,先建立一个新的副本,然后删除一个老的副本,再建立一个新的副本,删除一个老的副本
5.3.1.准备镜像(可以跳过)
我们基于tomcat准备三个不同版本的tomcat镜像,为Deployment做滚动升级做准备,您可以按照如下步骤打包三个tomcat镜像,也可以使用课件资料中的resources/tomcatimgs.tar我已经准备好的资源镜像包,如果使用我的镜像包,就上传tomcatimgs.tar到三个k8s服务器(/root目录),执行docker load -i /root/tomcatimgs.tar 即可加载三个版本的镜像
1. 下载tomcat镜像
docker pull tomcat
2. 运行tomcat容器
docker run -id --name=tomcat -p 8080:8080 tomcat
3.准备index.jsp
<%@ 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>
4.创建镜像
修改分别得到tomcat:v1 tomcat:v2 tomcat:v3
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
5.拷贝镜像
打包三个镜像共享给其他节点
docker save tomcat:v1 tomcat:v2 tomcat:v3 -o /root/tomcatimgs.tar
其他两个节点做
scp -r tomcatimgs.tar root@192.168.0.114:/root
6.加载镜像
docker load -i /root/tomcatimgs.tar
镜像准备完毕
5.3.2.Deployment控制pod
5.3.2.1.创建pod
1.创建资源文件
vi deploy.yaml
2.加入如下内容
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
3.创建Deployment
kubectl apply -f deploy.yaml
需要注意:三个k8s机器上都要有镜像:tomcat:v1;tomcat:v2:tomcat:v3
4.查看pods
kubectl get pods -o wide 查看pod详情
curl 192.168.32.168:8080 访问容器,通过pod的网络访问,外网目前访问不到
kubectl get deployments 查看deployments
5.3.2.2.扩容缩容
1.方式一:使用命令修改pod数量
kubectl scale deployment deploy-example --replicas=3 修改pod数量到 3 个
2.方式2:直接修改yaml文件的方式进行扩容
spec:
replicas: 5
3.方式3:通过打补丁的方式进行扩容 - 了解
kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
5.3.2.3.版本更新
这里有两种方式,1.滚动更新(rolling update) ; 2. 重新创建(recreate) ,默认为滚动更新
- 滚动更新:使用2个ReplicaSet,RS1删除一个旧的pod,RS2创建一个新的pod,依次类推实现pod滚动升级
- 重新创建:使用1个ReplicaSet,删除一个,创建一个,依次类推
方式1:yaml改镜像版本并应用
1.复制资源文件进行修改
cp deploy.yaml deploy1.yaml
2.把镜像版本修改为tomcat:v2 ,进行镜像升级
vi deploy1.yaml
3.应用资源文件
kubectl apply -f deploy1.yaml
4.查看Replicaset
kubectl get rs 查看deployement
多一个deployeement,原本的 3 个pod已经被干掉变成了 0 ,创建了新的 2 个 pod ,因为我新的资源文件中的replicas值为2
5.查看,访问,测试一下,容器中的项目版本已经更新
kubectl get pods -o wide --查看pod网络
curl 192.168.32.179:8080 --访问pod
方案2:命令设置镜像
1.设置镜像版本
kubectl set image deployment/deploy-example myapp=tomcat:v2
- deploy-example : deployment的名字
- myapp=tomcat:v2 镜像名=镜像:版本
2.查看rs
kubectl get rs
3.查看pod
kubectl get pods
4.访问容器内容
curl 192.168.185.220:8080
5.3.2.4.版本还原
1.查看历史
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
6.课程总结
6.1.重点
1.学习
6.2.难点
1.记住
7.常见异常
8.课后练习
9.面试题
10.扩展知识或课外阅读推荐
10.1.扩展知识
看官方资料,PDF书