注意:kubeadm与docker是有版本要求的。
如果版本不兼容,初始化 kubeadm
是会出现以下问题。
基础概念
什么是 Pod
控制器类型 K8S
网络通讯模式
Kubernetes
构建 K8S
集群
资源 掌握资源清单的语法 编写 Pod
掌握 Pod
的生命周期
Pod
控制器掌握各种控制器的特点以及使用定义方式
掌握 SVC
原理及其构建方式
掌握多种存储类型的特点 并且能够在不同环境中选择合适的存储方案(有自己的简介)
掌握调度器原理 能够根据要求把Pod 定义到想要的节点运行
集群的认证 鉴权 访问控制 原理及其流程
Linux yum
掌握 HELM
原理 HELM
模板自定义 HELM
部署一些常用插件
修改Kubeadm
达到证书可用期限为 10年 能够构建高可用的 Kubernetes 集群
DBMS
无状态服务:LVS APACHE
高可用集群副本数据最好是 >= 3 奇数个
这是一个谷歌Borg
调度器的架构。
负责分发,这里不能部署为偶数节点,只能部署技术节点。为了工作保障,做好部署3个以上的BorgMaster,说白了,这就有点类似注册中心。
真正工作的就是Borglet
,由于BorgMaster分发过来处理。
Schduler
任务调度负责将任务分发给node
节点处理。但是scheduler
不会直接和node
节点交互,会将任务交给 api server
保存到etcd
持久化文件中。
replication controller
简称 RC
控制器,管理副本的。
因为Schduler
和replication controller
和etcd
都会去访问 api server
,所以会在 Schduler
和replication controller
本地生成一次缓存,为了减少对 api server
的访问。
etcd
etcd
架构图(了解)
保存需要持久化的重要数据,etcd
的官方将它定位成一个可信赖的分布式键值存储服务,它能够为整个分布式集群存储些关键数据,协助分布式集群的正常运转。
etcd
保存数据访问
注意:k8s
在1.11
版本之前是没有v3
版的,使用的是v2
版本。但是 1.11
以后的版本etcv2
版已经放弃使用了,都是v3
版了。
主要软件有三个
kubelet
:与replication controller
简称 RC
、接口、运行环境之前的调用,并且维持Pod
生命周期,也就是Pod
的创建和销毁。kube proxy
实现Pod
与Pod
之间的负载均衡调用。container
:容器,可以值docker
,也可以是其他容器机制。docker
只是目前最流行引擎的实现方案。api server
:所有服务访问统一入口
CrontrollerManager
:控制器,维持副本期望数目
Scheduler
:负责介绍任务,选择合适的节点进行分配任务
etcd
:键值对数据库 储存K8S集群所有重要信息(持久化)
Kubelet
:直接跟容器引擎交互实现容器的生命周期管理
Kube-proxy
:负责写入规则至 IPTABLES、IPVS 实现服务映射访问的
coredns
:可以为集群中的SVC创建一个域名IP的对应关系解析
dashboard
:给 K8S 集群提供一个 B/S 结构访问体系
Ingress Controller
:官方只能实现四层代理,INGRESS 可以实现七层代理
Federation
:提供一个可以跨集群中心多K8S统一管理功能
Prometheus
:提供K8S集群的监控能力
ELK
:提供 K8S 集群日志统一分析介入平台
不被控制器管理的,销毁后不会自动创建
Replication Controller & ReplicaSet & Deployment
HPA (Horizontalpodautoscale)
Statefull Set
Daemonset Set
Job, Cronjob
ReplicationController
简称RC
: 用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod 来替代;而如果异常多出来的容器也会自动回收。在新版本的Kubernetes 中建议使用ReplicaSet 来取代ReplicationControlle。
ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且ReplicaSet 支持集合式的selector。
虽然ReplicaSet 可以独立使用,但一般还是建议使用Deployment 来自动管理ReplicaSet ,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet 不支持rolling-update 但Deployment 支持)
ReplicaSet
简称RS
:跟 Replicationcontroller
没有本质的不同,只是名字不一样,并且Replicase
支持集合式的 selector
。
虽然 ReplicaSet
可以独立使用,但一般还是建议使用 Deployment
来自动管理ReplicaSet
,这样就无需担心跟其他机制的不兼容问题(比如 Replicase
不支持rolling-update
但 Deployment
支持。
虽然 Deployment
实现滚动更新,但是需要和ReplicaSet
一起使用,因为Deployment
不支持Pod
创建。
Deployment 为Pod 和ReplicaSet 提供了一个声明式定义(declarative) 方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:
定义Deployment 来创建Pod 和ReplicaSet
Horizontal Pod Autoscaling 仅适用于Deployment 和ReplicaSet ,在V1 版本中仅支持根据Pod 的CPU 利用率扩所容,在v1alpha 版本中,支持根据内存和用户自定义的metric 扩缩容。
StatefulSet是为了解决有状态服务的问题(对应Deployments 和ReplicaSets是为无状态服务而设计),其应用场景包括:
稳定的持久化存储,即Pod 重新调度后还是能访问到相同的持久化数据,基于PVC 来实现
稳定的网络标志,即Pod 重新调度后其PodName和HostName不变,基于Headless Service (即没有Cluster IP 的Service )来实现
有序部署,有序扩展,即Pod 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0 到N-1
,在下一个Pod 运行之前所有之前的Pod 必须都是Running 和Ready 状态),基于init containers 来实现
有序收缩,有序删除(即从N-1 到0)
DaemonSet 确保全部(或者一些)Node 上运行一个Pod 的副本。当有Node 加入集群时,也会为他们新增一个Pod 。当有Node 从集群移除时,这些Pod 也会被回收。删除DaemonSet 将会删除它创建的所有Pod
使用DaemonSet 的一些典型用法
运行集群存储daemon,例如在每个Node 上运行glusterd、ceph。
在每个Node 上运行日志收集daemon,例如fluentd、logstash。
在每个Node 上运行监控daemon,例如Prometheus Node Exporter返回
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod 成功结束Cron Job管理基于时间的Job,即:
在给定时间点只运行一次
周期性地在给定时间点运行
如果要时间滚动更新,Deployment
会另外创建一个RS
。然后在新建的RS
下创建Pod
,新建一个Pod
,就将原来的Pod
停用,这里也可以回退的,因为原来的Pod
并没有删除,只是停用。
Kubernetes 的网络模型假定了所有Pod 都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在。而在私有云里搭建Kubernetes 集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的Docker 容器之间的互相访问先打通,然后运行Kubernetes。
创建一个Pod
之后,会自动创建一个容器。这个容器主要作用是共享当前Pod
的网络栈和挂在卷,然后这个Pod
在创建其他容器时,就共享这个网络栈。这样就可以实现Pod
中的容器网路通信和存储问题,需要注意:在同一Pod中端口不能重复,因为使用的都是同一个网络栈,如果端口重复了,会启动失败或者无限的启动。
Flannel
是Core0S
团队针对 Kubernetes
设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的 Docker
容器都具有全集群唯一的虚拟IP
地址。而且它还能在这些IP地址之间建立一个覆盖网络(0 verla Network
),通过这个覆盖网络,将数据包原封不动地传递到目标容器内。
这张图上有两个物理主机,每台物理主机上运行了两个Pod
。需要实现这四个来自不同物理主机的Pod
通讯,在同主机的Pod
直接采用共享网络栈的方式是很好做到的,不同主机之间的通讯是通过Flannel
实现的。
存储管理Flannel 可分配的IP 地址段资源
监控ETCD 中每个 Pod 的实际地址,并在内存中建立维护 Pod 节点路由表。
同一个Pod 共享同一个网络命名空间,共享同一个Linux 协议栈
Pod1 与Pod2 不在同一台主机,Pod的地址是与docker0在同一个网段的,但docker0网段与宿主机网卡是两个完全不同的IP网段,并且不同Node之间的通信只能通过宿主机的物理网卡进行。将Pod的IP和所在Node的IP关联起来,通过这个关联让Pod可以互相访问。
Pod1 与Pod2 在同一台机器,由Docker0 网桥直接转发请求至Pod2,不需要经过Flannel。
目前基于性能考虑,全部为iptables 维护和转发。
Pod 向外网发送请求,查找路由表, 转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables执行Masquerade,把源IP 更改为宿主网卡的IP,然后向外网服务器发送请求。
必须通过Service
k8s
安装,采用 Kubeadm
自动化安装方式。如果采用源码包构建,这样会每个组件都占用一个进程,如果进程杀死了就没有不能使用了。
这里就是我们使用yum install
软件的地址,默认好像是国外的,下载起来特别缓慢,需要这是为国内的,例如:清华大学的,或者阿里云的都可以。配置地址在 /etc/yum.repos.d
下的 CentOS-Base.repo
。这个问价那种是可以配置多个数据源的。
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
CentOS-Base.repo
文件替换为一下数据# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#
[base]
name=CentOS-$releasever - Base
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/os/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#released updates
[updates]
name=CentOS-$releasever - Updates
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/updates/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/extras/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/centosplus/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
yum clean all # 清除系统所有的yum缓存
yum makecache # 生成yum缓存
yum repolist all # 查看所有的yum源
yum repolist enabled # 查看可用的yum源
如果是真实服务器就不用设置了,应为真实服务器的IP本来就是静态的,不会随机变动。
这里如果不设置,默认是动态IP
,这样后面会很麻烦的。我们将配置文件中的IP
配置成当前的IP,但是重启后IP有改变了。所以这里有必要设置以下的。
设置地址在 /etc/sysconfig/network-scripts/
目录下有一个 ifcfg-*
的文件,根据电脑不同,这个文件名不同,通常都是 ifcfg-ens33
。
vim /etc/sysconfig/network-scripts/ifcfg-ens33
需要更改 BOOTPROTO="static"
设置为static
,默认是 BOOTPROTO="dhcp"
这样的。
IPADDR=192.168.22.132 # 静态IP地址
NETMASK=255.255.255.0 # 子网掩码
GATEWAY=192.168.22.1 # 网管,如果配置利润软路由koolshare之类的,这里需要指定软路由的地址。
DNS1=192.168.22.1 # DNS1 这两个DNS配置了干嘛不太清楚
DNS2=114.114.114.114 # DNS2
这里一定要重启网络服务,否则配置不生效。
service network restart
或者
/etc/init.d/network restart
官网:https://github.com/koolshare
安装软路由的主要目的是:我们国内访问不到谷歌的镜像仓库,通过软路由配置一个能够访问外网的SSR
服务器信息,在软路由里面安装一个安全上网插件,这样就可以访问了。不推荐这样干,国内有阿里镜像仓库,可以直接配置阿里镜像仓库就可以了。
分别将每台主机的设置为响应的名称,不用设置也是没有问题的,不过设置过了,后面的操作会要方便一些。
hostnamectl set-hostname k8s-master01
hostnamectl set-hostname node01
hostnamectl set-hostname node02
hostname
在Hosts
问价里面定义域名核对应的IP
,今后使用直接使用域名就方便很多了。这里还可以安装一个DNS
服务器解析。Hosts
文件路径 /etc/hosts
。
需要使用到的主机都要配置,我目前只使用三台主机,所以这三台我都配置。
vim /etc/hosts
192.168.22.132 k8s-master01
192.168.22.129 node01
192.168.22.131 node02
IP 地址和 主机名根据自己的实际情况来配置。
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wgetvimnet-tools git
这里的防火墙不是使用 firwalld
了,而是使用iptables
,因为 iptables
相对来说要牛批一些。今后需要开放那些端口,需要针对iptables
防火墙开启。
systemctl stop firewalld
systemctl disable firewalld
iptables-services
管理工具iptables
是一个防火墙,可以配置有状态的防火墙。有状态防火墙,举个例子:我不想让其它主机连接本机的任何端口,但又希望,当我主动去连接别人的时候,别人回过来的包我可以收到。
yum -y install iptables-services
iptables
systemctl start iptables
iptables
systemctl enable iptables
iptables
规则iptables -F
iptables
默认规则service iptables save
selinux
是一个安全增强型的Linux
,详细介绍参考:https://www.cnblogs.com/kelelipeng/p/10371593.html
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
swapoff -a
关闭swapoff
分区,这个分区表示虚拟内存。
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
: 永久关闭
setenforce 0
临时关闭selinux
getenforce //查看Selinux状态
关闭 swapoff
分区(虚拟内存)的原因是: Kubeadm(k8m)
安装k8s
的时候,init
初始化的时候会去检测 虚拟内存是否关闭,如果开启虚拟内存,Pod
会有可能放到虚拟内存中运行,会降低工作效率的。
在 /etc/sysctl.d/
目录下创建一个 kubernetes.conf
文件,并写入以下数据。但是我们这里直接在当前文件夹下创建 kubernetes.conf
文件,并将输入写入,然后在复制到 /etc/sysctl.d
文件夹下面。
kubernetes.conf
文件并写入数据cat > /opt/data/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1 # 开启网桥模式(必须)
net.bridge.bridge-nf-call-ip6tables=1 # 开启网桥模式(必须)
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0vm.swappiness=0 # 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它vm.overcommit_memory=1 # 不检查物理内存是否够用
vm.panic_on_oom=0 # 开启
OOMfs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963 # 开启最大打开数目
net.ipv6.conf.all.disable_ipv6=1 # 关闭ipv6协议(必须)
net.netfilter.nf_conntrack_max=2310720
EOF
net.bridge.bridge-nf-call-iptables=1 net.bridge.bridge-nf-call-ip6tables=1
这两条是开启网桥模式
net.ipv6.conf.all.disable_ipv6=1
关闭ipv6
以上这三个是必备的,其余的都是一个写优化。
cat > kubernetes.conf <
kubernetes.conf文件,并写入数据,写入得数据以 <
kubernetes.conf
文件复制到 /etc/sysctl.d
文件夹下并刷新。cp /opt/data/kubernetes.conf /etc/sysctl.d/kubernetes.conf
# 刷新,立即生效
sysctl -p /etc/sysctl.d/kubernetes.conf
# 设置系统时区为中国/上海
timedatectl set-timezone Asia/Shanghai
# 将当前的 UTC 时间写入硬件时钟
timedatectl set-local-rtc 0
# 重启依赖于系统时间的服务
systemctl restart rsyslog
systemctl restart crond
postfix
如果使用到邮件发送,那么可以不用关闭。
systemctl stop postfix && systemctl disable postfix
CentOS7
以后,引导方式改为 systemd journald
,所以日志系统就有两个同时在工作。我们需要更改为一个日志就可以了,更改为 systemd journald
日志工作就行。
# 创建持久化保存日志的目录
mkdir /var/log/journal
# 创建配置文件文件存放目录
mkdir /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
[Journal]
# 持久化保存到磁盘
Storage=persistent
# 压缩历史日志
Compress=yes
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000
# 最大占用空间
10GSystemMaxUse=10G
# 单日志文件最大
200MSystemMaxFileSize=200M
# 日志保存时间 2 周
MaxRetentionSec=2week
# 不将日志转发到 syslog
ForwardToSyslog=no
EOF
# 不将日志转发到 syslog
ForwardToSyslog=no
这里设置 no 以后,我们的日志就不会转发到
syslog
里面去,这样就会减轻服务器的压力。
journald
配置systemctl restart systemd-journald
参考:https://www.cnblogs.com/jaxyoun/p/12845360.html
CentOS 7.x
系统自带的 3.10.x
内核存在一些 Bug
,导致运行的 Docker
、Kubernetes
不稳定。
yum
源库yum -y update
ELRepo
仓库的yum
源rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
这里有4.4X
和 5.9.X
两个版本
安装 4.4.X
版本,下面我直接写 kernel-lt
,需要看一下 kernel-lt
与查询出来的是否为 4.4
内核,如果是其他内核,那么安装的就是其他内核了。
yum --enablerepo=elrepo-kernel install -y kernel-lt
如果安装最新版本yum --enablerepo=elrepo-kernel install kernel-ml
sudo awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
rpm -qa | grep kernel
yum remove kernel-3.10.0-1160.2.2.el7.x86_64
注意:当前使用的内核是删除不了的。
设置了需要重启才会生效。
grub2-set-default 'CentOS Linux (4.4.243-1.el7.elrepo.x86_64) 7 (Core)'
Linux
reboot
uname -r
kube-proxy
主要是解决SVC
与Pod
之间的调度关系,将 kube-proxy
模式更改为 ipvs
的调度方式,ipvs
很大程度上提高kube-proxy
的访问效率。
br_netfilter
br_netfilter
: 透明防火墙,介绍:https://blog.csdn.net/weixin_33804582/article/details/92542460?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
参考:https://www.cnblogs.com/sxwen/p/8417268.html
modprobe br_netfilter
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
docker
相关依赖yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
有些时候,这个 \
不能识别为换行,下面的网址就会提示没问文件或目录,所以我们可以使用一样来执行。
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
上面已经设置了阿里云仓库地址了,这里查询的就是阿里云仓库地址中的版本。
yum list docker-ce --showduplicates | sort -r
docker
(方式一,推荐)yum install docker-ce-18.09.8-3.el7
yum install docker-ce-18.09.8-3.el7 docker-ce-selinux-18.09.8-3.el7
后面的 docker-ce-selinux-18.09.8-3.el7
可以不用写。
docker
(方式二)yum install -y docker-ce
docker
(方式三)yum update -y && yum install -y docker-ce
yum -y update
:升级所有包同时也升级软件和系统内核
yum -y upgrade
:只升级所有包,不升级软件和系统内核
yum install -y docker-ce
:安装docker-ce
,这是docker
的一个开源版本。docker也分为几种。
将docker
安装完成后,重新启动操作系统查看一下Linux
内核,发现会回到原来的历史版本,3.10
。这是因为安装docker
的时候执行了 yum update -y
命令,升级所有包、升级软件、系统内核造成的。
解决方式
查看4.1
升级内核部分。
docker -v
docker
systemctl restart docker
systemctl enable docker
daemon
(docker
日志信息)注意:这些文件需要docker
启动过了才会有的,如果没有启动过docker就想设置的,那么就先创建文件在启动docker。
cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts":
{
"max-size": "100m"
},
"registry-mirrors": ["https://w57n2hu2.mirror.aliyuncs.com"]
}
EOF
“exec-opts”: [“native.cgroupdriver=systemd”] 设置docker中cgroupdriver分组为systemd
“log-driver”: “json-file” 设置
docker
日志存储类型为json-file
类型存储“log-opts”: {“max-size”: “100m” } 日志存储大小为 100M
"registry-mirrors": ["https://w57n2hu2.mirror.aliyuncs.com"]
:设置镜像仓库地址。
docker
配置文件更改daemon.json
配置文件一定要刷新。
mkdir -p /etc/systemd/system/docker.service.d
systemctl daemon-reload
注意:daemon-reload
没有空格的。
systemctl restart docker
systemctl enable docker
如果启动失败,重新设置 /etc/docker/daemon.json
配置文件,在 systemctl daemon -reload
刷新配置文件,重新启动。
- 启动docker: systemctl start docker
- 停止docker: systemctl stop docker
- 重启docker: systemctl restart docker
- 查看docker状态: systemctl status docker
- 开机自动启动docker: systemctl enable docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
yum remove docker docker-common docker-selinux docker-engine
yum list installed | grep docker
yum remove docker-ce
这里需要指定版本删除,不指定就匹配最新版本的docker
。
rm -rf /var/lib/docker
卸载:https://www.cnblogs.com/cpw6/p/12483258.html
kubeadm
为国内镜像cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
kubeadm
、kubelet
和 kubectl
官网文档:https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
您需要在每台机器上安装以下的软件包:
kubeadm
:用来初始化集群的指令。kubelet
:在集群中的每个节点上用来启动 pod
和容器等。kubectl
:用来与集群通信的命令行工具。注意:这几个的版本必须一致,否则会导致版本不匹配问题。
yum -y install kubeadm-1.15.1 kubectl-1.15.1 kubelet-1.15.1
kubelet
开机自启k8s是以docker的形式存在,所以需要设置为开机自启。
systemctl enable kubelet.service
tar -zxvf kubeadm-basic.images.tar.gz
如果镜像有很多个需要导入,如果我们一个一个的导入会很麻烦,所以写一个脚本导入会更加方便。
touch /opt/data/kubeadm.sh
#!/bin/bash
ls /opt/data/kubeadm-basic.images > /opt/data/list.txt
cd /opt/data/kubeadm-basic.images
for x in $(cat /opt/data/list.txt)
do
docker load -i $x
done
rm -rf /opt/data/list.txt # 将这个删除,不删除也没问题
ls /opt/data/kubeadm-basic.images > /opt/data/list.txt
: 将kubeadm-basic.images
这个目录中的所有问价名读取到list.txt
中。
cd /opt/data/kubeadm-basic.images
进入kubeadm-basic.images
文件夹for x in $(cat /opt/data/list.txt) do docker load -i $x done
循环list.txt中的文件,
docker load -i $x
添加到docker
中。
kubeadm-config.yaml
文件中kubeadm config print init-defaults > /opt/data/kubeadm-config.yaml
kubeadm config print init-defaults
:显示kubeadm
默认的初始化文件。
kubeadm config print init-defaults > /opt/data/kubeadm-config.yam
: 将kubeadm
:默认的初始化文件打印到kubeadm-config.yam
文件中。
注意:上面截图中将 kubeadm-config.yaml
文件后缀写成 yam
了,少了 l
,需要注意一下。
kubeadm-config.yaml
文件需要更改一下配置,注意:这里读语法很讲究,直接使用vim
命令更改,注意缩进不要使用tab
键,使用空格。
advertiseAddress: 192.168.22.132 # 当前服务器节点地址 (当前服务器的IP地址)
kubernetesVersion: v1.15.1 # 版本号
podSubnet: "10.244.0.0/16" # Pod 网段
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
featureGates:
SupportIPVSProxyMode: true
mode: ipvs # 默认的调度模式更改为ipvs模式
全部配置
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.22.132 # 当前服务器节点地址 (当前服务器的IP地址)
bindPort: 6443 # 端口号,默认就好
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: k8s-master01 # 主机名
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: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.15.1 # 版本号
networking:
dnsDomain: cluster.local
podSubnet: "10.244.0.0/16" # Pod 网段
serviceSubnet: 10.96.0.0/12
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
featureGates:
SupportIPVSProxyMode: true
mode: ipvs # 默认的调度模式更改为ipvs模式
kubeadm init --config=/opt/data/kubeadm-config.yaml --experimental-upload-certs | tee /opt/data/kubeadm-init.log
kubeadm init --config=/opt/data/kubeadm-config.yaml
:指定从/opt/data/kubeadm-config.yaml
文件初始化安装。
experimental-upload-certs
: 在高可用的节点下自动颁发证书。
tee kubeadm-init.log
: 将日志问价写入到kubeadm-init.log
文件中。
执行这条命令后会报一下异常,好像是版本升级导致的,需要将
--experimental-upload-certs
替换为--upload-certs
。上面这种方式是没有问题的,下面这种方式创建出来有些配置文件没有,并且连
kubeadm-init.log
日志文件都是加密的,所以不要使用下面这种方式,这里写出来说明这个坑已经踩过了。# 这种方式不使用 kubeadm init --config=/opt/data/kubeadm-config.yaml --upload-certs | tee /opt/data/kubeadm-init.log
- kubeadm与docker版本不支持
- CPU数量少于2
第一次启动失败,第二次启动包端口等信息被占用
问题解决
kubeadm reset # 重启kubeadm
日志已经输出到 /opt/data/kubeadm-init.log
文件中了,所以直接到这个文件中查看。
这些命令都在日志文件底部
mkdir -p $HOME/.kube # 在家目录下面创建 .kube目录
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config # 拷贝集群管理员配置文件
sudo chown $(id -u):$(id -g) $HOME/.kube/config # 授权
kubectl get node
状态为NotReady
(不可用),因为k8s
要求有一个扁平化的网络存在,所以需要构建flannel
网路插件。
https://www.cnblogs.com/xiao987334176/p/12696740.html
https://www.cnblogs.com/devilwind/p/8880677.html
flannel
目录保存 kube-flannel.yml
文件,因为 flannel
是基于 yml
文件创建的。mkdir -p /opt/data/flannel
kube-flannel.yml
到 /opt/data/flannel
目录中cd /opt/data/flannel # 进入/opt/data/flannel目录
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
如果wget
命令不存在,安装 yum -y install wget
。
执行安装日志中的加入命令即可
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
官网:https://goharbor.io
Python应该是应该是2.7或更高版本
Docker引擎应为引擎应为1.10或更高版本
Docker Compose需要为需要为1.6.0或更高版本
docker-compose
curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m`> /usr/local/bin/docker-compose
Harbor 官方地址:https://github.com/vmware/harbor/releases
tar xvf harbor-offline-installer-<version>.tgz
https://github.com/vmware/harbor/releases/download/v1.2.0/harbor-offline-installer-v1.2.0.tgz
hostname:目标的主机名或者完全限定域名
ui_url_protocol:http或https,默认为http
db_password:用于db_auth的MySQL数据库的根密码。更改此密码进行任何生产用途。
max_job_workers:(默认值为3)作业服务中的复制工作人员的最大数量。对于每个映像复制作业,作业服务中的复制工作人员的最大数量。对于每个映像复制作业,工作人员将存储库的所有标签同步到远程目标。增加此数字允许系统中更多的并发复制作业。但是,由于每个工工作人员将存储库的所有标签同步到远程目标。增加此数字允许系统中更多的并发复制作业。但是,由于每个工作人员都会消耗一定数量的网络作人员都会消耗一定数量的网络/ CPU / IO资源,请根据主机的硬件资源,仔细选择该属性的值资源,请根据主机的硬件资源,仔细选择
Kubernetes Service
定义了这样一种抽象:一个Pod
的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。这一组Pod
能够被Service
访问到,通常是通过Label Selector
。
Service能够提供负载均衡的能力,但是在使用上有以下限制:
Service 在 K8s 中有以下四种类型
在 Kubernetes 集群中,每个 Node 运行一个kube-proxy进程。kube-proxy负责为Service实现了一种VIP(虚拟 IP)的形式,而不是ExternalName的形式。在 Kubernetes v1.0 版本,代理完全在 userspace。在Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。从 Kubernetes v1.2 起,默认就是iptables 代理。在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理。
在 Kubernetes 1.14 版本开始默认使用ipvs 代理。
在 Kubernetes v1.0 版本,Service是 “4层”(TCP/UDP over IP)概念。在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用来表示 “7层”(HTTP)服务。
!为何不使用 round-robin DNS?
这种模式,kube-proxy 会监视 Kubernetes Service对象和Endpoints,调用netlink接口以相应地创建ipvs 规则并定期与 Kubernetes Service对象和Endpoints对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod。
与 iptables 类似,ipvs 于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:
clusterIP 主要在每个 node 节点使用 iptables,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口。
为了实现图上的功能,主要需要以下几个组件的协同工作:
创建 myapp-deploy.yaml 文件
有时不需要或不想要负载均衡,以及单独的 Service IP 。遇到这种情况,可以通过指定 ClusterIP(spec.clusterIP) 的值为 “None” 来创建 Headless Service 。这类 Service 并不会分配 Cluster IP, kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。
nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod
iptables -t nat -nvLKUBE-NODEPORTS
loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用cloud provider 去创建 LB 来向节点导流
这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例如:hub.atguigu.com )。ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
当查询主机 my-service.defalut.svc.cluster.local ( SVC_NAME.NAMESPACE.svc.cluster.local )时,集群的DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。
Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx
kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml
deployment、Service、Ingress Yaml
文件
创建证书,以及 cert 存储方式。
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj"/CN=nginxsvc/O=nginxsvc"kubectl create secret tls tls-secret --key tls.key --cert tls.crt
deployment、Service、Ingress Yaml
文件
yum -y install httpd
htpasswd -c auth foo
kubectl create secret generic basic-auth --from-file=auth
名称 | 描述 | 值 |
---|---|---|
nginx.ingress.kubernetes.io/rewrite-target | 必须重定向流量的目标URI | 字符串 |
nginx.ingress.kubernetes.io/ssl-redirect | 指示位置部分是否仅可访问SSL(当Ingress包含证书时默认为True) | 布尔 |
nginx.ingress.kubernetes.io/force-ssl-redirect | 即使Ingress未启用TLS,也强制重定向到HTTPS | 布尔 |
nginx.ingress.kubernetes.io/app-root | 定义Controller必须重定向的应用程序根,如果它在’/'上下文中 | 字符串 |
nginx.ingress.kubernetes.io/use-regex | 指示Ingress上定义的路径是否使用正则表达式 | 布尔 |
ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象。
$ ls docs/user-guide/configmap/kubectl/
game.properties
ui.properties
$ cat docs/user-guide/configmap/kubectl/game.propertiese
nemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
$ cat docs/user-guide/configmap/kubectl/ui.propertie
scolor.good=purple
color.bad=yellowallow.textmode=true
how.nice.to.look=fairlyNice
$ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl
—from-file
指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容。
只要指定为一个文件就可以从单个文件中创建 ConfigMap
$ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties
$ kubectlget configmaps game-config-2 -o yaml
—from-file
这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的。
使用文字值创建,利用—from-literal参数传递配置信息,该参数可以使用多次,格式如下。
$ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
$ kubectlget configmaps special-config -o yaml
在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容
$ kubectl edit configmap log-config
$ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2`cat /tmp/log_levelDEBUG
更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新。
$ kubectl patch deployment my-nginx --patch'{"spec": {"template": {"metadata": {"annotations":{"version/config": "20190411" }}}}}'
这个例子里我们在.spec.template.metadata.annotations
中添加version/config
,每次通过修改version/config
来触发滚动更新。
!!!更新 ConfigMap 后:
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret 可以以 Volume 或者环境变量的方式使用。
Secret 有三种类型:
用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的/run/secrets/kubernetes.io/serviceaccount目录中。
$ kubectl run nginx --image nginxdeployment "nginx" created
$ kubectlget podsNAME READY STATUS RESTARTS AGEnginx-3137573019-md1u2 1/1 Running 0 13s
$ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
namespace
token
Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式:
$ echo-n"admin" | base64
YWRtaW4=
$ echo-n"1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm
secrets.yml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
使用 Kuberctl 创建 docker registry 认证的 secret
$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAILsecret "myregistrykey" created.
在创建 Pod 的时候,通过imagePullSecrets来引用刚创建的 myregistrykey
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: roc/awangyang:v1
imagePullSecrets :
- name: myregistrykey
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题。
Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷
Kubernetes 支持以下类型的卷:
awsElasticBlockStore
azureDisk
azureFile
cephfs
csi
downwardAPI
emptyDir
fc
flocker
gcePersistentDisk
gitRepo
glusterfs
hostPath
iscsi
local
nfs
persistentVolumeClaim
projected
portworxVolum
equobyte
rbd
scaleIO
secret
storageos
vsphereVolume
当 Pod 被分配给节点时,首先创建emptyDir卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除。
emptyDir的用法有:
hostPath
卷将主机节点的文件系统中的文件或目录挂载到集群中
hostPath
的用途如下:
除了所需的path属性之外,用户还可以为hostPath卷指定type
值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate |
如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为 0755,与 Kubelet 具有相同的组和所有权。 |
Directory |
给定的路径下必须存在目录 |
FileOrCreate |
如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为 0644,与 Kubelet 具有相同的组和所有权。 |
File |
给定的路径下必须存在文件 |
Socket |
给定的路径下必须存在 UNIX 套接字 |
CharDevice |
给定的路径下必须存在字符设备 |
BlockDevice |
给定的路径下必须存在块设备 |
使用这种卷类型是请注意,因为:
由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同
当 Kubernetes 按照计划添加资源感知调度时,将无法考虑hostPath使用的资源。
在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入hostPath卷。
PersistentVolume
(PV)是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。
PersistentVolumeClaim
(PVC)是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)。
集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费
当管理员创建的静态 PV 都不匹配用户的PersistentVolumeClaim时,集群可能会尝试动态地为 PVC 创建卷。此配置基于StorageClasses:PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为""可以有效地禁用其动态配置
要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的DefaultStorageClass[准入控制器]。例如,通过确保DefaultStorageClass位于 API server 组件的–admission-control标志,使用逗号分隔的有序值列表中,可以完成此操作
master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV 和 PVC 绑定后,PersistentVolumeClaim绑定是排他性的,不管它们是如何绑定的。 PVC 跟PV 绑定是一对一的映射
PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的删除将被推迟,直到 PVC 不再被任何 pod 使用。
PersistentVolume
类型以插件形式实现。Kubernetes
目前支持以下插件类型:
GCEPersistentDisk
AWSElasticBlockStore
AzureFileAzureDisk
FC (Fibre Channel)
。FlexVolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
。Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte
Volumes
。HostPath
VMware
PhotonPortworx
VolumesScaleIO
Volumes
StorageOS
。PersistentVolume
可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV 的访问模式都将被设置为该卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式。
在命令行中,访问模式缩写为:
Volume 插件 | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStoreAWSElasticBlockStore | √ | - | - |
AzureFile | √ | √ | √ |
AzureDisk | √ | - | - |
CephFS | √ | √ | √ |
Cinder | √ | - | - |
FC | √ | √ | - |
FlexVolume | √ | √ | - |
Flocker | √ | - | - |
GCEPersistentDisk | √ | √ | - |
Glusterfs | √ | √ | √ |
HostPath | √ | - | - |
iSCSI | √ | √ | - |
PhotonPersistentDisk | √ | - | - |
Quobyte | √ | √ | √ |
NFS | √ | √ | √ |
RBD | √ | √ | - |
VsphereVolume | √ | - | -(当 pod 并列时有效) |
PortworxVolume | √ | - | √ |
ScaleIO | √ | √ | - |
StorageOS | √ | - | - |
当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略
卷可以处于以下的某种状态:
命令行会显示绑定到 PV 的 PVC 的名称
yum install -y nfs-common nfs-utils rpcbind
mkdir /nfsdata
chmod666 /nfsdata
chown nfsnobod y
/nfsdatacat /etc/exports/nfsdata *(rw,no_root_squash,no_all_squash,sync)
systemctl start rpcbind
systemctl start nfs
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfspv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /data/nfs
server: 10.66.66.10
Statefulset的启停顺序
StatefulSet使用场景:
Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。听起来非常简单,但有
很多要考虑的问题:
Sheduler 是作为单独的程序运行的,启动之后会一直坚挺 API Server,获取 PodSpec.NodeName 为空的 pod,
对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上
调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为 predicate ;然后对通过的节点按照优先级
排序,这个是 priority ;最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误。
如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。
经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程: 按照优先级大小对节点排序
优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:
除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通过 spec:schedulername 参数指定调度器的名
字,可以为 pod 选择某个调度器进行调度。比如下面的 pod 选择 my-scheduler 进行调度,而不是默认的
default-scheduler
:
apiVersion: v1
kind: Pod
metadata:
name: annotation-second-scheduler
labels:
name: multischeduler-example
spec:
schedulername: my-scheduler
containers:
- name: pod-with-second-annotation-container
image: gcr.io/google_containers/pause:2.0
pod.spec.nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.atguigu.com/library/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- k8s-node02
preferredDuringSchedulingIgnoredDuringExecution
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.atguigu.com/library/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: source
operator: In
values:
- qikqiak
合体
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.atguigu.com/library/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- k8s-node02
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: source
operator: In
values:
- qikqiak
键值运算关系
apiVersion: v1
kind: Pod
metadata:
name: pod-3
labels:
app: pod-3
spec:
containers:
- name: pod-3
image: hub.atguigu.com/library/myapp:v1
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pod-1
topologyKey: kubernetes.io/hostname
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pod-2
topologyKey: kubernetes.io/hostname
亲和性/反亲和性调度策略比较如下:
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | n, NotIn, Exists,DoesNotExist, Gt, Lt | 否 | 指定主机 |
podAffinity | Pod | In, NotIn, Exists,DoesNotExist | 是 | POD与指定POD同一拓扑域 |
podAnitAffinity | Pod | In, NotIn, Exists,DoesNotExist | 是 | POD与指定POD不在同一拓扑域 |